import { useSeoMeta } from '@unhead/react';
import { Layout } from '@/components/Layout';
import { EditProfileForm } from '@/components/EditProfileForm';
import { RelayListManager } from '@/components/RelayListManager';
import { FollowListManager } from '@/components/FollowListManager';
import { WalletModal } from '@/components/WalletModal';
import { SecuritySettings } from '@/components/SecuritySettings';
import { RelatrSettings } from '@/components/RelatrSettings';
import { LanguageSelector } from '@/components/LanguageToggle';
import { MyDataTab } from '@/components/MyDataTab';
import { useTranslation } from '@/contexts/LanguageContext';
import { useQueryClient } from '@tanstack/react-query';
import { useNostr } from '@nostrify/react';
import { NSchema as n } from '@nostrify/nostrify';
import { useState } from 'react';
import { LoginArea } from '@/components/auth/LoginArea';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useAppContext } from '@/hooks/useAppContext';
import { toast } from '@/hooks/useToast';
import {
User,
Palette,
Radio,
Wallet,
Settings,
Wrench,
RotateCcw,
Shield,
ExternalLink,
Languages,
RefreshCw,
AlertCircle,
Database,
} from 'lucide-react';
// Fallback relays for fetching profile data
const PROFILE_FALLBACK_RELAYS = [
'wss://purplepag.es',
'wss://relay.damus.io',
'wss://nos.lol',
];
function ProfileTab() {
const { user, metadata } = useCurrentUser();
const { nostr } = useNostr();
const queryClient = useQueryClient();
const [isRefreshing, setIsRefreshing] = useState(false);
const handleRefreshProfile = async () => {
if (!user) return;
setIsRefreshing(true);
console.log('[ProfileTab] Manual refresh for pubkey:', user.pubkey.slice(0, 8) + '...');
try {
// First invalidate the cache
queryClient.invalidateQueries({ queryKey: ['author', user.pubkey] });
// Try main relays
let events = await nostr.query(
[{ kinds: [0], authors: [user.pubkey], limit: 1 }],
{ signal: AbortSignal.timeout(8000) }
);
console.log('[ProfileTab] Main relays returned', events.length, 'events');
// If not found, try fallback relays
if (events.length === 0) {
console.log('[ProfileTab] Trying fallback relays...');
const fallbackGroup = nostr.group(PROFILE_FALLBACK_RELAYS);
events = await fallbackGroup.query(
[{ kinds: [0], authors: [user.pubkey], limit: 1 }],
{ signal: AbortSignal.timeout(8000) }
);
console.log('[ProfileTab] Fallback relays returned', events.length, 'events');
}
if (events.length > 0) {
const event = events[0];
try {
const profileMetadata = n.json().pipe(n.metadata()).parse(event.content);
queryClient.setQueryData(['author', user.pubkey], { metadata: profileMetadata, event });
toast({
title: 'Profile refreshed!',
description: `Found profile: ${profileMetadata.name || 'unnamed'}`,
});
} catch {
toast({
title: 'Profile found',
description: 'But metadata could not be parsed.',
variant: 'destructive',
});
}
} else {
toast({
title: 'Profile not found',
description: 'Your profile (kind 0 event) was not found on any relay. You may need to publish it.',
variant: 'destructive',
});
}
} catch (error) {
console.error('[ProfileTab] Refresh failed:', error);
toast({
title: 'Refresh failed',
description: 'Could not connect to relays. Check your internet connection.',
variant: 'destructive',
});
} finally {
setIsRefreshing(false);
}
};
if (!user) {
return (
Log in to edit your profile.
Login Required
Profile not loaded. Your profile data wasn't found on the configured relays. Try refreshing or make sure you've published your profile.
💡 Tip: After getting your NIP-05, add it to your profile in the "NIP-05" field above and save.
Dark Mode Only
SkateSpots is designed with a dark neon aesthetic inspired by Tony Hawk's Underground 2 and skate culture. The black background with neon pink, lime, and orange creates the signature skateboarding vibe.
Use Community Relay
{useSkateRelay ? 'Enabled - Your content syncs with the global skate community' : 'Disabled - Using only your personal relays'}
💡 What does this do?
⚠️ Note: With the community relay disabled, you'll only see skate content from relays you've configured below. Make sure you have at least one relay set up!
goskatespots.nostr1.com
wss://goskatespots.nostr1.com
The dedicated SkateSpots community relay. Custom policies for spots, events, coaches, filmers, and shops. Toggle it on/off above.
⚠️ Allowlisted: Your npub must be approved to publish here. DM the relay owner to request access.
auth.nostr1.com
wss://auth.nostr1.com
Authentication relay for Nostr identity verification and NIP-42 auth flows.
wotr.relatr.xyz
wss://wotr.relatr.xyz
Relatr's Web of Trust relay. Powers trust scores and broader Nostr network connectivity.
relay.ditto.pub
wss://relay.ditto.pub
General purpose relay with broad Nostr network coverage for maximum reach.
purplepag.es
wss://purplepag.es
Read onlyProfile aggregator that indexes Nostr profiles from across the network. Used for fast profile lookups and discovery.
Your content publishes to all write-enabled relays for maximum reliability. You can customise your relay list above using the relay manager.
💡 Want to run your own relay? Check out{' '} relay.tools {' '}to easily spin up and manage your own Nostr relay!
Log in to manage your wallet.
What is NWC? Nostr Wallet Connect lets you link your Lightning wallet (like Alby, Minibits, Zeus, or Coinos) to send zaps without copy-pasting invoices.
The Sasquatch appears as a minimizable button in the bottom-left corner. Click to expand or minimize at any time. If you want to reset it to expanded view, use the button below.
Manage your account and app preferences