When you run a B2B auto parts e-shop, goods don’t stop at the counter — you deliver them to customers. And every customer has a different location, different hours, different requirements. When you have dozens of them, you need a system that tracks who belongs where and what’s being shipped.
I recently added delivery route management to a white-label auto parts e-shop — here’s how it works.
The Problem
The e-shop had orders, delivery notes, invoices — but it was missing a layer connecting customers to specific delivery routes. The admin knew someone needed a delivery, but had to remember whether it was “Kolín-south” or “Kutná Hora”. Documents lacked delivery addresses, contact info, and route notes.
Solution: Three Layers
1. Route Definitions
A new admin page for managing delivery routes. Each route has a name, address, contact person, phone, and notes. Routes can be toggled on and off — inactive routes don’t show up in assignment dropdowns.
// Schema
model DeliveryRoute {
id String @id @default(cuid())
name String
deliveryAddress String?
contactName String?
contactPhone String?
note String?
active Boolean @default(true)
sortOrder Int @default(0)
customers Customer[]
}
2. Customer-to-Route Assignment
A new Delivery tab in the customer detail page. The admin sets:
- Route — pick from active routes
- Delivery address — can differ from the billing address
- Contact person and phone — who receives the goods
- Delivery note — free text (e.g., “call 30 minutes before arrival”)
Delivery details are separate from billing — B2B customers often have a warehouse at a different location than their registered office.
3. Display on Documents
Route and delivery info propagated to:
- Order detail — admin sees the route name at a glance
- Delivery notes and invoices — delivery address, contact, and note on the document
- PDF export — same info in printable form
Server Action Feedback
Alongside delivery routes, I unified the UX feedback for server actions. A new ActionFeedbackForm component wraps <form> with an action handler and automatically shows:
- Pending state — button changes to “Saving…” and gets disabled
- Success state — brief green “Saved” confirmation
- Error state — fallback message on failure
A second component, PendingSubmitButton, solves the same problem at the single-button level — useful when wrapping the whole form isn’t needed.
// Usage
<ActionFeedbackForm
action={updateDeliveryRoute}
pendingLabel="Saving…"
successLabel="Saved"
errorFallback="Save failed"
>
{/* form fields */}
<Button type="submit">Save</Button>
</ActionFeedbackForm>
What It Brought
- Admin sees which route an order belongs to at a glance
- Customers get the correct delivery address on their documents
- The driver gets contact info and notes for each shipment
- New routes can be added without touching code
The whole change stayed within the database (Prisma migration), API layer (server actions), and UI — no external system, no extra dependencies.