diff --git a/README.md b/README.md index 7e101a0..3a08d7b 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ Never commit real values to source control. `.env.local` is already ignored by G | `npm run seed:venues` | Seed sample venue data (developer script) | | `npm run bootstrap-superadmin` | Grant the initial superadmin role to `SUPER_ADMIN_EMAIL` (see docs first) | | `npm run prune:trade-leads` | Prune trade inquiries past the 24-month retention window (dry-run; `-- --delete` executes) | +| `npm run migrate:venue-islands` | Backfill the canonical venue `island` field from legacy `locationName` values (dry-run; `-- --write` executes) | ## Deployment overview diff --git a/components/admin-dashboard.tsx b/components/admin-dashboard.tsx index ec407ad..d7ad444 100644 --- a/components/admin-dashboard.tsx +++ b/components/admin-dashboard.tsx @@ -30,6 +30,8 @@ import { type RebuildMeta, } from "@/components/admin-workspace"; import { refreshAdminAccess } from "@/lib/admin-session-refresh"; +import { resolveVenueIsland } from "@/lib/venue-filters"; +import { isVenueIsland } from "@/lib/venue-islands"; import type { AdminRole, Beer, Venue } from "@/lib/types"; const DEFAULT_BEER: Beer = { @@ -195,7 +197,11 @@ export function AdminDashboard() { useEffect(() => { const found = venues.find((venue) => venue.slug === selectedVenueSlug); if (!found) return; - setVenueForm(found); + // Legacy records lack the canonical island field (Issue #134): preselect + // the island resolved from the old free-text location so saving writes + // the field without manual repair. Unresolvable records leave the + // required select unset instead of guessing. + setVenueForm({ ...found, island: resolveVenueIsland(found) }); setVenueCarriesSelection(found.carriesBeerSlugs ?? []); setVenueTapSelection(found.tapBeerSlugs ?? []); setVenueCanSelection(found.canBeerSlugs ?? []); @@ -538,6 +544,11 @@ export function AdminDashboard() { return; } + if (!isVenueIsland(venueForm.island)) { + setStatusMessage("Select an island for this venue."); + return; + } + setIsSaving(true); setStatusMessage(""); try { diff --git a/components/admin-fixture.tsx b/components/admin-fixture.tsx index 4ca9f85..b6cb258 100644 --- a/components/admin-fixture.tsx +++ b/components/admin-fixture.tsx @@ -11,6 +11,8 @@ import { AdminWorkspace, type RebuildMeta, } from "@/components/admin-workspace"; +import { resolveVenueIsland } from "@/lib/venue-filters"; +import { isVenueIsland } from "@/lib/venue-islands"; import type { AdminRole, Beer, Venue } from "@/lib/types"; const FIXTURE_BEERS: Beer[] = [ @@ -50,6 +52,7 @@ const FIXTURE_VENUES: Venue[] = [ slug: "fixture-tavern", type: "bar_restaurant", locationName: "Windwardside", + island: "saba", carriesBeerSlugs: ["saba-suds-pilsner"], tapBeerSlugs: ["saba-suds-pilsner"], canBeerSlugs: [], @@ -143,7 +146,8 @@ export function AdminFixture({ role }: { role: AdminRole }) { setSelectedVenueSlug(slug); const found = FIXTURE_VENUES.find((venue) => venue.slug === slug); if (found) { - setVenueForm(found); + // Mirror the real dashboard's legacy-island resolution (Issue #134). + setVenueForm({ ...found, island: resolveVenueIsland(found) }); setVenueCarriesSelection(found.carriesBeerSlugs ?? []); setVenueTapSelection(found.tapBeerSlugs ?? []); setVenueCanSelection(found.canBeerSlugs ?? []); @@ -169,6 +173,10 @@ export function AdminFixture({ role }: { role: AdminRole }) { setStatusMessage("Venue name and slug are required."); return; } + if (!isVenueIsland(venueForm.island)) { + setStatusMessage("Select an island for this venue."); + return; + } setIsSaving(true); setStatusMessage(""); setTimeout(() => { diff --git a/components/admin-workspace.tsx b/components/admin-workspace.tsx index 3e75617..e7625b8 100644 --- a/components/admin-workspace.tsx +++ b/components/admin-workspace.tsx @@ -8,6 +8,7 @@ import { type AdminPanelUser, } from "@/components/admin-access"; import type { Beer, Venue } from "@/lib/types"; +import { VENUE_ISLAND_OPTIONS, type VenueIsland } from "@/lib/venue-islands"; export interface RebuildMeta { cooldownUntil?: number; @@ -383,8 +384,24 @@ export function AdminWorkspace({ +