uchill/front_material/components/profile/ProfileAnalyticsTab.tsx

130 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useState, useEffect } from 'react';
import { getIncomeStats } from '@/api/income';
import { LoadingSpinner } from '@/components/common/LoadingSpinner';
const formatCurrency = (v: number) =>
new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB', maximumFractionDigits: 0 }).format(v);
export function ProfileAnalyticsTab() {
const [data, setData] = useState<any>(null);
const [loading, setLoading] = useState(true);
const [period, setPeriod] = useState<'day' | 'week' | 'month'>('month');
useEffect(() => {
setLoading(true);
getIncomeStats({ period })
.then(setData)
.catch(() => setData(null))
.finally(() => setLoading(false));
}, [period]);
if (loading && !data) {
return <LoadingSpinner size="medium" />;
}
if (!data) {
return (
<p style={{ color: 'var(--md-sys-color-on-surface-variant)', fontSize: 14 }}>
Нет данных о доходах
</p>
);
}
const s = data.summary || {};
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
{(['day', 'week', 'month'] as const).map((p) => (
<button
key={p}
type="button"
onClick={() => setPeriod(p)}
style={{
padding: '8px 16px',
borderRadius: 8,
border: period === p ? 'none' : '1px solid var(--md-sys-color-outline)',
background: period === p ? 'var(--md-sys-color-primary)' : 'transparent',
color: period === p ? 'var(--md-sys-color-on-primary)' : 'var(--md-sys-color-on-surface)',
fontSize: 14,
cursor: 'pointer',
}}
>
{p === 'day' ? 'День' : p === 'week' ? 'Неделя' : 'Месяц'}
</button>
))}
</div>
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))',
gap: 16,
}}
>
<div className="ios26-panel" style={{ padding: 16 }}>
<div style={{ fontSize: 12, color: 'var(--md-sys-color-on-surface-variant)', marginBottom: 4 }}>
Общий доход
</div>
<div style={{ fontSize: 20, fontWeight: 600, color: 'var(--md-sys-color-on-surface)' }}>
{formatCurrency(s.total_income || 0)}
</div>
</div>
<div className="ios26-panel" style={{ padding: 16 }}>
<div style={{ fontSize: 12, color: 'var(--md-sys-color-on-surface-variant)', marginBottom: 4 }}>
Занятий
</div>
<div style={{ fontSize: 20, fontWeight: 600, color: 'var(--md-sys-color-on-surface)' }}>
{s.total_lessons || 0}
</div>
</div>
<div className="ios26-panel" style={{ padding: 16 }}>
<div style={{ fontSize: 12, color: 'var(--md-sys-color-on-surface-variant)', marginBottom: 4 }}>
Средняя цена
</div>
<div style={{ fontSize: 20, fontWeight: 600, color: 'var(--md-sys-color-on-surface)' }}>
{formatCurrency(s.average_lesson_price || 0)}
</div>
</div>
</div>
{data.top_lessons && data.top_lessons.length > 0 && (
<div>
<div
style={{
fontSize: 11,
fontWeight: 600,
letterSpacing: '0.05em',
color: 'var(--md-sys-color-on-surface-variant)',
marginBottom: 12,
}}
>
ТОП ЗАНЯТИЙ ПО ДОХОДАМ
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
{data.top_lessons.slice(0, 5).map((item: any, i: number) => (
<div
key={i}
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: 12,
borderRadius: 12,
background: 'var(--md-sys-color-surface-container-low)',
}}
>
<span style={{ fontSize: 14, color: 'var(--md-sys-color-on-surface)' }}>
{item.lesson_title || item.target_name}
</span>
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--md-sys-color-primary)' }}>
{formatCurrency(item.total_income || 0)}
</span>
</div>
))}
</div>
</div>
)}
</div>
);
}