Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place

logout button

Changed files
+61 -2
public
+28 -1
public/editor/editor.tsx
··· 21 21 import { 22 22 Globe, 23 23 Loader2, 24 - Trash2 24 + Trash2, 25 + LogOut 25 26 } from 'lucide-react' 26 27 import Layout from '@public/layouts' 27 28 import { useUserInfo } from './hooks/useUserInfo' ··· 156 157 await fetchSites() 157 158 } 158 159 160 + const handleLogout = async () => { 161 + try { 162 + const response = await fetch('/api/auth/logout', { 163 + method: 'POST', 164 + credentials: 'include' 165 + }) 166 + const result = await response.json() 167 + if (result.success) { 168 + // Redirect to home page after successful logout 169 + window.location.href = '/' 170 + } else { 171 + alert('Logout failed: ' + (result.error || 'Unknown error')) 172 + } 173 + } catch (err) { 174 + alert('Logout failed: ' + (err instanceof Error ? err.message : 'Unknown error')) 175 + } 176 + } 177 + 159 178 if (loading) { 160 179 return ( 161 180 <div className="w-full min-h-screen bg-background flex items-center justify-center"> ··· 181 200 <span className="text-sm text-muted-foreground"> 182 201 {userInfo?.handle || 'Loading...'} 183 202 </span> 203 + <Button 204 + variant="ghost" 205 + size="sm" 206 + onClick={handleLogout} 207 + className="h-8 px-2" 208 + > 209 + <LogOut className="w-4 h-4" /> 210 + </Button> 184 211 </div> 185 212 </div> 186 213 </header>
+33 -1
public/index.tsx
··· 16 16 17 17 function App() { 18 18 const [showForm, setShowForm] = useState(false) 19 + const [checkingAuth, setCheckingAuth] = useState(true) 19 20 const inputRef = useRef<HTMLInputElement>(null) 20 21 21 22 useEffect(() => { 23 + // Check authentication status on mount 24 + const checkAuth = async () => { 25 + try { 26 + const response = await fetch('/api/auth/status', { 27 + credentials: 'include' 28 + }) 29 + const data = await response.json() 30 + if (data.authenticated) { 31 + // User is already authenticated, redirect to editor 32 + window.location.href = '/editor' 33 + return 34 + } 35 + } catch (error) { 36 + console.error('Auth check failed:', error) 37 + } finally { 38 + setCheckingAuth(false) 39 + } 40 + } 41 + 42 + checkAuth() 43 + }, []) 44 + 45 + useEffect(() => { 22 46 if (showForm) { 23 47 setTimeout(() => inputRef.current?.focus(), 500) 24 48 } 25 49 }, [showForm]) 50 + 51 + if (checkingAuth) { 52 + return ( 53 + <div className="min-h-screen bg-background flex items-center justify-center"> 54 + <div className="w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin"></div> 55 + </div> 56 + ) 57 + } 26 58 27 59 return ( 28 60 <> ··· 61 93 <div className="max-w-4xl mx-auto text-center"> 62 94 <div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-accent/10 border border-accent/20 mb-8"> 63 95 <span className="w-2 h-2 bg-accent rounded-full animate-pulse"></span> 64 - <span className="text-sm text-accent-foreground"> 96 + <span className="text-sm text-foreground"> 65 97 Built on AT Protocol 66 98 </span> 67 99 </div>