fix(pos): handle expired API sessions and add receipt preview close button
This commit is contained in:
@@ -1 +1 @@
|
|||||||
0.2.8
|
0.2.9
|
||||||
|
|||||||
4
project/apps/admin/package-lock.json
generated
4
project/apps/admin/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@mercadodevida/admin",
|
"name": "@mercadodevida/admin",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@mercadodevida/admin",
|
"name": "@mercadodevida/admin",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lexical/history": "^0.49.0",
|
"@lexical/history": "^0.49.0",
|
||||||
"@lexical/html": "^0.49.0",
|
"@lexical/html": "^0.49.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mercadodevida/admin",
|
"name": "@mercadodevida/admin",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --port 3001",
|
"dev": "next dev --port 3001",
|
||||||
|
|||||||
4
project/apps/pos/package-lock.json
generated
4
project/apps/pos/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mercadodevida-pos",
|
"name": "mercadodevida-pos",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mercadodevida-pos",
|
"name": "mercadodevida-pos",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "^16.3.1",
|
"next": "^16.3.1",
|
||||||
"react": "^19.2.8",
|
"react": "^19.2.8",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mercadodevida-pos",
|
"name": "mercadodevida-pos",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --port 3002",
|
"dev": "next dev --port 3002",
|
||||||
|
|||||||
@@ -59,7 +59,15 @@ export default function ReceiptModal({
|
|||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
aria-labelledby="receipt-title"
|
aria-labelledby="receipt-title"
|
||||||
>
|
>
|
||||||
<div className="mx-auto w-full max-w-xl rounded-2xl bg-white p-6 shadow-2xl print:max-w-none print:rounded-none print:p-0 print:shadow-none">
|
<div className="relative mx-auto w-full max-w-xl rounded-2xl bg-white p-6 shadow-2xl print:max-w-none print:rounded-none print:p-0 print:shadow-none">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onDelivered}
|
||||||
|
aria-label="Cerrar"
|
||||||
|
className="no-print absolute right-4 top-4 text-2xl text-gray-400 hover:text-gray-700"
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
{/* Ticket content - only this gets printed */}
|
{/* Ticket content - only this gets printed */}
|
||||||
<div ref={articleRef} className="ticket-print-area">
|
<div ref={articleRef} className="ticket-print-area">
|
||||||
<article className="space-y-4 bg-white text-sm text-gray-900 print:bg-white">
|
<article className="space-y-4 bg-white text-sm text-gray-900 print:bg-white">
|
||||||
|
|||||||
@@ -12,6 +12,15 @@ async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
|
|||||||
...(init?.headers ?? {}),
|
...(init?.headers ?? {}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
if (res.status === 401) {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
window.location.href = '/login';
|
||||||
|
}
|
||||||
|
throw Object.assign(new Error('Sesión caducada, identifícate de nuevo'), {
|
||||||
|
status: 401,
|
||||||
|
code: 'UNAUTHORIZED',
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const err = (await res.json().catch(() => ({ message: res.statusText }))) as {
|
const err = (await res.json().catch(() => ({ message: res.statusText }))) as {
|
||||||
message?: string;
|
message?: string;
|
||||||
@@ -22,6 +31,15 @@ async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
|
|||||||
code: err.error?.code,
|
code: err.error?.code,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Defensive: if a proxy/misconfiguration ever returns HTML on a successful
|
||||||
|
// response, surface a readable message instead of a JSON parse crash.
|
||||||
|
const contentType = res.headers.get('content-type') ?? '';
|
||||||
|
if (!contentType.includes('application/json')) {
|
||||||
|
throw Object.assign(new Error('Respuesta inesperada del servidor (sesión o proxy)'), {
|
||||||
|
status: res.status,
|
||||||
|
code: 'INVALID_RESPONSE',
|
||||||
|
});
|
||||||
|
}
|
||||||
return res.json() as Promise<T>;
|
return res.json() as Promise<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,15 @@ export function proxy(request: NextRequest) {
|
|||||||
cookie.includes('session_token=');
|
cookie.includes('session_token=');
|
||||||
|
|
||||||
if (!hasSession) {
|
if (!hasSession) {
|
||||||
|
// API callers expect JSON. Redirecting them to /login makes fetch() follow
|
||||||
|
// the redirect and receive the HTML login page, which surfaces as the
|
||||||
|
// cryptic "Unexpected token '<'" parse error in the terminal UI.
|
||||||
|
if (pathname.startsWith('/api/')) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: { statusCode: 401, code: 'UNAUTHORIZED', message: 'Authentication required' } },
|
||||||
|
{ status: 401 },
|
||||||
|
);
|
||||||
|
}
|
||||||
return NextResponse.redirect(new URL('/login', request.url));
|
return NextResponse.redirect(new URL('/login', request.url));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
project/frontend/package-lock.json
generated
4
project/frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "16.3.1",
|
"next": "16.3.1",
|
||||||
"react": "19.2.8",
|
"react": "19.2.8",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|||||||
4
project/package-lock.json
generated
4
project/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mercadodevida-backend",
|
"name": "mercadodevida-backend",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mercadodevida-backend",
|
"name": "mercadodevida-backend",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/cookie": "^11.1.2",
|
"@fastify/cookie": "^11.1.2",
|
||||||
"@fastify/cors": "^11.3.0",
|
"@fastify/cors": "^11.3.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mercadodevida-backend",
|
"name": "mercadodevida-backend",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "mercadodevida vNext backend - modular monolith skeleton",
|
"description": "mercadodevida vNext backend - modular monolith skeleton",
|
||||||
|
|||||||
4
project/storefront/package-lock.json
generated
4
project/storefront/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mercadodevida-storefront",
|
"name": "mercadodevida-storefront",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mercadodevida-storefront",
|
"name": "mercadodevida-storefront",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
"@tailwindcss/postcss": "^4.1.17",
|
||||||
"next": "^16.0.5",
|
"next": "^16.0.5",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mercadodevida-storefront",
|
"name": "mercadodevida-storefront",
|
||||||
"version": "0.2.8",
|
"version": "0.2.9",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "mercadodevida customer storefront shell",
|
"description": "mercadodevida customer storefront shell",
|
||||||
|
|||||||
Reference in New Issue
Block a user