Profile access, real gig messaging, desktop Local Chat removal + audit fixes
#0 Crew band gig booking: - Rename "Book them for a gig" -> "Set up a gig" (honest: it creates an event) - Add "Message about a gig" -> pre-filled encrypted DM (NIP-17) to the crew founder via existing /messages/:npub?message= flow (real communication) #1 Profile access (was missing/mislabeled everywhere): - Desktop header: add "View my profile" icon linking to /npub - Mobile user menu: split mislabeled "My Profile"(->Settings) into "View Profile" (-> /npub) + "Settings" - Burger menu: add "View Profile" entry - Settings > Edit Profile: add "View my public profile" quick link #2 Remove standalone Local Chat button on desktop map toolbar (kept on mobile) Audit fixes: - Mobile menu "Wallet & Stash" -> "Wallet" (Stash is already its own item) Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
8056b02ad1
commit
ee9e04d3e0
4 changed files with 63 additions and 10 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import { useState, useRef } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { CustomizeNavSheet } from '@/components/CustomizeNavSheet';
|
||||
import { useNavPreferences, useDesktopNavPreferences, type NavTab } from '@/hooks/useNavPreferences';
|
||||
|
|
@ -193,9 +194,15 @@ function MobileHeaderUserMenu({
|
|||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link to="/settings" className="flex items-center gap-2 cursor-pointer">
|
||||
<Link to={`/${nip19.npubEncode(pubkey)}`} className="flex items-center gap-2 cursor-pointer">
|
||||
<User className="h-4 w-4" />
|
||||
My Profile
|
||||
View Profile
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link to="/settings" className="flex items-center gap-2 cursor-pointer">
|
||||
<Settings className="h-4 w-4" />
|
||||
Settings
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
|
|
@ -213,7 +220,7 @@ function MobileHeaderUserMenu({
|
|||
<DropdownMenuItem asChild>
|
||||
<Link to="/wallet" className="flex items-center gap-2 cursor-pointer">
|
||||
<Wallet className="h-4 w-4 text-orange-400" />
|
||||
<span className="text-orange-400">Wallet & Stash</span>
|
||||
<span className="text-orange-400">Wallet</span>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
|
|
@ -569,8 +576,21 @@ export function Layout({ children, noPadding }: LayoutProps) {
|
|||
<OfflineIndicator />
|
||||
{/* Language Toggle */}
|
||||
<LanguageToggle compact className="text-gray-400 hover:text-white" />
|
||||
{/* View own public profile */}
|
||||
{user && (
|
||||
<Link to={`/${nip19.npubEncode(user.pubkey)}`}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="text-gray-400 hover:text-[#ff0040] hover:bg-[#ff0040]/10"
|
||||
title="View my profile"
|
||||
>
|
||||
<User className="h-5 w-5" />
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
<Link to="/settings">
|
||||
<Button variant="ghost" size="icon">
|
||||
<Button variant="ghost" size="icon" title="Settings">
|
||||
<Settings className="h-5 w-5" />
|
||||
</Button>
|
||||
</Link>
|
||||
|
|
@ -661,6 +681,15 @@ export function Layout({ children, noPadding }: LayoutProps) {
|
|||
onClick={() => setMobileMenuOpen(false)}
|
||||
/>
|
||||
))}
|
||||
{user && (
|
||||
<NavLink
|
||||
href={`/${nip19.npubEncode(user.pubkey)}`}
|
||||
label="View Profile"
|
||||
icon={User}
|
||||
isActive={false}
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{user && (
|
||||
<NavLink
|
||||
href="/messages"
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import { NoteContent } from '@/components/NoteContent';
|
|||
import { useCrew } from '@/hooks/useCrews';
|
||||
import { useCrewFeed } from '@/hooks/useCrewFeed';
|
||||
import { useAuthor } from '@/hooks/useAuthor';
|
||||
import { useCurrentUser } from '@/hooks/useCurrentUser';
|
||||
import { genUserName } from '@/lib/genUserName';
|
||||
import { SKATE_CREW_KIND, SKATE_SPOT_KIND, CREW_VIBE_LABELS, SHOW_CREW_TREASURY } from '@/lib/types';
|
||||
import { sanitizeUrl, urlDomain } from '@/lib/sanitizeUrl';
|
||||
|
|
@ -130,6 +131,7 @@ export default function CrewDetailPage() {
|
|||
const { pubkey, identifier } = useParams<{ pubkey: string; identifier: string }>();
|
||||
const { data: crew, isLoading, error } = useCrew(identifier || '', pubkey);
|
||||
const author = useAuthor(crew?.pubkey);
|
||||
const { user } = useCurrentUser();
|
||||
const { isFounder, isAdmin, role, canManage } = useCrewRole(crew);
|
||||
const { toast } = useToast();
|
||||
const [agentOpen, setAgentOpen] = useState(false);
|
||||
|
|
@ -560,11 +562,20 @@ export default function CrewDetailPage() {
|
|||
to={`/create-event?crew=${crew.pubkey}:${crew.identifier}&type=concert&title=${encodeURIComponent(`${crew.bandName} live`)}`}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-purple-500 px-3 py-2 text-sm font-black uppercase text-white transition-colors hover:bg-purple-600"
|
||||
>
|
||||
<Calendar className="h-4 w-4" /> Book them for a gig
|
||||
<Calendar className="h-4 w-4" /> Set up a gig
|
||||
</Link>
|
||||
{user && user.pubkey !== crew.pubkey && (
|
||||
<Link
|
||||
to={`/messages/${npub}?message=${encodeURIComponent(`Hey ${crew.name} — interested in booking ${crew.bandName} for a gig. Are you around to talk dates?`)}`}
|
||||
className="flex items-center justify-center gap-2 rounded-lg border border-purple-500/30 bg-purple-500/10 px-3 py-2 text-sm font-bold text-purple-200 transition-colors hover:bg-purple-500/20"
|
||||
>
|
||||
<MessageSquare className="h-4 w-4" /> Message about a gig
|
||||
</Link>
|
||||
)}
|
||||
<p className="text-center text-[11px] leading-snug text-gray-500">
|
||||
Sets up a music event hosted by this crew on the Events calendar —
|
||||
sort the date & venue and it's booked.
|
||||
<strong className="text-gray-400">Set up a gig</strong> adds a music event to the
|
||||
calendar hosted by this crew. <strong className="text-gray-400">Message</strong> opens
|
||||
an encrypted DM to the crew to sort dates & details.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -1437,16 +1437,17 @@ export default function MapPage() {
|
|||
{/* Spacer */}
|
||||
<div className="flex-1 min-w-2" />
|
||||
|
||||
{/* Local Chat - live geohash channel for wherever the map is centered */}
|
||||
{/* Local Chat - live geohash channel for wherever the map is centered.
|
||||
Mobile only: on desktop the toolbar is dense and DMs/crew chat cover
|
||||
messaging, so we hide the standalone Local Chat trigger at md+. */}
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="gap-1.5 border-2 border-purple-500/50 hover:bg-purple-500/10 text-purple-400 font-bold h-8 px-2 sm:px-3 flex-shrink-0"
|
||||
className="md:hidden gap-1.5 border-2 border-purple-500/50 hover:bg-purple-500/10 text-purple-400 font-bold h-8 px-2 flex-shrink-0"
|
||||
>
|
||||
<MessageCircle className="h-4 w-4" />
|
||||
<span className="hidden md:inline">Local Chat</span>
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { useTranslation } from '@/contexts/LanguageContext';
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useNostr } from '@nostrify/react';
|
||||
import { NSchema as n } from '@nostrify/nostrify';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { LoginArea } from '@/components/auth/LoginArea';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
|
@ -183,6 +184,17 @@ function ProfileScreen({ onBack }: { onBack: () => void }) {
|
|||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{/* Quick link to the user's own public profile page */}
|
||||
<Link
|
||||
to={`/${nip19.npubEncode(user.pubkey)}`}
|
||||
className="flex items-center justify-between gap-3 p-3 rounded-2xl bg-muted/50 border border-border hover:bg-muted transition-colors"
|
||||
>
|
||||
<span className="flex items-center gap-2 text-sm font-medium">
|
||||
<User className="h-4 w-4 text-[#ff0040]" />
|
||||
View my public profile
|
||||
</span>
|
||||
<ExternalLink className="h-4 w-4 text-muted-foreground" />
|
||||
</Link>
|
||||
{!metadata?.name && (
|
||||
<div className="flex items-center gap-3 p-3 rounded-2xl bg-yellow-950/30 border border-yellow-500/40">
|
||||
<AlertCircle className="h-4 w-4 text-yellow-500 flex-shrink-0" />
|
||||
|
|
|
|||
Loading…
Reference in a new issue