diff --git a/client/src/pages/Analytics.tsx b/client/src/pages/Analytics.tsx index 3c7401d..bbf2843 100644 --- a/client/src/pages/Analytics.tsx +++ b/client/src/pages/Analytics.tsx @@ -11,7 +11,7 @@ const Analytics = () => { const { customers } = useSelector((state: RootState) => state.customers); const { expenses } = useSelector((state: RootState) => state.expenses); - const [dateRange, setDateRange] = useState('month'); + const [dateRange, setDateRange] = useState('2026'); // Helper function to get updated printing cost using current product costs const getUpdatedPrintingCost = (order: any) => { @@ -19,111 +19,104 @@ const Analytics = () => { return calculateOrderPrintingCost(updatedItems); }; - // Helper function to filter data by date range - const getDateRangeFilter = (range: string) => { - const now = new Date(); - const cutoffDate = new Date(); - - switch (range) { - case 'week': - cutoffDate.setDate(now.getDate() - 7); - break; - case 'month': - // Get the first day of last month - cutoffDate.setMonth(now.getMonth() - 1); - cutoffDate.setDate(1); - cutoffDate.setHours(0, 0, 0, 0); - break; - case 'quarter': - cutoffDate.setMonth(now.getMonth() - 3); - break; - case 'year': - cutoffDate.setFullYear(now.getFullYear() - 1); - break; - default: - // Default to first day of last month - cutoffDate.setMonth(now.getMonth() - 1); - cutoffDate.setDate(1); - cutoffDate.setHours(0, 0, 0, 0); - } - - return cutoffDate; - }; - - // Filter orders and expenses by selected date range + // Filter orders and expenses by selected date range using consistent logic const filteredOrders = useMemo(() => { - if (!orders) return []; - - // Handle specific month selections (e.g., "2026-03" for March 2026) - if (dateRange.match(/^\d{4}-\d{2}$/)) { - const [year, month] = dateRange.split('-').map(Number); - const startOfMonth = new Date(year, month - 1, 1); - const endOfMonth = new Date(year, month, 0, 23, 59, 59); - - return orders.filter(order => { - if (!order.dateOrdered) return false; - const orderDate = new Date(order.dateOrdered); - return orderDate >= startOfMonth && orderDate <= endOfMonth; - }); - } - - const cutoffDate = getDateRangeFilter(dateRange); - - if (dateRange === 'month') { - // For month view, show only the previous complete month - const now = new Date(); - const startOfLastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1); - const endOfLastMonth = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59); - - return orders.filter(order => { - if (!order.dateOrdered) return false; - const orderDate = new Date(order.dateOrdered); - return orderDate >= startOfLastMonth && orderDate <= endOfLastMonth; - }); - } + if (!orders || dateRange === 'all') return orders || []; + const now = new Date(); return orders.filter(order => { if (!order.dateOrdered) return false; const orderDate = new Date(order.dateOrdered); - return orderDate >= cutoffDate; + + // Handle specific month format (e.g., "2026-03" for March 2026) + if (dateRange.match(/^\d{4}-\d{2}$/)) { + const [year, month] = dateRange.split('-'); + return orderDate.getFullYear() === parseInt(year) && + orderDate.getMonth() === parseInt(month) - 1; + } + + // Handle quarter format (e.g., "2026-Q1") + if (dateRange.match(/^\d{4}-Q[1-4]$/)) { + const [year, quarter] = dateRange.split('-Q'); + const targetYear = parseInt(year); + const targetQuarter = parseInt(quarter); + const orderYear = orderDate.getFullYear(); + const orderQuarter = Math.floor(orderDate.getMonth() / 3) + 1; + return orderYear === targetYear && orderQuarter === targetQuarter; + } + + // Handle year format (e.g., "2026") - calendar year, not rolling 365 days + if (dateRange.match(/^\d{4}$/)) { + return orderDate.getFullYear() === parseInt(dateRange); + } + + // Handle legacy preset ranges (rolling periods from today) + const timeDiff = now.getTime() - orderDate.getTime(); + const daysDiff = timeDiff / (24 * 60 * 60 * 1000); + + switch (dateRange) { + case 'week': + return daysDiff >= 0 && daysDiff <= 7; + case 'month': + return daysDiff >= 0 && daysDiff <= 30; + case 'quarter': + return daysDiff >= 0 && daysDiff <= 90; + case 'year': + // For "This Year" option, show current calendar year + return orderDate.getFullYear() === now.getFullYear(); + default: + return true; + } }); }, [orders, dateRange]); const filteredExpenses = useMemo(() => { - if (!expenses) return []; - - // Handle specific month selections (e.g., "2026-03" for March 2026) - if (dateRange.match(/^\d{4}-\d{2}$/)) { - const [year, month] = dateRange.split('-').map(Number); - const startOfMonth = new Date(year, month - 1, 1); - const endOfMonth = new Date(year, month, 0, 23, 59, 59); - - return expenses.filter(expense => { - if (!expense.date) return false; - const expenseDate = new Date(expense.date); - return expenseDate >= startOfMonth && expenseDate <= endOfMonth; - }); - } - - const cutoffDate = getDateRangeFilter(dateRange); - - if (dateRange === 'month') { - // For month view, show only the previous complete month - const now = new Date(); - const startOfLastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1); - const endOfLastMonth = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59); - - return expenses.filter(expense => { - if (!expense.date) return false; - const expenseDate = new Date(expense.date); - return expenseDate >= startOfLastMonth && expenseDate <= endOfLastMonth; - }); - } + if (!expenses || dateRange === 'all') return expenses || []; + const now = new Date(); return expenses.filter(expense => { if (!expense.date) return false; const expenseDate = new Date(expense.date); - return expenseDate >= cutoffDate; + + // Handle specific month format (e.g., "2026-03" for March 2026) + if (dateRange.match(/^\d{4}-\d{2}$/)) { + const [year, month] = dateRange.split('-'); + return expenseDate.getFullYear() === parseInt(year) && + expenseDate.getMonth() === parseInt(month) - 1; + } + + // Handle quarter format (e.g., "2026-Q1") + if (dateRange.match(/^\d{4}-Q[1-4]$/)) { + const [year, quarter] = dateRange.split('-Q'); + const targetYear = parseInt(year); + const targetQuarter = parseInt(quarter); + const expenseYear = expenseDate.getFullYear(); + const expenseQuarter = Math.floor(expenseDate.getMonth() / 3) + 1; + return expenseYear === targetYear && expenseQuarter === targetQuarter; + } + + // Handle year format (e.g., "2026") - calendar year, not rolling 365 days + if (dateRange.match(/^\d{4}$/)) { + return expenseDate.getFullYear() === parseInt(dateRange); + } + + // Handle legacy preset ranges (rolling periods from today) + const timeDiff = now.getTime() - expenseDate.getTime(); + const daysDiff = timeDiff / (24 * 60 * 60 * 1000); + + switch (dateRange) { + case 'week': + return daysDiff >= 0 && daysDiff <= 7; + case 'month': + return daysDiff >= 0 && daysDiff <= 30; + case 'quarter': + return daysDiff >= 0 && daysDiff <= 90; + case 'year': + // For "This Year" option, show current calendar year + return expenseDate.getFullYear() === now.getFullYear(); + default: + return true; + } }); }, [expenses, dateRange]); @@ -314,8 +307,11 @@ const Analytics = () => { - + + + +