diff --git a/src/renderer/components/dashboard/charts/ChartCard.tsx b/src/renderer/components/dashboard/charts/ChartCard.tsx
new file mode 100644
index 00000000..e99f5166
--- /dev/null
+++ b/src/renderer/components/dashboard/charts/ChartCard.tsx
@@ -0,0 +1,54 @@
+import { ChartLine } from "@phosphor-icons/react";
+
+interface ChartCardProps {
+ title: string;
+ period?: string;
+ isEmpty?: boolean;
+ emptyHeading?: string;
+ emptyBody?: string;
+ ariaLabel?: string;
+ children: React.ReactNode;
+}
+
+export function ChartCard({
+ title,
+ period = "14d",
+ isEmpty = false,
+ emptyHeading = "No activity yet",
+ emptyBody = "Charts will appear once your company starts running tasks.",
+ ariaLabel,
+ children,
+}: ChartCardProps) {
+ return (
+
+
+
+ {title}
+
+
+ {period}
+
+
+ {isEmpty ? (
+
+
+
+ {emptyHeading}
+
+
+ {emptyBody}
+
+
+ ) : (
+
{children}
+ )}
+
+ );
+}
diff --git a/src/renderer/components/dashboard/charts/ChartTooltip.tsx b/src/renderer/components/dashboard/charts/ChartTooltip.tsx
new file mode 100644
index 00000000..0a0a538c
--- /dev/null
+++ b/src/renderer/components/dashboard/charts/ChartTooltip.tsx
@@ -0,0 +1,57 @@
+import type { TooltipContentProps } from "recharts";
+
+interface ChartTooltipExtraProps {
+ valuePrefix?: string;
+ valueSuffix?: string;
+}
+
+type Props = Partial> & ChartTooltipExtraProps;
+
+export function ChartTooltip({
+ active,
+ payload,
+ label,
+ valuePrefix = "",
+ valueSuffix = "",
+}: Props) {
+ if (!active || !payload?.length) return null;
+
+ const dateStr =
+ typeof label === "string"
+ ? new Date(label + "T00:00:00").toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ year: "numeric",
+ })
+ : String(label);
+
+ return (
+
+
{dateStr}
+ {payload.map((entry, i) => (
+
+
+
+ {valuePrefix}
+ {typeof entry.value === "number"
+ ? entry.value.toLocaleString()
+ : entry.value}
+ {valueSuffix}
+
+
+ ))}
+
+ );
+}