Task #391: Live clock in Executive Meetings header

Added a `HeaderClock` component to artifacts/tx-os/src/pages/executive-meetings.tsx
that renders next to the "Export PDF" button in the sticky page header.

- Updates every 1s via setInterval (cleared on unmount)
- Locale-aware formatting via Intl.DateTimeFormat (ar / en) with hour12
- Hidden on <sm screens (`hidden sm:flex`) and on print
- Uses existing palette (text-[#0B1E3F]) + Clock lucide icon
- tabular-nums to prevent jitter as digits change
- data-testid="em-header-clock" for future tests

No deviations from plan. tx-os typecheck passes.
This commit is contained in:
riyadhafraa
2026-05-05 09:48:22 +00:00
parent 69c31dfdce
commit 119374c64b
@@ -43,6 +43,7 @@ import {
ChevronLeft,
ChevronRight,
Search,
Clock,
} from "lucide-react";
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@/components/ui/collapsible";
import { Button } from "@/components/ui/button";
@@ -758,6 +759,33 @@ export default function ExecutiveMeetingsPage() {
);
}
function HeaderClock({ lang }: { lang: "ar" | "en" }) {
const [now, setNow] = useState<Date>(() => new Date());
useEffect(() => {
const id = window.setInterval(() => setNow(new Date()), 1000);
return () => window.clearInterval(id);
}, []);
const formatter = useMemo(
() =>
new Intl.DateTimeFormat(lang === "ar" ? "ar" : "en", {
hour: "numeric",
minute: "2-digit",
hour12: true,
}),
[lang],
);
return (
<div
className="hidden sm:flex items-center gap-1.5 text-sm font-medium text-[#0B1E3F] tabular-nums print:hidden"
data-testid="em-header-clock"
aria-live="off"
>
<Clock className="w-4 h-4 opacity-70" />
<span>{formatter.format(now)}</span>
</div>
);
}
function ExecutiveMeetingsPageInner() {
const { t, i18n } = useTranslation();
const [, setLocation] = useLocation();
@@ -885,6 +913,7 @@ function ExecutiveMeetingsPageInner() {
<div className="flex-1" />
<div className="flex items-center gap-2">
<HeaderClock lang={lang} />
<Button
variant="outline"
size="sm"