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() {
)}
+ + + + + + {t('marketplaceExtrasUi.saveSearch')} + + +
+ + setSaveSearchName(event.target.value)} + onKeyDown={(event) => { if (event.key === 'Enter') saveCurrentSearch(); }} + placeholder={t('marketplaceExtrasUi.searchName')} + className="h-11 border-gray-700 bg-gray-900 text-white" + autoFocus + /> +
+ + +
+
+
+
); }