Add OTP login flow and multi-cafe role switching

Introduce an OTP input box on login/register, surface user roles and a
cafe chooser, add a dashboard switch button in the POS screen, and
register OTP validators explicitly to survive Docker layer caching.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-05-29 17:14:46 +03:30
parent 923a00b113
commit c68cca4f17
15 changed files with 364 additions and 44 deletions
+4 -2
View File
@@ -76,7 +76,9 @@ export async function apiGetPaged<T>(url: string): Promise<{ items: T[]; meta: P
export class ApiClientError extends Error {
constructor(
public readonly code: string,
message: string
message: string,
/** Payload returned alongside a non-success response (e.g. CHOOSE_CAFE choices). */
public readonly payload?: unknown
) {
super(message);
this.name = "ApiClientError";
@@ -87,7 +89,7 @@ export async function apiPost<T, B = unknown>(url: string, body?: B): Promise<T>
const { data } = await api.post<ApiResponse<T>>(url, body);
if (!data.success || data.data === undefined) {
const code = data.error?.code ?? "REQUEST_FAILED";
throw new ApiClientError(code, data.error?.message ?? "Request failed");
throw new ApiClientError(code, data.error?.message ?? "Request failed", data.data);
}
return data.data;
}
+13
View File
@@ -4,6 +4,13 @@ export interface ApiResponse<T> {
error?: { code: string; message: string; field?: string };
}
export interface CafeMembership {
cafeId: string;
cafeName: string;
role: string;
planTier: string;
}
export interface AuthTokenResponse {
accessToken: string;
refreshToken: string;
@@ -15,6 +22,12 @@ export interface AuthTokenResponse {
language: string;
actor?: string;
branchId?: string | null;
memberships?: CafeMembership[] | null;
}
/** Returned (in the data field) when a phone belongs to multiple cafés. */
export interface CafeChoicesResponse {
cafes: CafeMembership[];
}
export interface MenuCategory {