"use client";
import { Check, Copy, Repeat2, Square, SquareCheckBig, X } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { formatAmount, formatUsd } from "@/app/lib/units";
import type { Aisle, GroceryLine, GrocerySummary, ItemId } from "@/app/types";
import { BudgetMeter } from "./BudgetMeter";
interface PanelProps {
summary: GrocerySummary;
budget: number;
priceSourceLabel: string;
onToggleOnHand: (itemId: ItemId, onHand: boolean) => void;
}
export function GrocerySummaryPanel({ summary, budget, priceSourceLabel, onToggleOnHand }: PanelProps) {
const [copied, setCopied] = useState(false);
const byAisle = groupByAisle(summary.lines);
const remaining = budget - summary.checkoutTotal;
async function copyList() {
const text = summary.lines
.filter((l) => !l.onHand)
.map((l) => `☐ ${l.packages} × ${l.item.name} (${l.item.packageLabel})`)
.join("\n");
try {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
// Clipboard can be blocked; list remains visible on screen.
}
}
return (
{/* --- Tactile Market Receipt Header -------------------------------- */}
= 0 ? "Left in budget" : "Over budget"}
value={formatUsd(Math.abs(remaining))}
tone={remaining >= 0 ? "text-status-ok" : "text-status-danger"}
/>
{summary.sharedItemCount > 0 && (
{summary.sharedItemCount} store item{summary.sharedItemCount > 1 ? "s" : ""} shared across meals
)}
{/* --- Shopping List Header ----------------------------------------- */}
Shopping list
Tap items you already have on hand
{summary.lines.length > 0 && (
)}
{summary.lines.length === 0 ? (
Add meals to build your aisle-sorted grocery receipt.
) : (
{byAisle.map(([aisle, lines]) => (
{aisle}
{lines.map((line) => (
))}
))}
)}
{priceSourceLabel}. Actual store prices vary by location.
);
}
function GroceryRow({ line, onToggleOnHand }: { line: GroceryLine; onToggleOnHand: PanelProps["onToggleOnHand"] }) {
const { item } = line;
return (
);
}
function Stat({ label, value, hint, tone = "text-ink" }: { label: string; value: string; hint?: string; tone?: string }) {
return (
{label}
{value}
);
}
function groupByAisle(lines: GroceryLine[]): [Aisle, GroceryLine[]][] {
const groups = new Map();
for (const line of lines) {
const group = groups.get(line.item.aisle) ?? [];
group.push(line);
groups.set(line.item.aisle, group);
}
return [...groups];
}
// ---------------------------------------------------------------------------
// GroceryListDrawer: Native