From 057ef0a8f3a52c217c8dbadfe08bc699a8cc68b5 Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Sat, 10 Oct 2026 10:09:41 +0700 Subject: [PATCH] fix(marketplace): localize trade state and pending status Trade-record state (revoked/verifying) and the listing pending status were printed raw. New marketUi.trades.stateRevoked/stateVerifying and marketUi.statusPending (en/es). Also reclassify the request tag as cosmetic (never read in the client) in the audit. --- MARKETPLACE_FLOW_AUDIT.md | 13 +++++++++---- src/i18n/en.ts | 3 +++ src/i18n/es.ts | 3 +++ src/pages/ListingDetailPage.tsx | 2 +- src/pages/TradesPage.tsx | 3 ++- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/MARKETPLACE_FLOW_AUDIT.md b/MARKETPLACE_FLOW_AUDIT.md index 0438787..c793f4c 100644 --- a/MARKETPLACE_FLOW_AUDIT.md +++ b/MARKETPLACE_FLOW_AUDIT.md @@ -97,10 +97,12 @@ visibility, terminology, translation). - **[reported] `useTradeReputation` skips `onlyVerified`** (`:216-222`), unlike `useTradeIntegrity`/`useShipmentStatus`, so a hostile relay can inject forged reputation events. -- **[reported] Request back-reference is wrong.** `publishTrade` writes the - listing `a` coord as the `request` tag (`useTradeAttestations.ts:141`), but - NIP.md documents `31872::`; both call sites pass the coord - (`TradesPage.tsx:210`, `ConversationPage.tsx:193`). +- **[reported, cosmetic] Request back-reference is wrong.** `publishTrade` writes + the listing `a` coord as the `request` tag (`useTradeAttestations.ts:141`) where + NIP.md documents `31872::`. Confirmed not consumed anywhere in the + client (a repo-wide scan finds no `request` tag reader), so it is a + spec-conformance issue only, not a functional one; deferred rather than risk a + writer/reader mismatch. - **[reported] Receipts are one global blob, keyed by listing coord, not account-scoped** (`receipts.ts:64-71`), and `ListingOffersPanel` never reads them back (`:74,335`), so the Pay button can reappear and a prior trade's @@ -227,6 +229,9 @@ Second batch (payment, attestation, escrow): `ShippingStatusCard` now show an explicit "could not reach the relays" notice (`marketUi.loadFailed`) instead of an empty / "nothing waiting" / "no trades" state when their query errors. +15. **Localized trade status:** the trade-record `state` and the listing + `pending` status are no longer printed raw (`marketUi.trades.stateRevoked` / + `stateVerifying`, `marketUi.statusPending`). ## 7. Recommended order diff --git a/src/i18n/en.ts b/src/i18n/en.ts index 7f77748..3e69cc6 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -1660,6 +1660,8 @@ marketUi: { recordedSale: 'recorded a sale — confirm your side', confirmSale: 'Confirm sale', confirm: 'Confirm', + stateRevoked: 'revoked', + stateVerifying: 'verifying', nothingWaiting: 'Nothing waiting on you right now. 🛹', yourRecords: 'Your trade records', noTrades: 'No trades yet. Close a deal and confirm it to start building reputation.', @@ -1773,6 +1775,7 @@ marketUi: { paidBody: 'Ask the seller to confirm the trade so it counts for both of you.', }, loadFailed: 'Could not reach the relays. Check your connection and try again.', + statusPending: 'pending', offers: { accepted: 'Accepted', declined: 'Declined', diff --git a/src/i18n/es.ts b/src/i18n/es.ts index d65d13b..65d8b62 100644 --- a/src/i18n/es.ts +++ b/src/i18n/es.ts @@ -1660,6 +1660,8 @@ marketUi: { recordedSale: 'registró una venta — confirma tu parte', confirmSale: 'Confirmar venta', confirm: 'Confirmar', + stateRevoked: 'revocada', + stateVerifying: 'verificando', nothingWaiting: 'No hay nada pendiente por tu parte. 🛹', yourRecords: 'Tus registros de tratos', noTrades: 'Aún no hay tratos. Cierra un trato y confírmalo para empezar a construir reputación.', @@ -1773,6 +1775,7 @@ marketUi: { paidBody: 'Pide al vendedor que confirme el trato para que cuente para ambos.', }, loadFailed: 'No se pudo contactar con los relays. Comprueba tu conexión e inténtalo de nuevo.', + statusPending: 'pendiente', offers: { accepted: 'Aceptada', declined: 'Rechazada', diff --git a/src/pages/ListingDetailPage.tsx b/src/pages/ListingDetailPage.tsx index 1d89eb8..8b4f204 100644 --- a/src/pages/ListingDetailPage.tsx +++ b/src/pages/ListingDetailPage.tsx @@ -200,7 +200,7 @@ export default function ListingDetailPage() { )} {item.status && item.status !== 'active' && !isSold && ( - {item.status.toUpperCase()} + {item.status === 'pending' ? t('marketUi.statusPending') : item.status.toUpperCase()} )} diff --git a/src/pages/TradesPage.tsx b/src/pages/TradesPage.tsx index 0934692..e0f864c 100644 --- a/src/pages/TradesPage.tsx +++ b/src/pages/TradesPage.tsx @@ -274,6 +274,7 @@ export default function TradesPage() { : null; const role = roleTyped === 'sold' ? t('marketUi.trades.roleSold') : roleTyped === 'bought' ? t('marketUi.trades.roleBought') : t('marketUi.trades.roleTrade'); const state = ev.tags.find(([t]) => t === 's')?.[1] ?? 'valid'; + const stateLabel = state === 'revoked' ? t('marketUi.trades.stateRevoked') : state === 'verifying' ? t('marketUi.trades.stateVerifying') : state; const counterparty = ev.tags.find(([t]) => t === 'p')?.[1]; return ( @@ -293,7 +294,7 @@ export default function TradesPage() {

{new Date(ev.created_at * 1000).toLocaleDateString(dateLocaleCode())} - {state !== 'valid' && ` · ${state}`} + {state !== 'valid' && ` · ${stateLabel}`}

{parsed && (