From 3f35a6f3a44fe4c65b7caa855b2d7c7cd749ab1a Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Thu, 29 Oct 2026 20:57:43 +0700 Subject: [PATCH] feat: sponsorship opt-in and Bitcoin grantmaker inquiry --- src/components/EditProfileForm.tsx | 52 ++++++++++++- src/i18n/ca/batch3.ts | 4 + src/i18n/ca/batch6.ts | 17 ++++ src/i18n/cs/batch3.ts | 4 + src/i18n/cs/batch4.ts | 17 ++++ src/i18n/de/batch3.ts | 4 + src/i18n/de/batch4.ts | 17 ++++ src/i18n/el/batch3.ts | 4 + src/i18n/el/batch4.ts | 17 ++++ src/i18n/en.ts | 21 +++++ src/i18n/es.ts | 21 +++++ src/i18n/eu/batch3.ts | 4 + src/i18n/eu/batch6.ts | 17 ++++ src/i18n/fr/batch3.ts | 4 + src/i18n/fr/batch4.ts | 17 ++++ src/i18n/gl/batch3.ts | 4 + src/i18n/gl/batch6.ts | 17 ++++ src/i18n/hi/batch3.ts | 4 + src/i18n/hi/batch6.ts | 17 ++++ src/i18n/id/batch3.ts | 4 + src/i18n/id/batch4.ts | 17 ++++ src/i18n/it/batch3.ts | 4 + src/i18n/it/batch4.ts | 17 ++++ src/i18n/ja/batch6.ts | 4 + src/i18n/ja/batch7.ts | 17 ++++ src/i18n/ko/batch3.ts | 4 + src/i18n/ko/batch4.ts | 17 ++++ src/i18n/nl/batch3.ts | 4 + src/i18n/nl/batch4.ts | 17 ++++ src/i18n/pl/batch3.ts | 4 + src/i18n/pl/batch4.ts | 17 ++++ src/i18n/pt/batch3.ts | 4 + src/i18n/pt/batch4.ts | 17 ++++ src/i18n/ro/batch3.ts | 4 + src/i18n/ro/batch4.ts | 17 ++++ src/i18n/ru/batch3.ts | 4 + src/i18n/ru/batch4.ts | 17 ++++ src/i18n/sv/batch3.ts | 4 + src/i18n/sv/batch4.ts | 17 ++++ src/i18n/th/batch8.ts | 4 + src/i18n/th/batch9.ts | 17 ++++ src/i18n/tr/batch3.ts | 4 + src/i18n/tr/batch4.ts | 17 ++++ src/i18n/uk/batch3.ts | 4 + src/i18n/uk/batch4.ts | 17 ++++ src/i18n/vi/batch3.ts | 4 + src/i18n/vi/batch4.ts | 17 ++++ src/i18n/zh-CN/batch3.ts | 4 + src/i18n/zh-CN/batch4.ts | 17 ++++ src/i18n/zh-TW/batch3.ts | 4 + src/i18n/zh-TW/batch4.ts | 17 ++++ src/pages/NIP19Page.tsx | 27 +++++-- src/pages/SupportersPage.tsx | 121 ++++++++++++++++++++++++++++- 53 files changed, 736 insertions(+), 10 deletions(-) diff --git a/src/components/EditProfileForm.tsx b/src/components/EditProfileForm.tsx index fe532b9..3b54f61 100644 --- a/src/components/EditProfileForm.tsx +++ b/src/components/EditProfileForm.tsx @@ -20,7 +20,7 @@ import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Switch } from '@/components/ui/switch'; import { Label } from '@/components/ui/label'; -import { Loader2, Upload, Zap, ShieldCheck, AlertCircle, Bitcoin, Award, MessageSquareLock, UserRound, X, Plus, Bot, BadgeCheck, HelpCircle, Server, AtSign } from 'lucide-react'; +import { Loader2, Upload, Zap, ShieldCheck, AlertCircle, Bitcoin, Award, MessageSquareLock, UserRound, Handshake, X, Plus, Bot, BadgeCheck, HelpCircle, Server, AtSign } from 'lucide-react'; import { NSchema as n, type NostrMetadata } from '@nostrify/nostrify'; import { useQueryClient } from '@tanstack/react-query'; import { useUploadFile } from '@/hooks/useUploadFile'; @@ -72,6 +72,8 @@ export const EditProfileForm: React.FC = () => { // pointer formats as Settings → Coordinator (nprofile / cordn.net link / // npub / hex) as well as an http(s) URL — this is the discovery field. const [cordn, setCordn] = useState(''); + const [openToSponsorships, setOpenToSponsorships] = useState(false); + const [sponsorNote, setSponsorNote] = useState(''); // Extra personal NIP-05 handles — stored in a separate kind-30078 record so // another client re-saving the profile can't drop them. @@ -131,6 +133,8 @@ export const EditProfileForm: React.FC = () => { ); } if (typeof raw.cordn === 'string') setCordn(raw.cordn); + setOpenToSponsorships(raw.sponsorships_open === true); + if (typeof raw.sponsorships_note === 'string') setSponsorNote(raw.sponsorships_note); } }, [metadata, form]); @@ -252,6 +256,17 @@ export const EditProfileForm: React.FC = () => { // Retire the legacy field now that badges supersede it. delete data.sponsors; + // Sponsorship opt-in (custom kind-0 fields). The profile only claims + // this when the skater explicitly turned it on. + if (openToSponsorships) { + data.sponsorships_open = true; + if (sponsorNote.trim()) data.sponsorships_note = sponsorNote.trim(); + else delete data.sponsorships_note; + } else { + delete data.sponsorships_open; + delete data.sponsorships_note; + } + // Cordn contact link (custom field). if (cordnTrimmed) { // Normalise a bare pointer (nprofile/npub/hex) to Cordn's canonical @@ -402,6 +417,41 @@ export const EditProfileForm: React.FC = () => { )} /> + {/* Sponsorship opt-in — explicit consent, never inferred from activity. */} +
+
+
+ +

+ {t('settingsUi.editProfile.openToSponsorshipsHint')} +

+
+ +
+ {openToSponsorships && ( +
+ +