From 8b895a48582852e2200bfde99649882cb3e6afc9 Mon Sep 17 00:00:00 2001
From: SkateSpots
Date: Thu, 29 Oct 2026 10:27:02 +0700
Subject: [PATCH] feat: marketplace saved searches, quick offers, safety
---
src/components/OfferDialog.tsx | 20 ++++
src/i18n/ca/batch1.ts | 16 +++
src/i18n/cs/drift.ts | 16 +++
src/i18n/de/drift.ts | 16 +++
src/i18n/el/drift.ts | 16 +++
src/i18n/eu/batch1.ts | 16 +++
src/i18n/fr/drift.ts | 16 +++
src/i18n/gl/batch1.ts | 16 +++
src/i18n/hi/batch1.ts | 16 +++
src/i18n/id/drift.ts | 16 +++
src/i18n/it/drift.ts | 16 +++
src/i18n/ja/drift.ts | 16 +++
src/i18n/ko/drift.ts | 16 +++
src/i18n/legacy/index.ts | 3 +
src/i18n/legacy/marketplaceExtrasUi.ts | 35 ++++++
src/i18n/nl/drift.ts | 16 +++
src/i18n/pl/drift.ts | 16 +++
src/i18n/pt/drift.ts | 16 +++
src/i18n/ro/drift.ts | 16 +++
src/i18n/ru/drift.ts | 16 +++
src/i18n/sv/drift.ts | 16 +++
src/i18n/th/drift.ts | 16 +++
src/i18n/tr/drift.ts | 16 +++
src/i18n/uk/drift.ts | 16 +++
src/i18n/vi/drift.ts | 16 +++
src/i18n/zh-CN/drift.ts | 16 +++
src/i18n/zh-TW/drift.ts | 16 +++
src/pages/GearSwapPage.tsx | 147 ++++++++++++++++++++++++-
28 files changed, 586 insertions(+), 3 deletions(-)
create mode 100644 src/i18n/legacy/marketplaceExtrasUi.ts
diff --git a/src/components/OfferDialog.tsx b/src/components/OfferDialog.tsx
index 6f301af..f21b328 100644
--- a/src/components/OfferDialog.tsx
+++ b/src/components/OfferDialog.tsx
@@ -127,6 +127,26 @@ export function OfferDialog({
+
+ {t('marketplaceExtrasUi.offerTemplates')}
+
+
+ {[
+ t('marketplaceExtrasUi.offerDiscount'),
+ t('marketplaceExtrasUi.offerSwap'),
+ t('marketplaceExtrasUi.offerPickup'),
+ t('marketplaceExtrasUi.offerShipping'),
+ ].map((template) => (
+
+ ))}
+
diff --git a/src/i18n/ca/batch1.ts b/src/i18n/ca/batch1.ts
index 2fecd86..9519c74 100644
--- a/src/i18n/ca/batch1.ts
+++ b/src/i18n/ca/batch1.ts
@@ -1373,6 +1373,22 @@ const batch1 = {
trust: "Confiança",
noResults: "Cap resultat per a «{{query}}».",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Cerques desades",
+ saveSearch: "Desa la cerca",
+ searchName: "Posa nom a aquesta cerca…",
+ deleteSearch: "Elimina la cerca desada",
+ safetyTitle: "Compra i ven amb seguretat",
+ safetyMeet: "Trobeu-vos en un lloc públic i reviseu el material abans de pagar.",
+ safetyKeys: "No comparteixis mai frases seed ni claus privades. Mantén el tracte al xat de l'aplicació.",
+ safetyEscrow: "Per als enviaments, llegeix primer les condicions de l'escrow: l'escrow Cashu és només per a l'app nativa i no està verificat.",
+ safetyMore: "Llegeix les normes del mercat",
+ offerTemplates: "Notes ràpides",
+ offerDiscount: "Pots fer un 10 % de descompte?",
+ offerSwap: "Consideraries un intercanvi?",
+ offerPickup: "Puc recollir-ho aquesta setmana.",
+ offerShipping: "Pots agrupar l'enviament?",
+ },
};
export default batch1;
diff --git a/src/i18n/cs/drift.ts b/src/i18n/cs/drift.ts
index b73279b..f77903e 100644
--- a/src/i18n/cs/drift.ts
+++ b/src/i18n/cs/drift.ts
@@ -451,6 +451,22 @@ const drift = {
trust: "Důvěra",
noResults: "Žádné výsledky pro „{{query}}“.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Uložená hledání",
+ saveSearch: "Uložit hledání",
+ searchName: "Pojmenuj toto hledání…",
+ deleteSearch: "Smazat uložené hledání",
+ safetyTitle: "Nakupuj a prodávej bezpečně",
+ safetyMeet: "Sejděte se na veřejném místě a vybavení si před platbou prohlédněte.",
+ safetyKeys: "Nikdy nesdílej seed fráze ani soukromé klíče. Drž obchod v chatu v aplikaci.",
+ safetyEscrow: "U zásilek si nejdřív přečti podmínky escrow: Cashu escrow je jen pro nativní aplikaci a je neověřené.",
+ safetyMore: "Přečíst pravidla tržiště",
+ offerTemplates: "Rychlé poznámky",
+ offerDiscount: "Můžeš dát slevu 10 %?",
+ offerSwap: "Nepřemýšlel bys o výměně?",
+ offerPickup: "Tento týden si to můžu vyzvednout.",
+ offerShipping: "Můžeš spojit dopravu?",
+ },
};
export default drift;
diff --git a/src/i18n/de/drift.ts b/src/i18n/de/drift.ts
index 64430da..03e9b04 100644
--- a/src/i18n/de/drift.ts
+++ b/src/i18n/de/drift.ts
@@ -453,6 +453,22 @@ const drift = {
trust: "Vertrauen",
noResults: "Keine Ergebnisse für „{{query}}“.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Gespeicherte Suchen",
+ saveSearch: "Suche speichern",
+ searchName: "Diese Suche benennen…",
+ deleteSearch: "Gespeicherte Suche löschen",
+ safetyTitle: "Sicher kaufen & verkaufen",
+ safetyMeet: "Trefft euch an einem öffentlichen Ort und prüft die Ausrüstung, bevor ihr bezahlt.",
+ safetyKeys: "Teile niemals Seed-Phrasen oder private Schlüssel. Wickle den Deal im In-App-Chat ab.",
+ safetyEscrow: "Bei Versandgeschäften lies zuerst die Escrow-Bedingungen: Cashu-Escrow gibt es nur in der nativen App, und sie ist nicht verifiziert.",
+ safetyMore: "Marktplatz-Richtlinien lesen",
+ offerTemplates: "Schnellnotizen",
+ offerDiscount: "Gehen 10 % Rabatt?",
+ offerSwap: "Würdest du über einen Tausch nachdenken?",
+ offerPickup: "Ich kann es diese Woche abholen.",
+ offerShipping: "Kannst du den Versand bündeln?",
+ },
};
export default drift;
diff --git a/src/i18n/el/drift.ts b/src/i18n/el/drift.ts
index 67c90a5..8012509 100644
--- a/src/i18n/el/drift.ts
+++ b/src/i18n/el/drift.ts
@@ -455,6 +455,22 @@ const drift = {
trust: "Εμπιστοσύνη",
noResults: "Κανένα αποτέλεσμα για «{{query}}».",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Αποθηκευμένες αναζητήσεις",
+ saveSearch: "Αποθήκευση αναζήτησης",
+ searchName: "Ονόμασε αυτή την αναζήτηση…",
+ deleteSearch: "Διαγραφή αποθηκευμένης αναζήτησης",
+ safetyTitle: "Αγόρασε και πούλα με ασφάλεια",
+ safetyMeet: "Συναντηθείτε σε δημόσιο σημείο και ελέγξτε τον εξοπλισμό πριν πληρώσετε.",
+ safetyKeys: "Ποτέ μη μοιράζεσαι seed phrases ή ιδιωτικά κλειδιά. Κράτα τη συναλλαγή στο chat της εφαρμογής.",
+ safetyEscrow: "Για αποστολές, διάβασε πρώτα τους όρους του escrow: το Cashu escrow είναι μόνο για την εγγενή εφαρμογή και δεν είναι επαληθευμένο.",
+ safetyMore: "Διάβασε τους κανόνες της αγοράς",
+ offerTemplates: "Γρήγορες σημειώσεις",
+ offerDiscount: "Μπορείς να κάνεις 10% έκπτωση;",
+ offerSwap: "Θα σκεφτόσουν μια ανταλλαγή;",
+ offerPickup: "Μπορώ να το παραλάβω αυτή την εβδομάδα.",
+ offerShipping: "Μπορείς να συνδυάσεις τα μεταφορικά;",
+ },
};
export default drift;
diff --git a/src/i18n/eu/batch1.ts b/src/i18n/eu/batch1.ts
index 6a7675b..869c5f9 100644
--- a/src/i18n/eu/batch1.ts
+++ b/src/i18n/eu/batch1.ts
@@ -1373,6 +1373,22 @@ const batch1 = {
trust: "Konfiantza",
noResults: "Ez dago emaitzarik «{{query}}» bilaketarako.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Gordetako bilaketak",
+ saveSearch: "Gorde bilaketa",
+ searchName: "Eman izena bilaketa honi…",
+ deleteSearch: "Ezabatu gordetako bilaketa",
+ safetyTitle: "Erosi eta saldu segurtasunez",
+ safetyMeet: "Elkartu leku publiko batean eta aztertu materiala ordaindu aurretik.",
+ safetyKeys: "Inoiz ez partekatu seed esaldiak edo gako pribatuak. Egin tratuak aplikazioko txatean.",
+ safetyEscrow: "Bidalketetan, irakurri lehenik escrow baldintzak: Cashu escrow aplikazio natiboan soilik dago eta ez dago egiaztatuta.",
+ safetyMore: "Irakurri azokaren jarraibideak",
+ offerTemplates: "Ohar azkarrak",
+ offerDiscount: "%10eko deskontua egin dezakezu?",
+ offerSwap: "Trukea kontuan hartuko zenuke?",
+ offerPickup: "Aste honetan jaso dezaket.",
+ offerShipping: "Bidalketa batu dezakezu?",
+ },
};
export default batch1;
diff --git a/src/i18n/fr/drift.ts b/src/i18n/fr/drift.ts
index 5697a07..2802078 100644
--- a/src/i18n/fr/drift.ts
+++ b/src/i18n/fr/drift.ts
@@ -453,6 +453,22 @@ const drift = {
trust: "Confiance",
noResults: "Aucun résultat pour « {{query}} ».",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Recherches enregistrées",
+ saveSearch: "Enregistrer la recherche",
+ searchName: "Nommer cette recherche…",
+ deleteSearch: "Supprimer la recherche enregistrée",
+ safetyTitle: "Acheter et vendre en toute sécurité",
+ safetyMeet: "Retrouvez-vous dans un lieu public et inspectez le matériel avant de payer.",
+ safetyKeys: "Ne partagez jamais de phrases de récupération ni de clés privées. Gardez la transaction dans le chat de l'application.",
+ safetyEscrow: "Pour les envois, lisez d'abord les conditions de l'escrow : l'escrow Cashu est réservé à l'application native et n'est pas vérifié.",
+ safetyMore: "Lire les règles du marché",
+ offerTemplates: "Notes rapides",
+ offerDiscount: "Peux-tu faire 10 % de remise ?",
+ offerSwap: "Envisagerais-tu un échange ?",
+ offerPickup: "Je peux venir le chercher cette semaine.",
+ offerShipping: "Peux-tu regrouper l'expédition ?",
+ },
};
export default drift;
diff --git a/src/i18n/gl/batch1.ts b/src/i18n/gl/batch1.ts
index 9660eb3..0c924d3 100644
--- a/src/i18n/gl/batch1.ts
+++ b/src/i18n/gl/batch1.ts
@@ -1373,6 +1373,22 @@ const batch1 = {
trust: "Confianza",
noResults: "Sen resultados para «{{query}}».",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Buscas gardadas",
+ saveSearch: "Gardar busca",
+ searchName: "Ponlle nome a esta busca…",
+ deleteSearch: "Eliminar busca gardada",
+ safetyTitle: "Compra e vende con seguridade",
+ safetyMeet: "Quedade nun lugar público e revisade o material antes de pagar.",
+ safetyKeys: "Nunca compartas frases seed nin claves privadas. Mantén o trato na chat da aplicación.",
+ safetyEscrow: "Para os envíos, le primeiro as condicións do escrow: o escrow Cashu é só para a app nativa e non está verificado.",
+ safetyMore: "Ler as normas do mercado",
+ offerTemplates: "Notas rápidas",
+ offerDiscount: "Podes facer un 10 % de desconto?",
+ offerSwap: "Considerarías un intercambio?",
+ offerPickup: "Podo recollerlo esta semana.",
+ offerShipping: "Podes agrupar o envío?",
+ },
};
export default batch1;
diff --git a/src/i18n/hi/batch1.ts b/src/i18n/hi/batch1.ts
index a9a1988..78d50fc 100644
--- a/src/i18n/hi/batch1.ts
+++ b/src/i18n/hi/batch1.ts
@@ -1373,6 +1373,22 @@ const batch1 = {
trust: "भरोसा",
noResults: "“{{query}}” के लिए कोई परिणाम नहीं।",
},
+ marketplaceExtrasUi: {
+ savedSearches: "सहेजी गई खोजें",
+ saveSearch: "खोज सहेजें",
+ searchName: "इस खोज को नाम दें…",
+ deleteSearch: "सहेजी गई खोज हटाएं",
+ safetyTitle: "सुरक्षित रूप से खरीदें और बेचें",
+ safetyMeet: "किसी सार्वजनिक जगह पर मिलें और भुगतान से पहले सामान जांच लें।",
+ safetyKeys: "सीड वाक्यांश या निजी कुंजियां कभी साझा न करें। सौदा ऐप की चैट में ही रखें।",
+ safetyEscrow: "शिपिंग वाले सौदों के लिए पहले एस्क्रो की शर्तें पढ़ें: Cashu एस्क्रो केवल नेटिव ऐप में है और सत्यापित नहीं है।",
+ safetyMore: "मार्केटप्लेस दिशानिर्देश पढ़ें",
+ offerTemplates: "झटपट नोट्स",
+ offerDiscount: "क्या आप 10% छूट दे सकते हैं?",
+ offerSwap: "क्या आप अदला-बदली पर विचार करेंगे?",
+ offerPickup: "मैं इसे इस हफ्ते खुद ले सकता/सकती हूं।",
+ offerShipping: "क्या आप शिपिंग जोड़ सकते हैं?",
+ },
};
export default batch1;
diff --git a/src/i18n/id/drift.ts b/src/i18n/id/drift.ts
index ecc4f7a..b29ff8e 100644
--- a/src/i18n/id/drift.ts
+++ b/src/i18n/id/drift.ts
@@ -447,6 +447,22 @@ const driftStrings = {
trust: "Kepercayaan",
noResults: "Tidak ada hasil untuk “{{query}}”.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Pencarian tersimpan",
+ saveSearch: "Simpan pencarian",
+ searchName: "Beri nama pencarian ini…",
+ deleteSearch: "Hapus pencarian tersimpan",
+ safetyTitle: "Beli & jual dengan aman",
+ safetyMeet: "Bertemulah di tempat umum dan periksa perlengkapannya sebelum membayar.",
+ safetyKeys: "Jangan pernah membagikan frasa seed atau kunci privat. Lakukan transaksi di chat dalam aplikasi.",
+ safetyEscrow: "Untuk pengiriman, baca dulu ketentuan escrow: escrow Cashu hanya untuk aplikasi native dan belum terverifikasi.",
+ safetyMore: "Baca panduan marketplace",
+ offerTemplates: "Catatan cepat",
+ offerDiscount: "Bisa diskon 10%?",
+ offerSwap: "Mau mempertimbangkan tukar tambah?",
+ offerPickup: "Saya bisa ambil sendiri minggu ini.",
+ offerShipping: "Bisa gabung ongkos kirimnya?",
+ },
};
export default driftStrings;
diff --git a/src/i18n/it/drift.ts b/src/i18n/it/drift.ts
index 54b6288..d40a5bc 100644
--- a/src/i18n/it/drift.ts
+++ b/src/i18n/it/drift.ts
@@ -453,6 +453,22 @@ const drift = {
trust: "Fiducia",
noResults: "Nessun risultato per «{{query}}».",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Ricerche salvate",
+ saveSearch: "Salva ricerca",
+ searchName: "Dai un nome a questa ricerca…",
+ deleteSearch: "Elimina ricerca salvata",
+ safetyTitle: "Compra e vendi in sicurezza",
+ safetyMeet: "Incontratevi in un luogo pubblico e controllate l'attrezzatura prima di pagare.",
+ safetyKeys: "Non condividere mai frasi seed o chiavi private. Tieni lo scambio nella chat dell'app.",
+ safetyEscrow: "Per le spedizioni, leggi prima i termini dell'escrow: l'escrow Cashu è solo per l'app nativa e non è verificato.",
+ safetyMore: "Leggi le linee guida del marketplace",
+ offerTemplates: "Note rapide",
+ offerDiscount: "Puoi fare uno sconto del 10%?",
+ offerSwap: "Prenderesti in considerazione uno scambio?",
+ offerPickup: "Posso ritirarlo questa settimana.",
+ offerShipping: "Puoi raggruppare la spedizione?",
+ },
};
export default drift;
diff --git a/src/i18n/ja/drift.ts b/src/i18n/ja/drift.ts
index 2028255..27eb2f5 100644
--- a/src/i18n/ja/drift.ts
+++ b/src/i18n/ja/drift.ts
@@ -463,6 +463,22 @@ const drift: Dict = {
trust: "信頼",
noResults: "「{{query}}」の結果はありません。",
},
+ marketplaceExtrasUi: {
+ savedSearches: "保存した検索",
+ saveSearch: "検索を保存",
+ searchName: "この検索に名前を付ける…",
+ deleteSearch: "保存した検索を削除",
+ safetyTitle: "安全に売買する",
+ safetyMeet: "人目のある場所で待ち合わせ、支払う前にギアを確認しましょう。",
+ safetyKeys: "シードフレーズや秘密鍵は絶対に共有しないでください。取引はアプリ内チャットで進めましょう。",
+ safetyEscrow: "発送の取引では、まずエスクローの条件を読んでください。Cashu エスクローはネイティブアプリ専用で、未検証です。",
+ safetyMore: "マーケットプレイスのガイドラインを読む",
+ offerTemplates: "クイックメモ",
+ offerDiscount: "10% オフにできますか?",
+ offerSwap: "交換は検討できますか?",
+ offerPickup: "今週中に受け取れます。",
+ offerShipping: "送料をまとめられますか?",
+ },
};
export default drift;
diff --git a/src/i18n/ko/drift.ts b/src/i18n/ko/drift.ts
index f77b7cc..11bca11 100644
--- a/src/i18n/ko/drift.ts
+++ b/src/i18n/ko/drift.ts
@@ -463,6 +463,22 @@ const drift: Dict = {
trust: "신뢰",
noResults: "“{{query}}”에 대한 결과가 없습니다.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "저장된 검색",
+ saveSearch: "검색 저장",
+ searchName: "이 검색 이름 지정…",
+ deleteSearch: "저장된 검색 삭제",
+ safetyTitle: "안전하게 사고팔기",
+ safetyMeet: "공공장소에서 만나 결제 전에 장비를 확인하세요.",
+ safetyKeys: "시드 문구나 개인 키를 절대 공유하지 마세요. 거래는 앱 내 채팅에서 진행하세요.",
+ safetyEscrow: "배송 거래라면 먼저 에스크로 약관을 읽으세요. Cashu 에스크로는 네이티브 앱 전용이며 검증되지 않았습니다.",
+ safetyMore: "마켓플레이스 가이드라인 읽기",
+ offerTemplates: "빠른 메모",
+ offerDiscount: "10% 할인해 주실 수 있나요?",
+ offerSwap: "교환도 고려해 보시겠어요?",
+ offerPickup: "이번 주에 직접 수령할 수 있어요.",
+ offerShipping: "배송비를 묶을 수 있나요?",
+ },
};
export default drift;
diff --git a/src/i18n/legacy/index.ts b/src/i18n/legacy/index.ts
index fce14a3..1adb6b5 100644
--- a/src/i18n/legacy/index.ts
+++ b/src/i18n/legacy/index.ts
@@ -6,6 +6,7 @@ import notify from './notify';
import misc from './misc';
import cordnUi from './cordnUi';
import communityUi from './communityUi';
+import marketplaceExtrasUi from './marketplaceExtrasUi';
import globalSearchUi from './globalSearchUi';
import signerPromptUi from './signerPromptUi';
import newsletterDraftUi from './newsletterDraftUi';
@@ -24,6 +25,7 @@ export const legacyEn = {
legacyMiscUi: misc.en,
cordnUi: cordnUi.en,
communityUi: communityUi.en,
+ marketplaceExtrasUi: marketplaceExtrasUi.en,
globalSearchUi: globalSearchUi.en,
signerPromptUi: signerPromptUi.en,
newsletterDraftUi: newsletterDraftUi.en,
@@ -38,6 +40,7 @@ export const legacyEs = {
legacyMiscUi: misc.es,
cordnUi: cordnUi.es,
communityUi: communityUi.es,
+ marketplaceExtrasUi: marketplaceExtrasUi.es,
globalSearchUi: globalSearchUi.es,
signerPromptUi: signerPromptUi.es,
newsletterDraftUi: newsletterDraftUi.es,
diff --git a/src/i18n/legacy/marketplaceExtrasUi.ts b/src/i18n/legacy/marketplaceExtrasUi.ts
new file mode 100644
index 0000000..d21a027
--- /dev/null
+++ b/src/i18n/legacy/marketplaceExtrasUi.ts
@@ -0,0 +1,35 @@
+const marketplaceExtrasUi = {
+ en: {
+ savedSearches: 'Saved searches',
+ saveSearch: 'Save search',
+ searchName: 'Name this search…',
+ deleteSearch: 'Delete saved search',
+ safetyTitle: 'Buy & sell safely',
+ safetyMeet: 'Meet in a public spot and inspect the gear before paying.',
+ safetyKeys: 'Never share seed phrases or private keys. Keep the deal in the in-app chat.',
+ safetyEscrow: 'For shipped deals, read the escrow terms first: Cashu escrow is native-only and unverified.',
+ safetyMore: 'Read the marketplace guidelines',
+ offerTemplates: 'Quick notes',
+ offerDiscount: 'Can you do 10% off?',
+ offerSwap: 'Would you consider a swap?',
+ offerPickup: 'I can pick up this week.',
+ offerShipping: 'Can you bundle shipping?',
+ },
+ es: {
+ savedSearches: 'Búsquedas guardadas',
+ saveSearch: 'Guardar búsqueda',
+ searchName: 'Ponle nombre a esta búsqueda…',
+ deleteSearch: 'Eliminar búsqueda guardada',
+ safetyTitle: 'Compra y vende con seguridad',
+ safetyMeet: 'Quedad en un sitio público y revisa el material antes de pagar.',
+ safetyKeys: 'Nunca compartas frases semilla ni claves privadas. Mantén el trato en el chat de la app.',
+ safetyEscrow: 'Para envíos, lee primero las condiciones del depósito: el escrow Cashu es solo para la app nativa y no está verificado.',
+ safetyMore: 'Leer las normas del mercado',
+ offerTemplates: 'Notas rápidas',
+ offerDiscount: '¿Puedes hacer un 10 % de descuento?',
+ offerSwap: '¿Te plantearías un intercambio?',
+ offerPickup: 'Puedo recogerlo esta semana.',
+ offerShipping: '¿Puedes combinar el envío?',
+ },
+};
+export default marketplaceExtrasUi;
diff --git a/src/i18n/nl/drift.ts b/src/i18n/nl/drift.ts
index 9e44bbb..1d4d0d0 100644
--- a/src/i18n/nl/drift.ts
+++ b/src/i18n/nl/drift.ts
@@ -451,6 +451,22 @@ const drift = {
trust: "Vertrouwen",
noResults: "Geen resultaten voor ‘{{query}}’.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Opgeslagen zoekopdrachten",
+ saveSearch: "Zoekopdracht opslaan",
+ searchName: "Geef deze zoekopdracht een naam…",
+ deleteSearch: "Opgeslagen zoekopdracht verwijderen",
+ safetyTitle: "Veilig kopen & verkopen",
+ safetyMeet: "Spreek af op een openbare plek en bekijk de spullen voordat je betaalt.",
+ safetyKeys: "Deel nooit seed phrases of privésleutels. Houd de deal in de chat in de app.",
+ safetyEscrow: "Lees bij verzending eerst de escrowvoorwaarden: Cashu-escrow is alleen in de native app en niet geverifieerd.",
+ safetyMore: "Lees de marktplaatsrichtlijnen",
+ offerTemplates: "Snelle notities",
+ offerDiscount: "Kun je 10% korting geven?",
+ offerSwap: "Zou je een ruil overwegen?",
+ offerPickup: "Ik kan het deze week ophalen.",
+ offerShipping: "Kun je de verzendkosten bundelen?",
+ },
};
export default drift;
diff --git a/src/i18n/pl/drift.ts b/src/i18n/pl/drift.ts
index 16be67a..0936c33 100644
--- a/src/i18n/pl/drift.ts
+++ b/src/i18n/pl/drift.ts
@@ -451,6 +451,22 @@ const drift = {
trust: "Zaufanie",
noResults: "Brak wyników dla „{{query}}”.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Zapisane wyszukiwania",
+ saveSearch: "Zapisz wyszukiwanie",
+ searchName: "Nazwij to wyszukiwanie…",
+ deleteSearch: "Usuń zapisane wyszukiwanie",
+ safetyTitle: "Kupuj i sprzedawaj bezpiecznie",
+ safetyMeet: "Spotkajcie się w miejscu publicznym i obejrzyjcie sprzęt przed zapłatą.",
+ safetyKeys: "Nigdy nie udostępniaj fraz seed ani kluczy prywatnych. Prowadź transakcję w czacie w aplikacji.",
+ safetyEscrow: "W przypadku wysyłki najpierw przeczytaj warunki escrow: escrow Cashu działa tylko w aplikacji natywnej i nie jest zweryfikowany.",
+ safetyMore: "Przeczytaj zasady marketplace",
+ offerTemplates: "Szybkie notatki",
+ offerDiscount: "Czy możesz dać 10% zniżki?",
+ offerSwap: "Czy rozważysz zamianę?",
+ offerPickup: "Mogę odebrać w tym tygodniu.",
+ offerShipping: "Czy możesz połączyć wysyłkę?",
+ },
};
export default drift;
diff --git a/src/i18n/pt/drift.ts b/src/i18n/pt/drift.ts
index 5505fb0..d7e6684 100644
--- a/src/i18n/pt/drift.ts
+++ b/src/i18n/pt/drift.ts
@@ -453,6 +453,22 @@ const drift = {
trust: "Confiança",
noResults: "Nenhum resultado para “{{query}}”.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Pesquisas salvas",
+ saveSearch: "Salvar pesquisa",
+ searchName: "Dê um nome a esta pesquisa…",
+ deleteSearch: "Excluir pesquisa salva",
+ safetyTitle: "Compre e venda com segurança",
+ safetyMeet: "Encontrem-se em um local público e inspecionem o equipamento antes de pagar.",
+ safetyKeys: "Nunca compartilhe frases seed ou chaves privadas. Mantenha a negociação no chat do app.",
+ safetyEscrow: "Para envios, leia primeiro os termos do escrow: o escrow Cashu é apenas para o app nativo e não é verificado.",
+ safetyMore: "Ler as diretrizes do marketplace",
+ offerTemplates: "Notas rápidas",
+ offerDiscount: "Você consegue 10% de desconto?",
+ offerSwap: "Você consideraria uma troca?",
+ offerPickup: "Consigo retirar esta semana.",
+ offerShipping: "Você consegue agrupar o frete?",
+ },
};
export default drift;
diff --git a/src/i18n/ro/drift.ts b/src/i18n/ro/drift.ts
index e358391..07c4fc2 100644
--- a/src/i18n/ro/drift.ts
+++ b/src/i18n/ro/drift.ts
@@ -451,6 +451,22 @@ const drift = {
trust: "Încredere",
noResults: "Niciun rezultat pentru „{{query}}”.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Căutări salvate",
+ saveSearch: "Salvează căutarea",
+ searchName: "Denumește această căutare…",
+ deleteSearch: "Șterge căutarea salvată",
+ safetyTitle: "Cumpără și vinde în siguranță",
+ safetyMeet: "Întâlniți-vă într-un loc public și verificați echipamentul înainte de plată.",
+ safetyKeys: "Nu partaja niciodată fraze seed sau chei private. Ține tranzacția în chatul din aplicație.",
+ safetyEscrow: "Pentru livrări, citește mai întâi termenii escrow: escrow-ul Cashu este doar pentru aplicația nativă și nu este verificat.",
+ safetyMore: "Citește regulile marketplace-ului",
+ offerTemplates: "Note rapide",
+ offerDiscount: "Poți face 10% reducere?",
+ offerSwap: "Ai lua în calcul un schimb?",
+ offerPickup: "Pot ridica personal săptămâna asta.",
+ offerShipping: "Poți combina transportul?",
+ },
};
export default drift;
diff --git a/src/i18n/ru/drift.ts b/src/i18n/ru/drift.ts
index 9b5756a..b5274c5 100644
--- a/src/i18n/ru/drift.ts
+++ b/src/i18n/ru/drift.ts
@@ -455,6 +455,22 @@ const drift = {
trust: "Доверие",
noResults: "Нет результатов по запросу «{{query}}».",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Сохранённые поиски",
+ saveSearch: "Сохранить поиск",
+ searchName: "Назовите этот поиск…",
+ deleteSearch: "Удалить сохранённый поиск",
+ safetyTitle: "Покупайте и продавайте безопасно",
+ safetyMeet: "Встречайтесь в общественном месте и осматривайте снаряжение до оплаты.",
+ safetyKeys: "Никогда не делитесь seed-фразами или приватными ключами. Ведите сделку в чате приложения.",
+ safetyEscrow: "При доставке сначала прочитайте условия эскроу: Cashu-эскроу работает только в нативном приложении и не проверен.",
+ safetyMore: "Прочитать правила маркетплейса",
+ offerTemplates: "Быстрые заметки",
+ offerDiscount: "Можете сделать скидку 10%?",
+ offerSwap: "Рассмотрите обмен?",
+ offerPickup: "Могу забрать на этой неделе.",
+ offerShipping: "Можете объединить доставку?",
+ },
};
export default drift;
diff --git a/src/i18n/sv/drift.ts b/src/i18n/sv/drift.ts
index 0ec15c0..7364ec9 100644
--- a/src/i18n/sv/drift.ts
+++ b/src/i18n/sv/drift.ts
@@ -455,6 +455,22 @@ const drift = {
trust: "Förtroende",
noResults: "Inga resultat för ”{{query}}”.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Sparade sökningar",
+ saveSearch: "Spara sökning",
+ searchName: "Namnge den här sökningen…",
+ deleteSearch: "Ta bort sparad sökning",
+ safetyTitle: "Köp och sälj säkert",
+ safetyMeet: "Mötas på en offentlig plats och granska utrustningen innan ni betalar.",
+ safetyKeys: "Dela aldrig seed-fraser eller privata nycklar. Håll affären i appens chatt.",
+ safetyEscrow: "För skickade affärer, läs escrow-villkoren först: Cashu-escrow finns bara i den inbyggda appen och är overifierad.",
+ safetyMore: "Läs marknadsplatsens riktlinjer",
+ offerTemplates: "Snabba anteckningar",
+ offerDiscount: "Kan du ge 10 % rabatt?",
+ offerSwap: "Skulle du överväga ett byte?",
+ offerPickup: "Jag kan hämta den här veckan.",
+ offerShipping: "Kan du samla frakten?",
+ },
};
export default drift;
diff --git a/src/i18n/th/drift.ts b/src/i18n/th/drift.ts
index 3b6ae5d..265d335 100644
--- a/src/i18n/th/drift.ts
+++ b/src/i18n/th/drift.ts
@@ -447,6 +447,22 @@ const driftStrings = {
trust: "ความน่าเชื่อถือ",
noResults: "ไม่พบผลลัพธ์สำหรับ “{{query}}”",
},
+ marketplaceExtrasUi: {
+ savedSearches: "การค้นหาที่บันทึกไว้",
+ saveSearch: "บันทึกการค้นหา",
+ searchName: "ตั้งชื่อการค้นหานี้…",
+ deleteSearch: "ลบการค้นหาที่บันทึกไว้",
+ safetyTitle: "ซื้อและขายอย่างปลอดภัย",
+ safetyMeet: "นัดพบในที่สาธารณะและตรวจสอบอุปกรณ์ก่อนชำระเงิน",
+ safetyKeys: "อย่าแชร์วลี seed หรือคีย์ส่วนตัวเด็ดขาด ให้คุยดีลในแชทของแอป",
+ safetyEscrow: "สำหรับการจัดส่ง โปรดอ่านเงื่อนไข escrow ก่อน: escrow ของ Cashu ใช้ได้เฉพาะแอปเนทีฟและยังไม่ผ่านการตรวจสอบ",
+ safetyMore: "อ่านแนวทางของตลาด",
+ offerTemplates: "โน้ตด่วน",
+ offerDiscount: "ลด 10% ได้ไหม?",
+ offerSwap: "สนใจแลกเปลี่ยนไหม?",
+ offerPickup: "ฉันรับเองได้ภายในสัปดาห์นี้",
+ offerShipping: "รวมค่าส่งได้ไหม?",
+ },
};
export default driftStrings;
diff --git a/src/i18n/tr/drift.ts b/src/i18n/tr/drift.ts
index c6de72f..0a7b71f 100644
--- a/src/i18n/tr/drift.ts
+++ b/src/i18n/tr/drift.ts
@@ -447,6 +447,22 @@ const driftStrings = {
trust: "Güven",
noResults: "“{{query}}” için sonuç yok.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Kayıtlı aramalar",
+ saveSearch: "Aramayı kaydet",
+ searchName: "Bu aramayı adlandır…",
+ deleteSearch: "Kayıtlı aramayı sil",
+ safetyTitle: "Güvenle al ve sat",
+ safetyMeet: "Herkese açık bir yerde buluşun ve ödeme yapmadan önce ekipmanı inceleyin.",
+ safetyKeys: "Seed ifadelerini veya özel anahtarları asla paylaşmayın. Anlaşmayı uygulama içi sohbette sürdürün.",
+ safetyEscrow: "Kargolu anlaşmalarda önce escrow koşullarını okuyun: Cashu escrow yalnızca yerel uygulamada çalışır ve doğrulanmamıştır.",
+ safetyMore: "Pazar yeri kurallarını oku",
+ offerTemplates: "Hızlı notlar",
+ offerDiscount: "%10 indirim yapabilir misin?",
+ offerSwap: "Takas düşünür müsün?",
+ offerPickup: "Bu hafta kendim alabilirim.",
+ offerShipping: "Kargo ücretini birleştirebilir misin?",
+ },
};
export default driftStrings;
diff --git a/src/i18n/uk/drift.ts b/src/i18n/uk/drift.ts
index 0d67f7d..9ac16ed 100644
--- a/src/i18n/uk/drift.ts
+++ b/src/i18n/uk/drift.ts
@@ -455,6 +455,22 @@ const drift = {
trust: "Довіра",
noResults: "Немає результатів для «{{query}}».",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Збережені пошуки",
+ saveSearch: "Зберегти пошук",
+ searchName: "Назвіть цей пошук…",
+ deleteSearch: "Видалити збережений пошук",
+ safetyTitle: "Купуйте й продавайте безпечно",
+ safetyMeet: "Зустрічайтеся в публічному місці та огляньте спорядження до оплати.",
+ safetyKeys: "Ніколи не діліться seed-фразами чи приватними ключами. Тримайте угоду в чаті застосунку.",
+ safetyEscrow: "Для доставки спершу прочитайте умови ескроу: Cashu-ескроу працює лише в нативному застосунку й не перевірений.",
+ safetyMore: "Прочитати правила маркетплейсу",
+ offerTemplates: "Швидкі нотатки",
+ offerDiscount: "Можете зробити знижку 10%?",
+ offerSwap: "Розглянете обмін?",
+ offerPickup: "Можу забрати цього тижня.",
+ offerShipping: "Можете об'єднати доставку?",
+ },
};
export default drift;
diff --git a/src/i18n/vi/drift.ts b/src/i18n/vi/drift.ts
index a5eda94..da9c09e 100644
--- a/src/i18n/vi/drift.ts
+++ b/src/i18n/vi/drift.ts
@@ -447,6 +447,22 @@ const driftStrings = {
trust: "Tin cậy",
noResults: "Không có kết quả cho “{{query}}”.",
},
+ marketplaceExtrasUi: {
+ savedSearches: "Tìm kiếm đã lưu",
+ saveSearch: "Lưu tìm kiếm",
+ searchName: "Đặt tên cho tìm kiếm này…",
+ deleteSearch: "Xóa tìm kiếm đã lưu",
+ safetyTitle: "Mua bán an toàn",
+ safetyMeet: "Gặp nhau ở nơi công cộng và kiểm tra đồ trước khi trả tiền.",
+ safetyKeys: "Không bao giờ chia sẻ cụm seed hay khóa riêng tư. Giữ giao dịch trong chat của ứng dụng.",
+ safetyEscrow: "Với đơn gửi hàng, hãy đọc điều kiện escrow trước: escrow Cashu chỉ dùng cho ứng dụng gốc và chưa được xác minh.",
+ safetyMore: "Đọc hướng dẫn chợ",
+ offerTemplates: "Ghi chú nhanh",
+ offerDiscount: "Bạn giảm 10% được không?",
+ offerSwap: "Bạn có cân nhắc đổi đồ không?",
+ offerPickup: "Tôi có thể tự lấy trong tuần này.",
+ offerShipping: "Bạn gộp phí ship được không?",
+ },
};
export default driftStrings;
diff --git a/src/i18n/zh-CN/drift.ts b/src/i18n/zh-CN/drift.ts
index 27a446a..3bccc7b 100644
--- a/src/i18n/zh-CN/drift.ts
+++ b/src/i18n/zh-CN/drift.ts
@@ -463,6 +463,22 @@ const drift: Dict = {
trust: "信任",
noResults: "未找到“{{query}}”的结果。",
},
+ marketplaceExtrasUi: {
+ savedSearches: "已保存的搜索",
+ saveSearch: "保存搜索",
+ searchName: "为此搜索命名…",
+ deleteSearch: "删除已保存的搜索",
+ safetyTitle: "安全买卖",
+ safetyMeet: "在公共场所见面,付款前先检查装备。",
+ safetyKeys: "切勿分享助记词或私钥。交易请留在应用内聊天中。",
+ safetyEscrow: "寄送交易请先阅读托管条款:Cashu 托管仅限原生应用,且尚未验证。",
+ safetyMore: "阅读市场指南",
+ offerTemplates: "快捷留言",
+ offerDiscount: "能优惠 10% 吗?",
+ offerSwap: "可以考虑交换吗?",
+ offerPickup: "我这周可以自取。",
+ offerShipping: "可以合并运费吗?",
+ },
};
export default drift;
diff --git a/src/i18n/zh-TW/drift.ts b/src/i18n/zh-TW/drift.ts
index 03a97d3..2de7761 100644
--- a/src/i18n/zh-TW/drift.ts
+++ b/src/i18n/zh-TW/drift.ts
@@ -463,6 +463,22 @@ const drift: Dict = {
trust: "信任",
noResults: "找不到「{{query}}」的結果。",
},
+ marketplaceExtrasUi: {
+ savedSearches: "已儲存的搜尋",
+ saveSearch: "儲存搜尋",
+ searchName: "為此搜尋命名…",
+ deleteSearch: "刪除已儲存的搜尋",
+ safetyTitle: "安心買賣",
+ safetyMeet: "在公共場所見面,付款前先檢查裝備。",
+ safetyKeys: "切勿分享助記詞或私鑰。交易請留在應用程式內聊天中。",
+ safetyEscrow: "寄送交易請先閱讀託管條款:Cashu 託管僅限原生應用程式,且尚未驗證。",
+ safetyMore: "閱讀市場指南",
+ offerTemplates: "快速留言",
+ offerDiscount: "能優惠 10% 嗎?",
+ offerSwap: "可以考慮交換嗎?",
+ offerPickup: "我這週可以自取。",
+ offerShipping: "可以合併運費嗎?",
+ },
};
export default drift;
diff --git a/src/pages/GearSwapPage.tsx b/src/pages/GearSwapPage.tsx
index 39a6bfe..38fa9d6 100644
--- a/src/pages/GearSwapPage.tsx
+++ b/src/pages/GearSwapPage.tsx
@@ -1,4 +1,4 @@
-import { useState, useMemo } from 'react';
+import { useMemo, useState } from 'react';
import { useSeoMeta } from '@unhead/react';
import { Link } from 'react-router-dom';
import { PageHeader } from '@/components/PageHeader';
@@ -6,6 +6,8 @@ import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Input } from '@/components/ui/input';
+import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
+import { Label } from '@/components/ui/label';
import { Skeleton } from '@/components/ui/skeleton';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DropdownMenu, DropdownMenuContent, DropdownMenuCheckboxItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
@@ -20,12 +22,25 @@ import { GEAR_CATEGORIES } from '@/lib/types';
import { GEAR_CATEGORY_KEYS } from '@/lib/labelKeys';
import { getLastLocation } from '@/lib/lastLocation';
import { itemDistanceKm } from '@/lib/sortOptions';
-import { ShoppingCart, Plus, Search, Filter, ArrowUpDown, Users, ShieldCheck, UserCheck, AlertCircle, MapPin } from 'lucide-react';
+import { ShoppingCart, Plus, Search, Filter, ArrowUpDown, Users, ShieldCheck, UserCheck, AlertCircle, MapPin, Bookmark, X } from 'lucide-react';
import { useTranslation } from '@/contexts/language';
+import { useLocalStorage } from '@/hooks/useLocalStorage';
type SortOption = 'newest' | 'price_low' | 'price_high' | 'trust' | 'distance';
type TrustFilter = 'all' | 'verified' | 'trusted' | 'following';
+interface SavedSearch {
+ id: string;
+ name: string;
+ query: string;
+ category: string;
+ sort: SortOption;
+ fulfilment: 'all' | 'pickup' | 'ships';
+ trust: TrustFilter;
+ wtb: boolean;
+ selling: boolean;
+}
+
export default function GearSwapPage() {
const { t } = useTranslation();
useSeoMeta({
@@ -45,6 +60,9 @@ export default function GearSwapPage() {
const [trustFilter, setTrustFilter] = useState
('all');
const [showOnlyWTB, setShowOnlyWTB] = useState(false);
const [showOnlySelling, setShowOnlySelling] = useState(false);
+ const [savedSearches, setSavedSearches] = useLocalStorage('skatespots:gear-saved-searches', []);
+ const [saveSearchOpen, setSaveSearchOpen] = useState(false);
+ const [saveSearchName, setSaveSearchName] = useState('');
// Get unique seller pubkeys for batch queries
const sellerPubkeys = useMemo(() => {
@@ -182,6 +200,41 @@ export default function GearSwapPage() {
return filtered;
}, [items, searchQuery, selectedCategory, sortBy, trustFilter, showOnlyWTB, showOnlySelling, fulfilmentFilter, trustScores, followingSet]);
+ const applySavedSearch = (saved: SavedSearch) => {
+ setSearchQuery(saved.query);
+ setSelectedCategory(saved.category);
+ setSortBy(saved.sort);
+ setFulfilmentFilter(saved.fulfilment);
+ setTrustFilter(saved.trust);
+ setShowOnlyWTB(saved.wtb);
+ setShowOnlySelling(saved.selling);
+ };
+
+ const saveCurrentSearch = () => {
+ const name = saveSearchName.trim();
+ if (!name) return;
+ const saved: SavedSearch = {
+ id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
+ name,
+ query: searchQuery,
+ category: selectedCategory,
+ sort: sortBy,
+ fulfilment: fulfilmentFilter,
+ trust: trustFilter,
+ wtb: showOnlyWTB,
+ selling: showOnlySelling,
+ };
+ setSavedSearches((current) => [saved, ...current.filter((item) => item.name !== name)].slice(0, 12));
+ setSaveSearchOpen(false);
+ setSaveSearchName('');
+ };
+
+ const safetyItems = [
+ t('marketplaceExtrasUi.safetyMeet'),
+ t('marketplaceExtrasUi.safetyKeys'),
+ t('marketplaceExtrasUi.safetyEscrow'),
+ ];
+
const categoryOptions = [
{ value: 'all', label: t('marketUi.gearSwap.allCategories') },
...Object.entries(GEAR_CATEGORIES).map(([key]) => ({
@@ -212,6 +265,22 @@ export default function GearSwapPage() {
}
/>
+
+
+
+ {t('marketplaceExtrasUi.safetyTitle')}
+ {t('common.learnMore')}
+
+
+ {safetyItems.map((item) => (
+ - •{item}
+ ))}
+
+
+ {t('marketplaceExtrasUi.safetyMore')}
+
+
+
{/* Search & Filters */}
@@ -375,14 +444,54 @@ export default function GearSwapPage() {
+ {savedSearches.length > 0 && (
+
+
+ {t('marketplaceExtrasUi.savedSearches')}
+
+ {savedSearches.map((saved) => (
+
+
+
+
+ ))}
+
+ )}
+
{/* Results Count */}
{!isLoading && (
-
+
{filteredItems.length === 1
? t('marketUi.gearSwap.listingFound', { count: filteredItems.length })
: t('marketUi.gearSwap.listingsFound', { count: filteredItems.length })}
+
)}
@@ -472,6 +581,38 @@ export default function GearSwapPage() {
)}
+
+