From 9a05f23a04358affca5faa0acb5cd81911372136 Mon Sep 17 00:00:00 2001 From: c0mrade Date: Tue, 2 Jun 2026 15:55:10 +0300 Subject: [PATCH] =?UTF-8?q?feat(sales-stats):=20=D0=BF=D1=80=D0=B5=D1=81?= =?UTF-8?q?=D0=B5=D1=82=20=C2=AB=D0=AD=D1=82=D0=BE=D1=82=20=D0=BC=D0=B5?= =?UTF-8?q?=D1=81=D1=8F=D1=86=C2=BB=20(=D1=81=201-=D0=B3=D0=BE=20=D1=87?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0)=20=D0=B8=20=D0=BE=D0=BD=20=D0=B6?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=20=D1=83=D0=BC=D0=BE=D0=BB=D1=87=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Статистика по умолчанию открывается за текущий месяц с 1-го числа до сегодня (month-to-date), а не за фиксированные 30 дней. Добавлена кнопка «Этот месяц» в селектор периода; util getMonthToDateRange/isMonthToDate. --- src/components/sales-stats/PeriodSelector.tsx | 45 +++++++++---------- src/locales/en.json | 1 + src/locales/fa.json | 1 + src/locales/ru.json | 1 + src/locales/zh.json | 1 + src/pages/AdminSalesStats.tsx | 3 +- src/utils/period.ts | 22 +++++++++ 7 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 src/utils/period.ts diff --git a/src/components/sales-stats/PeriodSelector.tsx b/src/components/sales-stats/PeriodSelector.tsx index 35eff18..c55874a 100644 --- a/src/components/sales-stats/PeriodSelector.tsx +++ b/src/components/sales-stats/PeriodSelector.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { SALES_STATS } from '../../constants/salesStats'; +import { getMonthToDateRange, isMonthToDate } from '../../utils/period'; interface PeriodSelectorProps { value: { days?: number; startDate?: string; endDate?: string }; @@ -24,46 +25,44 @@ export function PeriodSelector({ value, onChange }: PeriodSelectorProps) { onChange({ days }); }; - const handleCustomToggle = () => { - setShowCustom((prev) => !prev); + const handleThisMonth = () => { + setShowCustom(false); + onChange({ days: undefined, ...getMonthToDateRange() }); }; + const handleCustomToggle = () => setShowCustom((prev) => !prev); + const handleDateChange = (field: 'startDate' | 'endDate', dateStr: string) => { - onChange({ - ...value, - days: undefined, - [field]: dateStr, - }); + onChange({ ...value, days: undefined, [field]: dateStr }); }; - const isPresetActive = (days: number) => !showCustom && value.days === days; + const buttonClass = (active: boolean) => + `rounded-lg px-3 py-1.5 text-sm font-medium transition-colors ${ + active + ? 'bg-accent-500/20 text-accent-400' + : 'bg-dark-800/50 text-dark-400 hover:bg-dark-700/50 hover:text-dark-300' + }`; + + const mtdActive = !showCustom && isMonthToDate(value); return (
+ + {SALES_STATS.PERIOD_PRESETS.map((days) => ( ))} - @@ -75,7 +74,7 @@ export function PeriodSelector({ value, onChange }: PeriodSelectorProps) { onChange={(e) => handleDateChange('startDate', e.target.value)} className="rounded-lg border border-dark-600 bg-dark-800 px-2 py-1 text-sm text-dark-200" /> - {'\u2014'} + {'—'} ({ days: SALES_STATS.DEFAULT_PERIOD }); + }>(() => getMonthToDateRange()); const params: SalesStatsParams = useMemo( () => ({ diff --git a/src/utils/period.ts b/src/utils/period.ts new file mode 100644 index 0000000..7032556 --- /dev/null +++ b/src/utils/period.ts @@ -0,0 +1,22 @@ +/** First day of the current month → today, as local YYYY-MM-DD strings. + * Used as the default sales-stats window ("this month so far"). */ +export function getMonthToDateRange(): { startDate: string; endDate: string } { + const now = new Date(); + const toLocalISODate = (d: Date) => + `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; + return { + startDate: toLocalISODate(new Date(now.getFullYear(), now.getMonth(), 1)), + endDate: toLocalISODate(now), + }; +} + +/** True when the period is exactly "from the 1st of the current month to today". */ +export function isMonthToDate(period: { + days?: number; + startDate?: string; + endDate?: string; +}): boolean { + if (period.days !== undefined) return false; + const mtd = getMonthToDateRange(); + return period.startDate === mtd.startDate && period.endDate === mtd.endDate; +}