All files / src/pages/dashboard/blocks MonthlyMovementMini.tsx

100% Statements 78/78
80% Branches 4/5
100% Functions 2/2
100% Lines 78/78

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 781x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 3x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 4x
/**
 * @file MonthlyMovementMini.tsx
 * @module pages/dashboard/blocks/MonthlyMovementMini
 *
 * @summary
 * Compact monthly stock movement chart for the Dashboard.
 * Displays inbound and outbound stock movements over the last 90 days.
 * Reuses the same API as the full Analytics page.
 *
 * @responsibilities
 * - Fetch monthly aggregated stock movement data (90-day window)
 * - Display dual-bar chart with color-coded inbound (success) and outbound (error) bars
 * - Show loading skeleton while data is being fetched
 * - Apply theme colors for visual consistency
 *
 * @usage
 * <MonthlyMovementMini />
 *
 * @i18n
 * Uses translation key: dashboard.kpi.movementTitle
 */
import { Card, CardContent, Typography, Skeleton, Box } from '@mui/material';
import { useTheme as useMuiTheme } from '@mui/material/styles';
import { useQuery } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { ResponsiveContainer, BarChart, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Bar } from 'recharts';
import { getMonthlyStockMovement } from '../../../api/analytics';
import { getTodayIso, getDaysAgoIso } from '../../../utils/formatters';
 
/**
 * Monthly stock movement chart component for dashboard KPI section.
 * Shows a 90-day rolling window of stock in/out movement aggregated by month.
 * @returns Memoized React component with dual-bar chart or skeleton loading state
 */
export default function MonthlyMovementMini() {
  const { t } = useTranslation('common');
  // Calculate 90-day window (from: 90 days ago, to: today)
  const from = getDaysAgoIso(90);
  const to = getTodayIso();
  const muiTheme = useMuiTheme();
 
  // Fetch monthly aggregated stock movement data
  const q = useQuery({
    queryKey: ['dashboard', 'movementMini', from, to],
    queryFn: () => getMonthlyStockMovement({ from, to }),
  });
  return (
    <Card>
      <CardContent sx={{ py: 1.5, px: 2 }}>
        {/* Card title */}
        <Typography variant="subtitle1" sx={{ mb: 0.75 }}>
          {t('dashboard.kpi.movementTitle', 'Stock movement (90d)')}
        </Typography>
 
        {/* Show skeleton while data is loading, otherwise render bar chart */}
        {q.isLoading ? (
          <Skeleton variant="rounded" height={220} />
        ) : (
          <Box sx={{ height: 240 }}>
            <ResponsiveContainer width="100%" height="90%">
              <BarChart data={q.data ?? []}>
                <CartesianGrid strokeDasharray="3 3" />
                <XAxis dataKey="month" />
                <YAxis />
                <Tooltip />
                <Legend />
                {/* Green bars: inbound stock movements */}
                <Bar dataKey="stockIn" fill={muiTheme.palette.success.main} />
                {/* Red bars: outbound stock movements */}
                <Bar dataKey="stockOut" fill={muiTheme.palette.error.main} />
              </BarChart>
            </ResponsiveContainer>
          </Box>
        )}
      </CardContent>
    </Card>
  );
}