https://altly.madebydanny.uk
at main 113 lines 3.6 kB view raw
1import { useState, useEffect } from "react"; 2import { useNavigate } from "react-router-dom"; 3import { Stats } from "@/components/Stats"; 4import { ImageUploader } from "@/components/ImageUploader"; 5import { Eye, LogOut, History as HistoryIcon } from "lucide-react"; 6import { Button } from "@/components/ui/button"; 7import { supabase } from "@/integrations/supabase/client"; 8import { User } from "@supabase/supabase-js"; 9 10const Index = () => { 11 const [user, setUser] = useState<User | null>(null); 12 const [dailyCount, setDailyCount] = useState(0); 13 const navigate = useNavigate(); 14 15 useEffect(() => { 16 supabase.auth.getSession().then(({ data: { session } }) => { 17 if (session?.user) { 18 setUser(session.user); 19 fetchDailyCount(session.user.id); 20 } else { 21 navigate("/auth"); 22 } 23 }); 24 25 const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => { 26 if (session?.user) { 27 setUser(session.user); 28 fetchDailyCount(session.user.id); 29 } else { 30 navigate("/auth"); 31 } 32 }); 33 34 return () => subscription.unsubscribe(); 35 }, [navigate]); 36 37 const fetchDailyCount = async (userId: string) => { 38 const oneDayAgo = new Date(Date.now() - 86400000).toISOString(); 39 const { data } = await supabase 40 .from('alt_text_generations') 41 .select('id') 42 .eq('user_id', userId) 43 .gte('created_at', oneDayAgo); 44 45 setDailyCount(data?.length || 0); 46 }; 47 48 const handleSignOut = async () => { 49 await supabase.auth.signOut(); 50 }; 51 52 if (!user) return null; 53 54 return ( 55 <div className="min-h-screen bg-background"> 56 {/* Header */} 57 <header className="border-b border-border/50 bg-card/50 backdrop-blur-sm sticky top-0 z-50"> 58 <div className="container mx-auto px-4 py-4 flex items-center justify-between"> 59 <div className="flex items-center gap-2"> 60 <div className="w-10 h-10 rounded-xl bg-primary/20 flex items-center justify-center"> 61 <Eye className="w-6 h-6 text-primary" /> 62 </div> 63 <span className="text-xl font-bold text-foreground">ALTly</span> 64 </div> 65 <div className="flex items-center gap-2"> 66 <Button 67 variant="ghost" 68 onClick={() => navigate("/history")} 69 className="gap-2" 70 > 71 <HistoryIcon className="w-4 h-4" /> 72 <span className="hidden sm:inline">History</span> 73 </Button> 74 <Button 75 variant="ghost" 76 size="sm" 77 onClick={handleSignOut} 78 > 79 <LogOut className="w-4 h-4 mr-1" /> 80 Sign Out 81 </Button> 82 </div> 83 </div> 84 </header> 85 86 <main className="container mx-auto px-4 py-12"> 87 {/* Hero Section */} 88 <div className="text-center mb-8"> 89 <h1 className="text-3xl md:text-4xl font-bold text-foreground mb-2"> 90 Generate Alt Text 91 </h1> 92 <p className="text-muted-foreground mb-2"> 93 Upload an image to generate accessible alt text 94 </p> 95 <p className="text-sm text-muted-foreground"> 96 Daily usage: <span className="font-semibold text-foreground">{dailyCount}/20</span> generations 97 </p> 98 </div> 99 100 {/* Stats Section */} 101 <Stats /> 102 103 {/* Upload Section */} 104 <div className="max-w-3xl mx-auto mb-12"> 105 <ImageUploader user={user} /> 106 </div> 107 108 </main> 109 </div> 110 ); 111}; 112 113export default Index;