Account dashboard¶
/account is the logged-in customer's home — designed to feel like a native
commerce app rather than a WordPress dashboard. Mobile-first, every section
is a self-contained card, and every primary action has a >= 44px tap target.
Layout¶
┌─────────────────────────────────────────────┐
│ AccountHeader │ ← greeting · Plug Points · stats
├──────────────────────┬──────────────────────┤
│ Reorder your last │ Upcoming delivery │ ← stacked on phone, side-by-side at md+
├──────────────────────┴──────────────────────┤
│ Your orders (last 10) │ ← richer cards w/ status pill + tracking
├─────────────────────────────────────────────┤
│ Saved boxes │ ← grid of custom boxes from /box/mine
├─────────────────────────────────────────────┤
│ Account links │ ← Subscription, Address, Preferences,
└─────────────────────────────────────────────┘ Sign out
The page itself is a server component (apps/web/app/account/page.tsx). The
only client island is <ReorderButton />, which holds a per-component pending
flag while it walks the cart store.
Sections¶
Account header¶
components/account/AccountHeader.tsx — server component. Renders the
greeting, a Plug Points badge, and three quick stats (orders, points, status
line with member-since).
Plug Points balance and the member-since date are placeholders — see the follow-ups below.
Reorder your last (one-tap)¶
components/account/ReorderButton.tsx — client component. Walks the most
recent order's line items and calls useCart.add({ id, quantity: 1 }) for
each, sequentially. Sequential is deliberate: Woo's Store API rotates the
Cart-Token on every mutation, and racing add-to-cart calls can drop items.
Once everything is queued the mini-cart pops open via
useMobileNav.openMiniCart().
Per-item failures (e.g. a discontinued product) are swallowed so a partial reorder still works.
Upcoming delivery (placeholder)¶
components/account/UpcomingDelivery.tsx — pure render. Always shows the
"no subscription yet" placeholder branch today. The real-data branch is
implemented and waiting for WP Subscriptions / Stripe Billing data to start
flowing into the page (Phase 2).
Your orders¶
components/account/OrderCard.tsx — server component. For each line item:
- Slugify the product name and look it up in
lib/fruit-taxonomy.ts. - If the slug is a known fruit, prefer the unified local PNG via
localFruitImage(slug)(under/media/fruits/{slug}.png). - Otherwise fall back to the Woo image URL that came back on the line item.
Tracking link discovery (pickTrackingUrl) tries the well-known meta_data
keys used by the popular Woo tracking plugins: tracking_url,
_tracking_url, aftership_tracking_url, and the array shape
_wc_shipment_tracking_items[0].tracking_link. Only https:// URLs are
accepted. The renderer hides the button entirely when none are present.
Saved boxes¶
components/account/SavedBoxesList.tsx — server component. Reads from a new
helper, lib/saved-boxes.ts → getMySavedBoxes(), which forwards the JWT
from the fp_auth cookie to GET /fruitplug/v1/box/mine. Returns [] on
any failure (network, 401, malformed body) so the empty state is always
safe to render.
Account links¶
components/account/AccountLinks.tsx — list of secondary destinations
(Subscription, Address, Preferences, Sign out). Sign out reuses the existing
<LogoutButton /> so we don't duplicate the auth flow.
Data sources¶
| Section | Endpoint | Auth | Notes |
|---|---|---|---|
| Header (profile) | GET /fruitplug/v1/auth/me |
JWT | Plugin's profile read |
| Orders | GET /wc/v3/orders?customer={id} |
Admin (consumer key/secret) | Server-side only |
| Saved boxes | GET /fruitplug/v1/box/mine |
JWT | New getMySavedBoxes() helper |
| Subscription | (not yet wired) | (future) | Placeholder card |
Known placeholders¶
These are intentional and should be picked up in follow-up slices once the underlying data is available from the WP plugin:
- Plug Points balance — the loyalty schema isn't wired into
/auth/meyet. The header readsMePayload.points_balanceand renders—/ "coming soon" when undefined. - Member since — the plugin's
/auth/medoesn't always returnregistered/created_at. Without it the status line falls back to "member of Fruit Plug". - Upcoming delivery — requires Phase 2 subscriptions infrastructure.
The component contract (
UpcomingSubscription) is in place; pass it a non-nullsubscriptionprop to activate the live branch.
Indexability¶
The page sets robots: { index: false, follow: false } and is excluded
from the sitemap. Account routes shouldn't be discoverable from search.