The 1st decentralized social network for sharing when you're on the toilet. Post a "flush" today! Powered by the AT Protocol.
at main 140 lines 4.5 kB view raw
1'use client'; 2 3import React, { useState, useEffect } from 'react'; 4import Link from 'next/link'; 5import Image from 'next/image'; 6import { usePathname } from 'next/navigation'; 7import styles from './NavigationBar.module.css'; 8import ProfileSearch from './ProfileSearch'; 9import ThemeToggle from './ThemeToggle'; 10import { useAuth } from '@/lib/auth-context'; 11 12export default function NavigationBar() { 13 const pathname = usePathname(); 14 const { isAuthenticated, signOut, session } = useAuth(); 15 const [handle, setHandle] = useState<string | null>(null); 16 17 // Fetch user's handle when authenticated 18 useEffect(() => { 19 if (isAuthenticated && session?.sub && !handle) { 20 fetchUserHandle(session.sub); 21 } 22 }, [isAuthenticated, session?.sub, handle]); 23 24 const fetchUserHandle = async (did: string) => { 25 try { 26 // Try to resolve DID to handle using PLC directory 27 const plcResponse = await fetch(`https://plc.directory/${did}/data`); 28 29 if (plcResponse.ok) { 30 const plcData = await plcResponse.json(); 31 if (plcData.alsoKnownAs && plcData.alsoKnownAs.length > 0) { 32 const handleUrl = plcData.alsoKnownAs[0]; 33 if (handleUrl.startsWith('at://')) { 34 const userHandle = handleUrl.substring(5); // Remove 'at://' 35 console.log(`Resolved DID ${did} to handle ${userHandle}`); 36 setHandle(userHandle); 37 return; 38 } 39 } 40 } 41 } catch (error) { 42 console.warn('Failed to resolve handle from PLC directory:', error); 43 } 44 45 // Fallback: try using the profile API 46 try { 47 const response = await fetch('/api/bluesky/profile', { 48 method: 'POST', 49 headers: { 50 'Content-Type': 'application/json' 51 }, 52 body: JSON.stringify({ 53 accessToken: 'placeholder', // OAuth session handles auth internally 54 dpopToken: 'placeholder', // OAuth session handles auth internally 55 handle: did, 56 pdsEndpoint: null 57 }) 58 }); 59 60 if (response.ok) { 61 const data = await response.json(); 62 if (data.handle && data.handle !== 'unknown') { 63 setHandle(data.handle); 64 } 65 } 66 } catch (error) { 67 console.warn('Failed to fetch handle from profile API:', error); 68 } 69 }; 70 71 const handleLogout = async () => { 72 await signOut(); 73 setHandle(null); // Clear handle on logout 74 }; 75 76 // Check if a link is active 77 const isActive = (path: string) => { 78 return pathname === path; 79 }; 80 81 return ( 82 <nav className={styles.navbar}> 83 <div className={styles.navStart}> 84 <Link href="/" className={styles.logo}> 85 <Image 86 src="/flushes-logo-horizontal.png" 87 alt="Flushes Logo" 88 width={200} 89 height={53} 90 priority 91 className={styles.logoImage} 92 /> 93 </Link> 94 95 <div className={styles.navLinks}> 96 <Link href="/" className={`${styles.navLink} font-medium ${isActive('/') ? styles.active : ''}`}> 97 Feed 98 </Link> 99 <Link href="/stats" className={`${styles.navLink} font-medium ${isActive('/stats') ? styles.active : ''}`}> 100 Stats 101 </Link> 102 <Link href="/shortcut" className={`${styles.navLink} font-medium ${isActive('/shortcut') ? styles.active : ''}`}> 103 Shortcut 104 </Link> 105 <Link href="/about" className={`${styles.navLink} font-medium ${isActive('/about') ? styles.active : ''}`}> 106 About 107 </Link> 108 {isAuthenticated && handle && ( 109 <Link 110 href={`/profile/${handle}`} 111 className={`${styles.navLink} font-medium ${pathname.startsWith('/profile/') ? styles.active : ''}`} 112 > 113 Profile 114 </Link> 115 )} 116 </div> 117 </div> 118 119 <div className={styles.secondRow}> 120 <div className={styles.navSearch}> 121 <ProfileSearch /> 122 </div> 123 124 <div className={styles.navEnd}> 125 <ThemeToggle /> 126 127 {isAuthenticated ? ( 128 <button onClick={handleLogout} className={`${styles.authButton} font-medium`}> 129 Logout 130 </button> 131 ) : ( 132 <Link href="/auth/login" className={`${styles.authButton} font-medium`}> 133 Login 134 </Link> 135 )} 136 </div> 137 </div> 138 </nav> 139 ); 140}