https://altly.madebydanny.uk
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;