From 883bd827083bd922193d4e489ae2689a5b7be7cc Mon Sep 17 00:00:00 2001 From: tommaso Date: Tue, 7 Jul 2026 15:46:51 +0200 Subject: [PATCH] Avviso storefront per ordini gia' annullati/rimborsati (info non bloccante) Al passo 2 del recesso, se l'ordine risulta gia' annullato (cancelledAt) o rimborsato/voided (financialStatus), mostra un banner informativo ambra (non blocca): il recesso resta ammesso (diritto incondizionato + funzione sempre accessibile Art. 54-bis), ma il consumatore e' informato dello stato. - recesso.copy: NOTICE.orderClosed. - recesso.server: noticeBanner + campo notice in renderStep2 + stile .notice ambra con icona. - proxy: calcola orderClosed al lookup e passa la notice a renderStep2. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01Mv83a29B4eFv5ixoj6PoE1 --- app/app/lib/recesso.copy.ts | 6 ++++++ app/app/lib/recesso.server.ts | 26 +++++++++++++++++++++++++- app/app/routes/proxy.tsx | 6 ++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/app/app/lib/recesso.copy.ts b/app/app/lib/recesso.copy.ts index c8b0908..dcdfb97 100644 --- a/app/app/lib/recesso.copy.ts +++ b/app/app/lib/recesso.copy.ts @@ -47,6 +47,12 @@ export const ERROR = { generic: "Si è verificato un problema. Riprova tra poco.", } as const; +// Avvisi informativi (non bloccanti). +export const NOTICE = { + orderClosed: + "Questo ordine risulta già annullato o rimborsato. Puoi comunque registrare il recesso; il negozio ti contatterà per eventuali dettagli.", +} as const; + // Schermata finale (dopo "Conferma recesso"). export function successMessage( orderName: string, diff --git a/app/app/lib/recesso.server.ts b/app/app/lib/recesso.server.ts index 8a71e30..617cd78 100644 --- a/app/app/lib/recesso.server.ts +++ b/app/app/lib/recesso.server.ts @@ -806,6 +806,21 @@ const PAGE_CSS = ` font-size: 0.92rem; } .error__icon { flex: none; width: 20px; height: 20px; margin-top: 1px; fill: currentColor; } + .notice { + display: flex; + align-items: flex-start; + gap: 10px; + background: rgba(240, 170, 40, 0.14); + border: 1px solid rgba(240, 170, 40, 0.55); + border-left: 3px solid rgba(240, 170, 40, 0.95); + border-radius: var(--radius-sm); + padding: 12px 14px; + margin: 0 0 18px; + color: var(--text); + font-size: 0.9rem; + line-height: 1.5; + } + .notice__icon { flex: none; width: 20px; height: 20px; margin-top: 1px; fill: #e0a020; } /* Riepilogo (step 3) */ .summary { margin: 18px 0 4px; } @@ -893,6 +908,14 @@ function errorBanner(message?: string): string { `; } +function noticeBanner(message?: string): string { + if (!message) return ""; + return `
+ + ${escapeHtml(message)} +
`; +} + /** * Pulsante info "i" + popover nativo (mini-modal, zero JS via Popover API). * Il popover vive nel top-layer; chiusura con Esc, click fuori o pulsante. @@ -985,12 +1008,13 @@ export function renderStep2(data: { customerName?: string; statementText: string; error?: string; + notice?: string; }): string { const customerName = data.customerName ?? ""; return renderShell( stepLayout({ head: stepHead(2, `Ordine ${data.orderName}`), - body: `${errorBanner(data.error)} + body: `${errorBanner(data.error)}${noticeBanner(data.notice)}
diff --git a/app/app/routes/proxy.tsx b/app/app/routes/proxy.tsx index f4552be..38bcbd0 100644 --- a/app/app/routes/proxy.tsx +++ b/app/app/routes/proxy.tsx @@ -24,6 +24,7 @@ import { import { ERROR, EXCLUSION_REASON, + NOTICE, exclusionMessage, statementTemplate, successMessage, @@ -195,12 +196,17 @@ export const action = async ({ request }: ActionFunctionArgs) => { ); } + const orderClosed = + !!match.cancelledAt || + match.financialStatus === "REFUNDED" || + match.financialStatus === "VOIDED"; return htmlResponse( renderStep2({ orderId: match.orderId, orderName: match.orderName, email: match.email, statementText: statementTemplate(match.orderName), + notice: orderClosed ? NOTICE.orderClosed : undefined, }), ); }