- Wire up Better Auth (email/password + Google/Apple SSO) with a sign-in/sign-up UI, header account menu, and a basket that follows the signed-in-or-guest state. - Give the order status page a vertical timeline per preparation step (with a distinct customer-facing name separate from the machine tag, a done/in-progress/queued/pending look, and a sonar-ping highlight on the active step), a formatted ETA (relative under 3h, absolute clock time beyond that), and Buy again / Get help / Cancel actions. - Expand Pizza's recipe into 6 steps across a shared prep station and the existing oven/assembly stations, with matching schema, seed, and domain changes plus updated/added test coverage. - Add an Orders list (account orders via session, guest orders via a locally remembered access-token list) with a shared getOrdersForCustomer domain summary, and remember a guest's name/contact after their first order so checkout doesn't ask again. - Improve page transitions with the View Transitions API: a shared element morph between an order card and its detail page, a stable (non-jumping) header across navigations, and reduced-motion handling. - Add a Ghost Kitchen wordmark (Space Grotesk, faded "Ghost", ghost icon standing in for the "o") and shrink the basket icon to match the rest of the header controls. - Add a run-ghost-kitchen agent skill documenting local setup, the dev-server driver, and the gotchas hit along the way. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
40 lines
1.1 KiB
TypeScript
40 lines
1.1 KiB
TypeScript
// A guest's name/contact, remembered locally so checkout doesn't ask again
|
|
// on their next order from this browser.
|
|
const STORAGE_KEY = 'ghost-kitchen-guest-identity'
|
|
|
|
export type GuestIdentity = { name: string; contact: string }
|
|
|
|
const isGuestIdentity = (value: unknown): value is GuestIdentity =>
|
|
typeof value === 'object' &&
|
|
value !== null &&
|
|
typeof (value as GuestIdentity).name === 'string' &&
|
|
typeof (value as GuestIdentity).contact === 'string'
|
|
|
|
export const getGuestIdentity = (): GuestIdentity | null => {
|
|
try {
|
|
const raw = window.localStorage.getItem(STORAGE_KEY)
|
|
if (!raw) return null
|
|
const parsed: unknown = JSON.parse(raw)
|
|
return isGuestIdentity(parsed) ? parsed : null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export const saveGuestIdentity = (identity: GuestIdentity) => {
|
|
try {
|
|
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(identity))
|
|
} catch {
|
|
// Unavailable (private mode, quota) — checkout still works, it just
|
|
// asks again next time.
|
|
}
|
|
}
|
|
|
|
export const clearGuestIdentity = () => {
|
|
try {
|
|
window.localStorage.removeItem(STORAGE_KEY)
|
|
} catch {
|
|
// Unavailable — nothing to clear.
|
|
}
|
|
}
|