diff --git a/src/components/CraftProfileForm.tsx b/src/components/CraftProfileForm.tsx index cfb9da9..ceb4ea5 100644 --- a/src/components/CraftProfileForm.tsx +++ b/src/components/CraftProfileForm.tsx @@ -16,6 +16,7 @@ import { useUploadFile } from '@/hooks/useUploadFile'; import { useToast } from '@/hooks/useToast'; import { LoginArea } from '@/components/auth/LoginArea'; import { NofferField } from '@/components/NofferField'; +import { PaymentReadinessNote } from '@/components/PaymentReadinessNote'; import { EntityTypeField } from '@/components/EntityTypeField'; import { CrewLinkField } from '@/components/CrewLinkField'; import { LabProUpgrade } from '@/components/LabProUpgrade'; @@ -445,9 +446,13 @@ export function CraftProfileForm({ config }: { config: CraftFormConfig }) { - {/* CLINK tip jar */} + {/* Payments — Lightning address (from profile) + optional CLINK code */} - + + + diff --git a/src/components/PaymentReadinessNote.tsx b/src/components/PaymentReadinessNote.tsx new file mode 100644 index 0000000..a649340 --- /dev/null +++ b/src/components/PaymentReadinessNote.tsx @@ -0,0 +1,69 @@ +import { Link } from 'react-router-dom'; +import { Zap, CheckCircle2, AlertCircle } from 'lucide-react'; +import { useCurrentUser } from '@/hooks/useCurrentUser'; +import { useAuthor } from '@/hooks/useAuthor'; +import { isValidLightningAddress, isValidSilentPayment } from '@/lib/types'; + +/** + * Payment-readiness note for provider / Lab / crew forms. + * + * Lightning address (lud16) and Bitcoin Silent Payment live on the user's Nostr + * profile (kind 0), NOT on each individual Lab event — so a single source of + * truth never goes stale across a person's many profiles. This note simply + * tells a provider whether that source is set up, and links them to Edit Profile + * if it isn't, so they always have a clear path to "get paid". + */ +export function PaymentReadinessNote() { + const { user } = useCurrentUser(); + const author = useAuthor(user?.pubkey || ''); + const metadata = author.data?.metadata; + + const lud16 = metadata?.lud16; + const hasLightning = isValidLightningAddress(lud16) || !!metadata?.lud06; + // Silent payment lives in a custom kind-0 field the app reads elsewhere. + const rawSp = (metadata as Record | undefined)?.bitcoin_silent_payment; + const hasSilentPayment = typeof rawSp === 'string' && isValidSilentPayment(rawSp); + + if (!user) return null; + + const ready = hasLightning; + + return ( +
+
+ + + {ready ? 'You can get paid' : 'Set up payments to get paid'} + +
+ + {ready ? ( +

+ + + Your Lightning address{lud16 ? <> ({lud16}) : ''} is on your + profile — people can zap and pay you directly. + {hasSilentPayment && ' A Bitcoin Silent Payment address is set too.'} + +

+ ) : ( +

+ + + Add a Lightning address (and optionally a Bitcoin Silent Payment address) to your{' '} + + Nostr profile + {' '} + so skaters can pay you. It's set once and works across every profile you have here. + +

+ )} +
+ ); +} diff --git a/src/lib/types.ts b/src/lib/types.ts index a4f5f75..361ab56 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1684,7 +1684,6 @@ export const JUDGE_FORMAT_LABELS: Record = { mini_ramp: 'Mini Ramp', park: 'Park', street: 'Street', - downhill: 'Downhill / Longboard', freestyle: 'Freestyle', world_tour: 'World Destruction Tour', am_series: 'Am Series / Qualifiers', diff --git a/src/pages/BecomeBuilderPage.tsx b/src/pages/BecomeBuilderPage.tsx index f69c820..1856d04 100644 --- a/src/pages/BecomeBuilderPage.tsx +++ b/src/pages/BecomeBuilderPage.tsx @@ -20,6 +20,7 @@ import { WalletModal } from '@/components/WalletModal'; import { LoginArea } from '@/components/auth/LoginArea'; import { SpotPicker } from '@/components/SpotPicker'; import { NofferField } from '@/components/NofferField'; +import { PaymentReadinessNote } from '@/components/PaymentReadinessNote'; import { EntityTypeField } from '@/components/EntityTypeField'; import { CrewLinkField } from '@/components/CrewLinkField'; import { @@ -486,6 +487,7 @@ export default function BecomeBuilderPage() { setSocial(e.target.value)} className="bg-gray-800 border-gray-700" /> +

💬 Clients can message you directly through SkateSpots' encrypted messaging

diff --git a/src/pages/BecomeCoachPage.tsx b/src/pages/BecomeCoachPage.tsx index 008774e..73f4299 100644 --- a/src/pages/BecomeCoachPage.tsx +++ b/src/pages/BecomeCoachPage.tsx @@ -19,6 +19,7 @@ import { WalletModal } from '@/components/WalletModal'; import { LoginArea } from '@/components/auth/LoginArea'; import { SpotPicker } from '@/components/SpotPicker'; import { NofferField } from '@/components/NofferField'; +import { PaymentReadinessNote } from '@/components/PaymentReadinessNote'; import { EntityTypeField } from '@/components/EntityTypeField'; import { CrewLinkField } from '@/components/CrewLinkField'; import { SKATE_COACH_KIND, SKATE_SPOT_KIND, COACH_SKILL_LABELS, COACH_SKILL_DESCRIPTIONS, isValidNoffer, type EntityType } from '@/lib/types'; @@ -401,6 +402,7 @@ export default function BecomeCoachPage() {
+
diff --git a/src/pages/BecomeEditorPage.tsx b/src/pages/BecomeEditorPage.tsx index acb51cb..2bf3653 100644 --- a/src/pages/BecomeEditorPage.tsx +++ b/src/pages/BecomeEditorPage.tsx @@ -18,6 +18,7 @@ import { useWallet } from '@/hooks/useWallet'; import { WalletModal } from '@/components/WalletModal'; import { LoginArea } from '@/components/auth/LoginArea'; import { NofferField } from '@/components/NofferField'; +import { PaymentReadinessNote } from '@/components/PaymentReadinessNote'; import { SKATE_EDITOR_KIND, EDITOR_SERVICE_LABELS, @@ -427,6 +428,7 @@ export default function BecomeEditorPage() { setWebsite(e.target.value)} className="bg-gray-800 border-gray-700" /> setSocial(e.target.value)} className="bg-gray-800 border-gray-700" />
+ diff --git a/src/pages/BecomeFilmerPage.tsx b/src/pages/BecomeFilmerPage.tsx index 47065e8..d930647 100644 --- a/src/pages/BecomeFilmerPage.tsx +++ b/src/pages/BecomeFilmerPage.tsx @@ -19,6 +19,7 @@ import { WalletModal } from '@/components/WalletModal'; import { LoginArea } from '@/components/auth/LoginArea'; import { SpotPicker } from '@/components/SpotPicker'; import { NofferField } from '@/components/NofferField'; +import { PaymentReadinessNote } from '@/components/PaymentReadinessNote'; import { EntityTypeField } from '@/components/EntityTypeField'; import { CrewLinkField } from '@/components/CrewLinkField'; import { SKATE_FILMER_KIND, SKATE_SPOT_KIND, FILMING_SERVICE_LABELS, FILMING_SERVICE_DESCRIPTIONS, FILMING_SKILL_LABELS, FILMING_SKILL_DESCRIPTIONS, isValidNoffer, type EntityType } from '@/lib/types'; @@ -459,6 +460,7 @@ export default function BecomeFilmerPage() { +
diff --git a/src/pages/BecomePhotographerPage.tsx b/src/pages/BecomePhotographerPage.tsx index 8389cf4..f0aeaf8 100644 --- a/src/pages/BecomePhotographerPage.tsx +++ b/src/pages/BecomePhotographerPage.tsx @@ -19,6 +19,7 @@ import { WalletModal } from '@/components/WalletModal'; import { LoginArea } from '@/components/auth/LoginArea'; import { SpotPicker } from '@/components/SpotPicker'; import { NofferField } from '@/components/NofferField'; +import { PaymentReadinessNote } from '@/components/PaymentReadinessNote'; import { EntityTypeField } from '@/components/EntityTypeField'; import { CrewLinkField } from '@/components/CrewLinkField'; import type { EntityType } from '@/lib/types'; @@ -508,6 +509,7 @@ export default function BecomePhotographerPage() { setSocial(e.target.value)} className="bg-gray-800 border-gray-700" />
+

💬 Riders can message you directly through SkateSpots' encrypted messaging