/** * График доходов для Dashboard ментора */ 'use client'; import React, { useMemo } from 'react'; import dynamic from 'next/dynamic'; import { IncomeChartData } from '@/api/dashboard'; const ApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); interface RevenueChartProps { data: IncomeChartData[]; loading?: boolean; period?: 'day' | 'week' | 'month'; /** Показывать серию «Занятий» (по умолчанию true для дашборда) */ showLessons?: boolean; /** Высота графика в px (по умолчанию 250) */ height?: number; } export const RevenueChart: React.FC = ({ data, loading, period = 'month', showLessons = true, height = 250, }) => { if (!data || data.length === 0) { return (
{loading ? 'Загрузка...' : 'Нет данных'}
); } const { categories, incomeSeries, lessonsSeries } = useMemo(() => { const items = Array.isArray(data) ? data : []; return { categories: items.map((item) => item.date), incomeSeries: items.map((item) => item.income), lessonsSeries: items.map((item) => item.lessons), }; }, [data]); const options: any = useMemo( () => ({ chart: { id: 'mentor-income-chart', toolbar: { show: false }, zoom: { enabled: false }, animations: { enabled: true, easing: 'easeinout', speed: 400, }, }, stroke: { curve: 'smooth', width: showLessons ? [3, 2] : 3, }, colors: showLessons ? ['#6750A4', '#7D5260'] : ['#6750A4'], dataLabels: { enabled: false, }, legend: { show: showLessons, position: 'top', horizontalAlign: 'left', markers: { width: 10, height: 10, radius: 12, }, labels: { colors: 'var(--md-sys-color-on-surface)', style: { fontSize: '15px', }, }, }, xaxis: { categories, axisBorder: { show: false }, axisTicks: { show: false }, labels: { formatter: (val: string) => { if (typeof val === 'string' && /^\d{2}\.\d{2}$/.test(val)) { return val.split('.')[0]; } return val; }, style: { colors: 'var(--md-sys-color-on-surface-variant)', fontSize: '18px', }, }, }, yaxis: showLessons ? [ { seriesName: 'Доход', labels: { formatter: (val: number) => `${Math.round(val)} ₽`, style: { colors: 'var(--md-sys-color-on-surface-variant)', fontSize: '18px', }, }, }, { opposite: true, seriesName: 'Занятий', labels: { style: { colors: 'var(--md-sys-color-on-surface-variant)', fontSize: '18px', }, }, }, ] : [ { labels: { formatter: (val: number) => `${Math.round(val)} ₽`, style: { colors: 'var(--md-sys-color-on-surface-variant)', fontSize: '18px', }, }, }, ], fill: { type: showLessons ? ['gradient', 'solid'] : 'gradient', gradient: { shade: 'dark', type: 'vertical', shadeIntensity: 0.6, gradientToColors: ['rgba(103,80,164,0)'], inverseColors: false, opacityFrom: 0.7, opacityTo: 0.15, stops: [0, 25, 50, 75, 100], }, }, tooltip: { shared: showLessons, intersect: false, style: { fontSize: '15px', }, x: { show: true, }, y: { formatter: (val: number, { seriesIndex }: any) => showLessons && seriesIndex === 1 ? `${val} занятий` : `${Math.round(Number(val)).toLocaleString('ru-RU')} ₽`, }, }, grid: { borderColor: 'var(--ios26-list-divider)', strokeDashArray: 4, yaxis: { lines: { show: true }, }, }, markers: { size: 0, hover: { size: 4, }, }, }), [categories, showLessons], ); const series = useMemo( () => showLessons ? [ { name: 'Доход', type: 'area' as const, data: incomeSeries }, { name: 'Занятий', type: 'line' as const, data: lessonsSeries }, ] : [{ name: 'Доход', type: 'area' as const, data: incomeSeries }], [incomeSeries, lessonsSeries, showLessons], ); return (
); };