Skip to content

Commit a3d0b7e

Browse files
Run SQL for authentication and media.
1 parent b7a60f3 commit a3d0b7e

10 files changed

Lines changed: 1129 additions & 99 deletions

File tree

src/App.tsx

Lines changed: 101 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,39 @@
11

2-
import { BrowserRouter, Routes, Route } from 'react-router-dom';
2+
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
33
import { useEffect, useState } from 'react';
4+
import { AuthProvider, useAuth } from './contexts/AuthContext';
45
import Index from './pages/Index';
6+
import Auth from './pages/Auth';
7+
import Profile from './pages/Profile';
58
import NotFound from './pages/NotFound';
69
import { Toaster } from "@/components/ui/toaster";
710
import { CircuitBoard, Cpu, Database, Globe, HardDrive, Layers, Monitor, Server, Zap } from 'lucide-react';
811

9-
function App() {
12+
interface ProtectedRouteProps {
13+
children: React.ReactNode;
14+
}
15+
16+
const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
17+
const { user, loading } = useAuth();
18+
19+
if (loading) {
20+
return (
21+
<div className="flex justify-center items-center min-h-screen bg-terminal-black">
22+
<div className="terminal-loading">
23+
<div className="text-terminal-green font-vt323 text-xl">Loading...</div>
24+
</div>
25+
</div>
26+
);
27+
}
28+
29+
if (!user) {
30+
return <Navigate to="/auth" replace />;
31+
}
32+
33+
return <>{children}</>;
34+
};
35+
36+
function AppContent() {
1037
const [animationFrames, setAnimationFrames] = useState<number[]>([]);
1138

1239
useEffect(() => {
@@ -16,67 +43,81 @@ function App() {
1643
}, []);
1744

1845
return (
19-
<BrowserRouter>
20-
<div className="min-h-screen bg-terminal-black text-terminal-green font-vt323 relative overflow-hidden">
21-
{/* Left side decorative elements */}
22-
<div className="fixed left-0 top-0 bottom-0 w-16 md:w-32 z-0 flex flex-col items-center justify-between py-10 overflow-hidden">
23-
<div className="h-full w-px bg-gradient-to-b from-terminal-purple/0 via-terminal-purple to-terminal-purple/0"></div>
24-
25-
{animationFrames.slice(0, 10).map((delay, i) => (
26-
<div
27-
key={`left-${i}`}
28-
className="absolute"
29-
style={{
30-
left: `${Math.random() * 100}%`,
31-
top: `${i * 10}%`,
32-
animationDelay: `${delay * 0.5}s`
33-
}}
34-
>
35-
{i % 5 === 0 && <CircuitBoard size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
36-
{i % 5 === 1 && <Database size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
37-
{i % 5 === 2 && <Server size={16} className="text-terminal-green/30 animate-pulse-slow" />}
38-
{i % 5 === 3 && <Cpu size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
39-
{i % 5 === 4 && <HardDrive size={16} className="text-terminal-green/30 animate-pulse-slow" />}
40-
</div>
41-
))}
42-
</div>
43-
44-
{/* Right side decorative elements */}
45-
<div className="fixed right-0 top-0 bottom-0 w-16 md:w-32 z-0 flex flex-col items-center justify-between py-10 overflow-hidden">
46-
<div className="h-full w-px bg-gradient-to-b from-terminal-purple/0 via-terminal-purple to-terminal-purple/0"></div>
47-
48-
{animationFrames.slice(10).map((delay, i) => (
49-
<div
50-
key={`right-${i}`}
51-
className="absolute"
52-
style={{
53-
right: `${Math.random() * 100}%`,
54-
top: `${i * 10}%`,
55-
animationDelay: `${delay * 0.5}s`
56-
}}
57-
>
58-
{i % 5 === 0 && <Zap size={16} className="text-terminal-cyan/30 animate-pulse-slow" />}
59-
{i % 5 === 1 && <Globe size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
60-
{i % 5 === 2 && <Monitor size={16} className="text-terminal-green/30 animate-pulse-slow" />}
61-
{i % 5 === 3 && <Layers size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
62-
{i % 5 === 4 && <CircuitBoard size={16} className="text-terminal-cyan/30 animate-pulse-slow" />}
63-
</div>
64-
))}
65-
</div>
66-
67-
{/* Main content */}
68-
<div className="relative z-10">
69-
<Routes>
70-
<Route path="/" element={<Index />} />
71-
<Route path="*" element={<NotFound />} />
72-
</Routes>
73-
</div>
46+
<div className="min-h-screen bg-terminal-black text-terminal-green font-vt323 relative overflow-hidden">
47+
{/* Left side decorative elements */}
48+
<div className="fixed left-0 top-0 bottom-0 w-16 md:w-32 z-0 flex flex-col items-center justify-between py-10 overflow-hidden">
49+
<div className="h-full w-px bg-gradient-to-b from-terminal-purple/0 via-terminal-purple to-terminal-purple/0"></div>
7450

75-
{/* Background grid overlay */}
76-
<div className="fixed inset-0 bg-[linear-gradient(to_right,#9b87f510_1px,transparent_1px),linear-gradient(to_bottom,#9b87f510_1px,transparent_1px)] bg-[size:24px_24px] z-0"></div>
51+
{animationFrames.slice(0, 10).map((delay, i) => (
52+
<div
53+
key={`left-${i}`}
54+
className="absolute"
55+
style={{
56+
left: `${Math.random() * 100}%`,
57+
top: `${i * 10}%`,
58+
animationDelay: `${delay * 0.5}s`
59+
}}
60+
>
61+
{i % 5 === 0 && <CircuitBoard size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
62+
{i % 5 === 1 && <Database size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
63+
{i % 5 === 2 && <Server size={16} className="text-terminal-green/30 animate-pulse-slow" />}
64+
{i % 5 === 3 && <Cpu size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
65+
{i % 5 === 4 && <HardDrive size={16} className="text-terminal-green/30 animate-pulse-slow" />}
66+
</div>
67+
))}
68+
</div>
69+
70+
{/* Right side decorative elements */}
71+
<div className="fixed right-0 top-0 bottom-0 w-16 md:w-32 z-0 flex flex-col items-center justify-between py-10 overflow-hidden">
72+
<div className="h-full w-px bg-gradient-to-b from-terminal-purple/0 via-terminal-purple to-terminal-purple/0"></div>
7773

78-
<Toaster />
74+
{animationFrames.slice(10).map((delay, i) => (
75+
<div
76+
key={`right-${i}`}
77+
className="absolute"
78+
style={{
79+
right: `${Math.random() * 100}%`,
80+
top: `${i * 10}%`,
81+
animationDelay: `${delay * 0.5}s`
82+
}}
83+
>
84+
{i % 5 === 0 && <Zap size={16} className="text-terminal-cyan/30 animate-pulse-slow" />}
85+
{i % 5 === 1 && <Globe size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
86+
{i % 5 === 2 && <Monitor size={16} className="text-terminal-green/30 animate-pulse-slow" />}
87+
{i % 5 === 3 && <Layers size={16} className="text-terminal-purple/30 animate-pulse-slow" />}
88+
{i % 5 === 4 && <CircuitBoard size={16} className="text-terminal-cyan/30 animate-pulse-slow" />}
89+
</div>
90+
))}
91+
</div>
92+
93+
{/* Main content */}
94+
<div className="relative z-10">
95+
<Routes>
96+
<Route path="/" element={<Index />} />
97+
<Route path="/auth" element={<Auth />} />
98+
<Route path="/profile" element={
99+
<ProtectedRoute>
100+
<Profile />
101+
</ProtectedRoute>
102+
} />
103+
<Route path="*" element={<NotFound />} />
104+
</Routes>
79105
</div>
106+
107+
{/* Background grid overlay */}
108+
<div className="fixed inset-0 bg-[linear-gradient(to_right,#9b87f510_1px,transparent_1px),linear-gradient(to_bottom,#9b87f510_1px,transparent_1px)] bg-[size:24px_24px] z-0"></div>
109+
110+
<Toaster />
111+
</div>
112+
);
113+
}
114+
115+
function App() {
116+
return (
117+
<BrowserRouter>
118+
<AuthProvider>
119+
<AppContent />
120+
</AuthProvider>
80121
</BrowserRouter>
81122
);
82123
}

src/components/ConfessionCard.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,16 @@ import RetroText from './RetroText';
66
import DegenRating from './DegenRating';
77
import ReactionButton from './ReactionButton';
88
import ReplyForm from './ReplyForm';
9-
import { addReaction, getReactions, getReplies, ReactionType, Reaction, Reply } from '@/services/confessionService';
9+
import {
10+
addReaction,
11+
getReactions,
12+
getReplies,
13+
getConfessionMedia,
14+
ReactionType,
15+
Reaction,
16+
Reply,
17+
Media
18+
} from '@/services/confessionService';
1019
import { useToast } from "@/hooks/use-toast";
1120

1221
interface ConfessionCardProps {
@@ -63,11 +72,14 @@ const ConfessionCard = ({ confession, isRandom = false }: ConfessionCardProps) =
6372
const [showReplyForm, setShowReplyForm] = useState(false);
6473
const [isLoadingReactions, setIsLoadingReactions] = useState(false);
6574
const [isLoadingReplies, setIsLoadingReplies] = useState(false);
75+
const [media, setMedia] = useState<Media | null>(null);
76+
const [isLoadingMedia, setIsLoadingMedia] = useState(true);
6677
const { toast } = useToast();
6778

6879
useEffect(() => {
6980
if (!isRandom) {
7081
loadReactions();
82+
loadMedia();
7183
}
7284
}, [confession.id, isRandom]);
7385

@@ -83,6 +95,18 @@ const ConfessionCard = ({ confession, isRandom = false }: ConfessionCardProps) =
8395
}
8496
};
8597

98+
const loadMedia = async () => {
99+
setIsLoadingMedia(true);
100+
try {
101+
const media = await getConfessionMedia(confession.id);
102+
setMedia(media);
103+
} catch (error) {
104+
console.error('Error loading media:', error);
105+
} finally {
106+
setIsLoadingMedia(false);
107+
}
108+
};
109+
86110
const loadReplies = async () => {
87111
if (replies.length > 0) return;
88112

@@ -130,6 +154,10 @@ const ConfessionCard = ({ confession, isRandom = false }: ConfessionCardProps) =
130154
await loadReplies();
131155
};
132156

157+
const isMediaImage = (mediaType?: string) => {
158+
return mediaType?.startsWith('image/');
159+
};
160+
133161
return (
134162
<PixelContainer
135163
className={`w-full mb-4 transition-all ${isRandom ? 'animate-glitch' : 'hover:scale-[1.01]'}`}
@@ -149,6 +177,17 @@ const ConfessionCard = ({ confession, isRandom = false }: ConfessionCardProps) =
149177
{confession.text}
150178
</RetroText>
151179

180+
{!isLoadingMedia && media && isMediaImage(media.mediaType) && (
181+
<div className="mt-4 mb-4 border-2 border-terminal-purple p-2 bg-terminal-darkgray/30">
182+
<img
183+
src={media.mediaUrl}
184+
alt="Confession media"
185+
className="max-h-80 mx-auto"
186+
loading="lazy"
187+
/>
188+
</div>
189+
)}
190+
152191
{!isRandom && (
153192
<div className="mt-6 border-t border-terminal-purple/20 pt-3">
154193
<div className="flex flex-wrap gap-2">

0 commit comments

Comments
 (0)