From 685a1269a4c8b724d728287f361fc07916cccb38 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 17 Jun 2026 00:31:33 -0600 Subject: [PATCH] feat(admin): apply design system to Stops pages - Stops list, new, and detail pages use new PageHeader with Operations eyebrow, Stops & Routes title, and editorial subtitle. - StopsCalendarClient: replace hardcoded amber (#f59e0b) and brown (#92400e) draft markers with --admin-warning / --admin-warning-soft tokens. Calendar structure unchanged (drag/click/edit preserved). - Add/Edit/StopDetail modals: replace hardcoded red rgba with --admin-danger-soft and color-mix derived borders. - StopsLocationsTabs: swap hardcoded emerald-* for --admin-primary / --admin-primary-soft tokens. - StopMessagingForm: align with design system (ha-field, ha-eyebrow, tokens). - StopProductAssignment error surface: tokens instead of red rgba. - StopsHeaderActions already tokenized via AdminButton; no change. TS clean. Calendar functionality unchanged. --- src/app/admin/stops/[id]/page.tsx | 302 ++++++++++-------- src/app/admin/stops/new/page.tsx | 53 +-- src/app/admin/stops/page.tsx | 42 ++- src/components/admin/AddStopModal.tsx | 2 +- src/components/admin/EditStopModal.tsx | 4 +- src/components/admin/StopDetailModal.tsx | 24 +- src/components/admin/StopMessagingForm.tsx | 70 ++-- .../admin/StopProductAssignment.tsx | 4 +- src/components/admin/StopsCalendarClient.tsx | 10 +- src/components/admin/StopsLocationsTabs.tsx | 12 +- 10 files changed, 304 insertions(+), 219 deletions(-) diff --git a/src/app/admin/stops/[id]/page.tsx b/src/app/admin/stops/[id]/page.tsx index 7b135a2..3869ff8 100644 --- a/src/app/admin/stops/[id]/page.tsx +++ b/src/app/admin/stops/[id]/page.tsx @@ -4,9 +4,17 @@ import StopProductAssignment from "@/components/admin/StopProductAssignment"; import MessageCustomersSection from "@/components/admin/MessageCustomersSection"; import { getAdminUser } from "@/lib/admin-permissions"; import AdminAccessDenied from "@/components/admin/AdminAccessDenied"; +import { PageHeader } from "@/components/admin/design-system"; import { redirect } from "next/navigation"; import Link from "next/link"; +const StopIcon = () => ( + + + + +); + type StopDetailPageProps = { params: Promise<{ id: string; @@ -68,18 +76,30 @@ export default async function StopDetailPage({ params }: StopDetailPageProps) { if (!stopRow) { return ( -
-
-

Stop not found

-
-            {id}
-          
- - ← Back to Stops - +
+
+
+

Operations

+ } + /> +
+
+                {id}
+              
+ + + + + Back to Stops + +
+
); @@ -148,138 +168,156 @@ export default async function StopDetailPage({ params }: StopDetailPageProps) { }, })); + const detailSubtitle = stop.brands?.name + ? `${stop.brands.name} · ${stop.location}` + : stop.location; + return ( -
-
- - ← Back to Stops - +
+
+

Operations

+ } + /> +
-
-
-
-

- {stop.brands?.name} -

-

- {stop.city}, {stop.state} -

-

{stop.location}

-
- - - {stop.active ? "Active" : "Inactive"} - -
- -
-
-

Date

-

- {stop.date} -

-
-
-

Time

-

- {stop.time} -

-
- {stop.address && ( -
-

Address

-

- {stop.address} - {stop.zip ? `, ${stop.zip}` : ""} -

-
- )} - {stop.cutoff_date && ( -
-

Cutoff

-

- {new Date(stop.cutoff_date + "T00:00:00").toLocaleDateString()} -

-
- )} -
-
- -
- + + + + + Back to Stops + -
-

- Assigned Products -

-

- Manage which products are available at this stop. -

+
+
+
+

+ {stop.brands?.name} +

+

+ {stop.city}, {stop.state} +

+

{stop.location}

+
-
- + + {stop.active ? "Active" : "Inactive"} + +
+ +
+
+

Date

+

+ {stop.date} +

+
+
+

Time

+

+ {stop.time} +

+
+ {stop.address && ( +
+

Address

+

+ {stop.address} + {stop.zip ? `, ${stop.zip}` : ""} +

+
+ )} + {stop.cutoff_date && ( +
+

Cutoff

+

+ {new Date(stop.cutoff_date + "T00:00:00").toLocaleDateString()} +

+
+ )} +
-
-
-

Edit Stop

-

- Update stop details, location, and availability. -

- - - {/* Message Customers */} -
-

Message Customers

-

- Send updates to customers with pending pickups at this stop. -

+
+

+ Assigned Products +

+

+ Manage which products are available at this stop. +

-
- +
+ +
+
+ +
+

Edit Stop

+

+ Update stop details, location, and availability. +

+ +
+ +
+
+ + {/* Message Customers */} +
+

Message Customers

+

+ Send updates to customers with pending pickups at this stop. +

+ +
+ +
); -} \ No newline at end of file +} diff --git a/src/app/admin/stops/new/page.tsx b/src/app/admin/stops/new/page.tsx index 97d9294..428ae13 100644 --- a/src/app/admin/stops/new/page.tsx +++ b/src/app/admin/stops/new/page.tsx @@ -3,9 +3,17 @@ import NewStopForm from "@/components/admin/NewStopForm"; import StopProductAssignment from "@/components/admin/StopProductAssignment"; import { getAdminUser } from "@/lib/admin-permissions"; import AdminAccessDenied from "@/components/admin/AdminAccessDenied"; +import { PageHeader } from "@/components/admin/design-system"; import { redirect } from "next/navigation"; import Link from "next/link"; +const StopIcon = () => ( + + + + +); + type Stop = { city: string; state: string; @@ -62,32 +70,39 @@ export default async function NewStopPage({ [brandId] ); + const pageTitle = duplicateFrom ? "Duplicate Stop" : "Create Stop"; + const pageSubtitle = duplicateFrom + ? `Pre-filled from ${duplicateFrom.city}, ${duplicateFrom.state}. Edit and save to create.` + : "Add a new tour stop for Tuxedo Corn or Indian River Direct."; + return ( -
-
-
+
+
+

Operations

+ } + /> +
+ +
+
- ← Back to Stops + + + + Back to Stops -
-
-

- {duplicateFrom ? "Duplicate Stop" : "Create Stop"} -

- -

- {duplicateFrom - ? `Pre-filled from ${duplicateFrom.city}, ${duplicateFrom.state}. Edit and save to create.` - : "Add a new tour stop for Tuxedo Corn or Indian River Direct."} -

- - +
+ +
); -} \ No newline at end of file +} diff --git a/src/app/admin/stops/page.tsx b/src/app/admin/stops/page.tsx index 23bd03f..bd259ac 100644 --- a/src/app/admin/stops/page.tsx +++ b/src/app/admin/stops/page.tsx @@ -3,6 +3,7 @@ import { getAdminUser } from "@/lib/admin-permissions"; import { getActiveBrandId } from "@/lib/brand-scope"; import AdminAccessDenied from "@/components/admin/AdminAccessDenied"; import StopTableClient from "@/components/admin/StopTableClient"; +import { PageHeader } from "@/components/admin/design-system"; import { redirect } from "next/navigation"; const StopIcon = () => ( @@ -75,20 +76,23 @@ export default async function AdminStopsPage({ searchParams }: PageProps) {
- -

Error loading stops

-
-              {error}
-            
-
-

Debug info:

-

adminUser.brand_id: {adminUser.brand_id ?? "null"}

-

adminUser.role: {adminUser.role}

-

adminUser.email: {adminUser.email}

+

Operations

+ } + /> +
+

Error loading stops

+
+                {error}
+              
+
+

Debug info:

+

adminUser.brand_id: {adminUser.brand_id ?? "null"}

+

adminUser.role: {adminUser.role}

+

adminUser.email: {adminUser.email}

+
@@ -115,7 +119,15 @@ export default async function AdminStopsPage({ searchParams }: PageProps) { return (
-
+
+

Operations

+ } + /> +
+
diff --git a/src/components/admin/AddStopModal.tsx b/src/components/admin/AddStopModal.tsx index 194d2b4..8dca66d 100644 --- a/src/components/admin/AddStopModal.tsx +++ b/src/components/admin/AddStopModal.tsx @@ -145,7 +145,7 @@ export default function AddStopModal({ isOpen, onClose, brandId, duplicateFrom,
diff --git a/src/components/admin/EditStopModal.tsx b/src/components/admin/EditStopModal.tsx index f3fd614..3ddbeaa 100644 --- a/src/components/admin/EditStopModal.tsx +++ b/src/components/admin/EditStopModal.tsx @@ -185,8 +185,8 @@ export default function EditStopModal({ isOpen, onClose, brandId, stop, onSucces {error && (
diff --git a/src/components/admin/StopDetailModal.tsx b/src/components/admin/StopDetailModal.tsx index a44a8fa..91f629d 100644 --- a/src/components/admin/StopDetailModal.tsx +++ b/src/components/admin/StopDetailModal.tsx @@ -93,19 +93,25 @@ export default function StopDetailModal({ stopId, onDuplicate, onClose }: Props) > {loading ? (
-
-
-
+
+
+
) : loadError ? ( -
+
{loadError}
) : stop ? (
{/* Tabs */}
setTab("details")}> @@ -223,8 +229,8 @@ function DetailsPanel({ {stop.active ? "Active" : "Inactive"} @@ -265,14 +271,14 @@ function DetailsPanel({ ) : ( Duplicate Stop diff --git a/src/components/admin/StopMessagingForm.tsx b/src/components/admin/StopMessagingForm.tsx index dd916c2..ea6d589 100644 --- a/src/components/admin/StopMessagingForm.tsx +++ b/src/components/admin/StopMessagingForm.tsx @@ -3,6 +3,7 @@ import { useState } from "react"; import { getStopPendingCustomers, type StopCustomer } from "@/actions/stops/get-stop-customers"; import { sendStopBlast } from "@/actions/communications/stop-blast"; +import { AdminButton } from "@/components/admin/design-system"; const quickMessages = [ { label: "Truck running late", value: "Heads up — the truck is running about 15 minutes behind schedule. Thanks for your patience!" }, @@ -84,10 +85,10 @@ export default function StopMessagingForm({ return (
-

+

Send Message

-

+

Notify all customers with pending pickups at this stop.

@@ -96,18 +97,21 @@ export default function StopMessagingForm({ ) : ( <> {customers.length === 0 ? ( -
+
No pending orders for this stop yet.
) : ( -
+
{customers.length} pending order{customers.length !== 1 ? "s" : ""} found {recipients.length !== customers.length && ( — {recipients.length} with contact info @@ -117,21 +121,21 @@ export default function StopMessagingForm({ {/* Channel */}
-