diff --git a/src/pages/ContactsPage.tsx b/src/pages/ContactsPage.tsx index 4e2bb6f..f4ec28f 100644 --- a/src/pages/ContactsPage.tsx +++ b/src/pages/ContactsPage.tsx @@ -72,7 +72,7 @@ function ContactRow({
{zapTarget && } - + diff --git a/src/pages/ConversationPage.tsx b/src/pages/ConversationPage.tsx index b50e29c..0709198 100644 --- a/src/pages/ConversationPage.tsx +++ b/src/pages/ConversationPage.tsx @@ -3,12 +3,14 @@ import { useParams, Link, useSearchParams } from 'react-router-dom'; import { useSeoMeta } from '@unhead/react'; import { nip19 } from 'nostr-tools'; import { Layout } from '@/components/Layout'; +import { LoginArea } from '@/components/auth/LoginArea'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; import { Skeleton } from '@/components/ui/skeleton'; import { useCurrentUser } from '@/hooks/useCurrentUser'; +import { useToast } from '@/hooks/useToast'; import { useNostrLogin } from '@nostrify/react/login'; import { hasNip44 as checkNip44 } from '@/lib/signerCapabilities'; import { useConversation, useSendDirectMessage, type DirectMessage } from '@/hooks/useDirectMessages'; @@ -70,6 +72,7 @@ export default function ConversationPage() { const { npub } = useParams<{ npub: string }>(); const [searchParams] = useSearchParams(); const { user } = useCurrentUser(); + const { toast } = useToast(); const { logins } = useNostrLogin(); const messagesEndRef = useRef(null); @@ -132,6 +135,15 @@ export default function ConversationPage() { onSuccess: () => { setNewMessage(''); }, + onError: (error) => { + // Without this a failed send is silent (common with interactive + // signers / relay hiccups) and the draft just sits there. + toast({ + title: 'Message failed to send', + description: error instanceof Error ? error.message : 'Please try again in a moment.', + variant: 'destructive', + }); + }, } ); }; @@ -157,6 +169,9 @@ export default function ConversationPage() {

Log in to view messages

+
+ +
diff --git a/src/pages/DirectMessagesPage.tsx b/src/pages/DirectMessagesPage.tsx index 909ab63..4075160 100644 --- a/src/pages/DirectMessagesPage.tsx +++ b/src/pages/DirectMessagesPage.tsx @@ -3,6 +3,7 @@ import { Link } from 'react-router-dom'; import { useSeoMeta } from '@unhead/react'; import { nip19 } from 'nostr-tools'; import { Layout } from '@/components/Layout'; +import { LoginArea } from '@/components/auth/LoginArea'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; @@ -179,6 +180,9 @@ export default function DirectMessagesPage() {

Private, encrypted messaging with skaters in the community

+
+ +
diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 070fc5a..5c0e56b 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -1156,7 +1156,15 @@ export default function SettingsPage() { const [searchParams] = useSearchParams(); // Allow deep-linking into a specific section via ?section=profile etc. - const initialSection = (searchParams.get('section') as Section) ?? null; + // Only sections that actually render are accepted; anything else (e.g. a + // stale bookmark to ?section=language) falls back to the menu rather than a + // blank screen with no way back. + const RENDERABLE_SECTIONS: Section[] = [ + 'profile', 'security', 'nip05', 'mydata', 'relays', 'crewnetwork', 'appearance', 'wallet', 'advanced', + ]; + const requestedSection = searchParams.get('section') as Section; + const initialSection = + requestedSection && RENDERABLE_SECTIONS.includes(requestedSection) ? requestedSection : null; const [section, setSection] = useState
(initialSection); const handleNavigate = (s: Section) => setSection(s); diff --git a/src/pages/SpotDetailPage.tsx b/src/pages/SpotDetailPage.tsx index 3be657e..ab96d29 100644 --- a/src/pages/SpotDetailPage.tsx +++ b/src/pages/SpotDetailPage.tsx @@ -510,18 +510,25 @@ export default function SpotDetailPage() { If you own or manage this shop, you can claim it to verify ownership and manage the listing.

{hasNip05 ? ( - +
+

+ To claim this shop, add a NIP-05 identifier that matches the shop's website domain. +

+ + + +
) : (

⚠️ NIP-05 verification required to claim shops

- + - +
)} diff --git a/src/pages/TourDetailPage.tsx b/src/pages/TourDetailPage.tsx index 4abac3b..9c24a4e 100644 --- a/src/pages/TourDetailPage.tsx +++ b/src/pages/TourDetailPage.tsx @@ -54,9 +54,10 @@ export default function TourDetailPage() { const handleBookTour = () => { if (!tour) return; - // Navigate to messages/DM with the guide - // For now, navigate to messages page - in future can open DM composer - navigate(`/messages?to=${tour.pubkey}`); + // Open a DM with the guide. Must use the same /messages/:npub route every + // other entry point uses — the old `/messages?to=` param was ignored, so + // the CTA silently opened an empty inbox. + navigate(`/messages/${nip19.npubEncode(tour.pubkey)}`); }; const handleShare = async () => {