Refactor: move public storefront stop data to server-side + parallel agent work
Server-side / caching refactor (Grok): - New RPC get_public_stops_for_brand (migration 148) for public storefront stops - New server action getPublicStopsForBrand with revalidate=300 + tags - Add revalidateTag invalidation to createStopsBatch + publishStop - Convert /tuxedo/stops and /indian-river-direct/stops to Server Components - Extract TuxedoStopsList + IndianRiverStopsList as client islands (GSAP only) - Removes supabase-js from browser bundle on those routes - Both pages now statically prerendered (5m ISR) Parallel agent changes also staged: - AI provider model list refresh (claude-sonnet-4-5, etc.) - ESLint directive patches for react-hooks/set-state-in-effect - Admin + storefront + checkout + cart updates - New admin_create_stop_rpcs migration (147) - Misc fixes across ~90 files Build verified: typecheck clean, lint clean on new files, production build succeeds.
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
createWaterHeadgate,
|
||||
regenerateHeadgateToken,
|
||||
updateWaterHeadgate,
|
||||
deleteWaterHeadgate,
|
||||
} from "@/actions/water-log/admin";
|
||||
import { AdminButton } from "@/components/admin/design-system";
|
||||
|
||||
@@ -118,6 +119,24 @@ export default function HeadgatesManager({ initialHeadgates, brandId }: Props) {
|
||||
}
|
||||
}
|
||||
|
||||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||||
|
||||
async function handleDelete(hg: Headgate) {
|
||||
if (!window.confirm(`Delete headgate "${hg.name}"? Existing log entries will be preserved.`)) return;
|
||||
setDeletingId(hg.id);
|
||||
const res = await deleteWaterHeadgate(hg.id);
|
||||
if (res.success) {
|
||||
// Optimistic update + refresh
|
||||
setHeadgates((prev) => prev.filter((h) => h.id !== hg.id));
|
||||
const refreshed = await getWaterHeadgatesAdmin(brandId);
|
||||
setHeadgates(refreshed);
|
||||
showToast("Headgate deleted");
|
||||
} else {
|
||||
showToast(res.error ?? "Failed to delete headgate", false);
|
||||
}
|
||||
setDeletingId(null);
|
||||
}
|
||||
|
||||
function toggleSelect(id: string) {
|
||||
setSelected((prev) => {
|
||||
const next = new Set(prev);
|
||||
@@ -312,6 +331,15 @@ export default function HeadgatesManager({ initialHeadgates, brandId }: Props) {
|
||||
<AdminButton variant="secondary" size="sm" onClick={() => setQrModal(hg)}>
|
||||
Print
|
||||
</AdminButton>
|
||||
<AdminButton
|
||||
variant="danger"
|
||||
size="sm"
|
||||
onClick={() => handleDelete(hg)}
|
||||
disabled={deletingId === hg.id}
|
||||
isLoading={deletingId === hg.id}
|
||||
>
|
||||
Delete
|
||||
</AdminButton>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -207,7 +207,7 @@ export default function WaterLogSettingsPage() {
|
||||
{/* High/Low Alerts */}
|
||||
<div className="rounded-xl bg-zinc-900 shadow-black/20 ring-1 ring-zinc-700 p-5 space-y-4">
|
||||
<p className="font-semibold text-zinc-100">High/Low Alerts</p>
|
||||
<p className="text-xs text-zinc-500">Receive an SMS when a reading exceeds a headgate's thresholds.</p>
|
||||
<p className="text-xs text-zinc-500">Receive an SMS when a reading exceeds a headgate's thresholds.</p>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user