30cdb5064a
~300 lines of code that were independently duplicated in Dashboard.tsx and Comparison.tsx are now in shared modules: - src/lib/locale.ts — LC interface, EN and AR language configs (merged fields from both pages into one unified interface) - src/lib/dateHelpers.ts — MONTH_KEYS, isLeap, makePresets, guessPreset, periodNameL, dateRangeTextL, currentMonth, shiftYear - src/components/shared/PeriodPicker.tsx — InlinePicker + PeriodHero - src/components/shared/AltMultiSelect.tsx — AltMultiSelect - src/components/shared/MetricCard.tsx — MetricCard Dashboard.tsx and Comparison.tsx now import from these shared modules. Zero behavioral changes — all props, ARIA, and render output unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
24 lines
1.2 KiB
TypeScript
24 lines
1.2 KiB
TypeScript
import React from 'react';
|
|
import { formatCurrency, formatNumber } from '../../services/dataService';
|
|
|
|
// ─── metric card ──────────────────────────────────────────────────
|
|
export default function MetricCard({ title, curr, prev, isCurrency, newLabel }: {
|
|
title: string; curr: number; prev: number; isCurrency?: boolean; newLabel?: string;
|
|
}) {
|
|
const fmt = (n: number) => isCurrency ? formatCurrency(n) : formatNumber(n);
|
|
const change = prev === 0 ? (curr > 0 ? Infinity : 0) : ((curr - prev) / prev * 100);
|
|
const isPos = change > 0, isNeg = change < 0;
|
|
return (
|
|
<div className="alt-metric">
|
|
<p className="alt-metric-title">{title}</p>
|
|
<div className="alt-metric-value">{fmt(curr)}</div>
|
|
<div className="alt-metric-footer">
|
|
{isFinite(change)
|
|
? <span className={`alt-change ${isPos ? 'alt-change--up' : isNeg ? 'alt-change--down' : 'alt-change--flat'}`}>{isPos ? '▲' : isNeg ? '▼' : '—'} {Math.abs(change).toFixed(1)}%</span>
|
|
: <span className="alt-change alt-change--up">{newLabel ?? 'New'}</span>}
|
|
<span className="alt-metric-prev">{fmt(prev)}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|