63 lines
2.6 KiB
TypeScript
63 lines
2.6 KiB
TypeScript
// Browser requests stay on the POS origin. The Next.js route handler proxies
|
|
// `/api/*` to the backend, so LAN clients never resolve their own localhost.
|
|
const API = '/api';
|
|
|
|
async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
|
|
const res = await fetch(`${API}${path}`, {
|
|
...init,
|
|
credentials: 'include',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...(init?.headers ?? {}),
|
|
},
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({ message: res.statusText })) as {
|
|
message?: string;
|
|
error?: { message?: string; code?: string };
|
|
};
|
|
throw Object.assign(
|
|
new Error(err.error?.message ?? err.message ?? 'Request failed'),
|
|
{ status: res.status, code: err.error?.code },
|
|
);
|
|
}
|
|
return res.json() as Promise<T>;
|
|
}
|
|
|
|
export const posApi = {
|
|
/** Get current terminal info. Requires x-terminal-id header set by middleware. */
|
|
me: () => apiFetch('/pos/terminals/me'),
|
|
/** Bind terminal with code. */
|
|
bind: (bindingCode: string) =>
|
|
apiFetch<{ terminalId: string; storeId: string }>('/pos/terminals/bind', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ bindingCode }),
|
|
}),
|
|
/** Get POS config (store + terminal + payment methods + session status). */
|
|
config: <T>() => apiFetch<T>('/pos/config'),
|
|
/** Open the daily cash session for the bound terminal. */
|
|
openSession: (openingCashCents: number) =>
|
|
apiFetch<{ id: string; status: 'OPEN' }>('/pos/sessions', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ openingCashCents }),
|
|
}),
|
|
/** List products by query. */
|
|
searchProducts: (q: string, storeId?: string, limit = 20) =>
|
|
apiFetch(`/pos/products/search?q=${encodeURIComponent(q)}&storeId=${storeId ?? ''}&limit=${limit}`),
|
|
/** Get product by EAN. */
|
|
productByEan: (ean: string) => apiFetch(`/pos/products/by-ean/${encodeURIComponent(ean)}`),
|
|
/** Get product by SKU. */
|
|
productBySku: (sku: string) => apiFetch(`/pos/products/by-sku/${encodeURIComponent(sku)}`),
|
|
/** Search identity customers for sale association. */
|
|
searchCustomers: (q: string) => apiFetch(`/pos/customers/search?q=${encodeURIComponent(q)}`),
|
|
/** Create an identity customer from the register. */
|
|
createCustomer: <T>(data: { email: string; displayName?: string; phone?: string }) =>
|
|
apiFetch<T>('/pos/customers', { method: 'POST', body: JSON.stringify(data) }),
|
|
};
|
|
|
|
export const authApi = {
|
|
login: (email: string, password: string) =>
|
|
apiFetch('/backoffice/auth/login', { method: 'POST', body: JSON.stringify({ email, password }) }),
|
|
logout: () => apiFetch('/backoffice/auth/logout', { method: 'POST' }),
|
|
};
|