From 12cca64f61029b8e227b323ad2312658560e3982 Mon Sep 17 00:00:00 2001 From: houseassassin Date: Tue, 12 May 2026 11:36:57 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20period=20filter=20in=20analytics=20?= =?UTF-8?q?=E2=80=94=20month/last=20month/3=20months/all=20time?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- src/admin/analytics/AnalyticsPage.jsx | 75 ++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/src/admin/analytics/AnalyticsPage.jsx b/src/admin/analytics/AnalyticsPage.jsx index 3fa69b5..c2bb6fa 100644 --- a/src/admin/analytics/AnalyticsPage.jsx +++ b/src/admin/analytics/AnalyticsPage.jsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useMemo, useState } from 'react'; import { TrendingUp, Download } from 'lucide-react'; import { useAnalyticsPage } from './useAnalyticsPage'; @@ -45,26 +45,55 @@ const SummaryCard = ({ label, value }) => ( ); +const PERIODS = [ + { value: 'month', label: 'Этот месяц' }, + { value: 'last_month', label: 'Прошлый месяц' }, + { value: '3months', label: '3 месяца' }, + { value: 'all', label: 'Всё время' }, +]; + const AnalyticsPage = () => { const { orders, loading } = useAnalyticsPage(); + const [period, setPeriod] = useState('month'); + + const filteredOrders = useMemo(() => { + const now = new Date(); + if (period === 'month') { + const start = new Date(now.getFullYear(), now.getMonth(), 1); + return orders.filter((o) => new Date(o.created_at) >= start); + } + if (period === 'last_month') { + const start = new Date(now.getFullYear(), now.getMonth() - 1, 1); + const end = new Date(now.getFullYear(), now.getMonth(), 1); + return orders.filter((o) => { + const d = new Date(o.created_at); + return d >= start && d < end; + }); + } + if (period === '3months') { + const start = new Date(now.getFullYear(), now.getMonth() - 2, 1); + return orders.filter((o) => new Date(o.created_at) >= start); + } + return orders; // 'all' + }, [orders, period]); const metrics = useMemo(() => { - const total = orders.length; - const completed = orders.filter((o) => o.status === 'завершена'); + const total = filteredOrders.length; + const completed = filteredOrders.filter((o) => o.status === 'завершена'); const completedCount = completed.length; const revenue = completed.reduce((sum, o) => sum + (Number(o.final_cost) || 0), 0); const avg = completedCount > 0 ? revenue / completedCount : 0; return { total, completedCount, revenue, avg }; - }, [orders]); + }, [filteredOrders]); const statusCounts = useMemo(() => { const counts = {}; STATUS_LIST.forEach((s) => { counts[s] = 0; }); - orders.forEach((o) => { + filteredOrders.forEach((o) => { if (counts[o.status] !== undefined) counts[o.status]++; }); return counts; - }, [orders]); + }, [filteredOrders]); const maxStatusCount = useMemo(() => Math.max(...Object.values(statusCounts), 1), [statusCounts]); @@ -72,7 +101,7 @@ const AnalyticsPage = () => { const months = getLast6Months(); const map = {}; months.forEach((m) => { map[m.key] = 0; }); - orders + filteredOrders .filter((o) => o.status === 'завершена') .forEach((o) => { if (!o.created_at) return; @@ -83,13 +112,13 @@ const AnalyticsPage = () => { } }); return months.map((m) => ({ ...m, revenue: map[m.key] })); - }, [orders]); + }, [filteredOrders]); const maxMonthRevenue = useMemo(() => Math.max(...revenueByMonth.map((m) => m.revenue), 1), [revenueByMonth]); const managerStats = useMemo(() => { const map = {}; - orders.forEach((o) => { + filteredOrders.forEach((o) => { const name = o.assigned_to || 'Не назначен'; if (!map[name]) { map[name] = { name, total: 0, completed: 0, revenue: 0 }; @@ -101,12 +130,12 @@ const AnalyticsPage = () => { } }); return Object.values(map).sort((a, b) => b.revenue - a.revenue); - }, [orders]); + }, [filteredOrders]); const handleExportCSV = () => { const BOM = ''; const headers = ['ID', 'Статус', 'Сумма', 'Дата создания', 'Менеджер', 'Плёнка']; - const rows = orders.map((o) => [ + const rows = filteredOrders.map((o) => [ o.id, o.status ?? '', o.final_cost ?? '', @@ -148,14 +177,14 @@ const AnalyticsPage = () => { + {/* Period selector */} +
+ {PERIODS.map((p) => ( + + ))} +
+ {/* Section A — Summary cards */}