Skip to content

Commit 3734134

Browse files
1. ta des boucle d'api :
38 | console.log('[authEdge.auth] No aut
1 parent 734c09b commit 3734134

5 files changed

Lines changed: 359 additions & 66 deletions

File tree

src/app/(app)/profile/page.tsx

Lines changed: 133 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,21 @@
44
import { useAuth } from '@/hooks/useAuth';
55
import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from '@/components/ui/card';
66
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
7-
import { User as UserIcon, Mail, Shield, Edit3, Image as ImageIcon } from 'lucide-react';
7+
import { User as UserIcon, Mail, Shield, Edit3, Image as ImageIcon, Github, Link2, PowerOff, ExternalLink, MessageSquare } from 'lucide-react';
88
import { Skeleton } from '@/components/ui/skeleton';
99
import { Button } from '@/components/ui/button';
1010
import { Input } from '@/components/ui/input';
1111
import { Label } from '@/components/ui/label';
1212
import { useForm } from 'react-hook-form';
1313
import { zodResolver } from '@hookform/resolvers/zod';
1414
import * as z from 'zod';
15-
import { useEffect, useState } from 'react';
15+
import { useEffect, useState, useActionState, startTransition as ReactStartTransition } from 'react';
1616
import { useToast } from '@/hooks/use-toast';
17-
import * as authService from '@/lib/authService'; // Import server actions
17+
import * as authService from '@/lib/authService';
18+
import { fetchUserGithubOAuthTokenAction, disconnectGithubAction, fetchGithubUserDetailsAction } from '@/app/(app)/projects/[id]/actions'; // Re-using from project actions for now
19+
import { useRouter } from 'next/navigation';
20+
import Link from 'next/link';
21+
1822

1923
const profileFormSchema = z.object({
2024
name: z.string().min(2, { message: "Name must be at least 2 characters." }),
@@ -24,12 +28,27 @@ const profileFormSchema = z.object({
2428

2529
type ProfileFormValues = z.infer<typeof profileFormSchema>;
2630

31+
interface GithubUserDetails {
32+
login: string;
33+
avatar_url: string;
34+
html_url: string;
35+
name: string | null;
36+
}
37+
2738
export default function ProfilePage() {
2839
const { user, isLoading: authLoading, refreshUser } = useAuth();
40+
const router = useRouter();
2941
const [isEditing, setIsEditing] = useState(false);
3042
const [isSubmitting, setIsSubmitting] = useState(false);
3143
const { toast } = useToast();
3244

45+
const [githubToken, setGithubToken] = useState<string | null>(null);
46+
const [githubUserDetails, setGithubUserDetails] = useState<GithubUserDetails | null>(null);
47+
const [isLoadingGithub, setIsLoadingGithub] = useState(true);
48+
49+
const [disconnectState, disconnectFormAction, isDisconnectPending] = useActionState(disconnectGithubAction, { success: false });
50+
51+
3352
const form = useForm<ProfileFormValues>({
3453
resolver: zodResolver(profileFormSchema),
3554
defaultValues: {
@@ -49,6 +68,38 @@ export default function ProfilePage() {
4968
}
5069
}, [user, form]);
5170

71+
useEffect(() => {
72+
async function loadGithubData() {
73+
if (user) {
74+
setIsLoadingGithub(true);
75+
const tokenData = await fetchUserGithubOAuthTokenAction();
76+
if (tokenData?.accessToken) {
77+
setGithubToken(tokenData.accessToken);
78+
const userDetails = await fetchGithubUserDetailsAction();
79+
setGithubUserDetails(userDetails);
80+
} else {
81+
setGithubToken(null);
82+
setGithubUserDetails(null);
83+
}
84+
setIsLoadingGithub(false);
85+
}
86+
}
87+
if (!authLoading) loadGithubData();
88+
}, [user, authLoading]);
89+
90+
useEffect(() => {
91+
if (!isDisconnectPending && disconnectState) {
92+
if (disconnectState.success) {
93+
toast({ title: "Success", description: disconnectState.message });
94+
setGithubToken(null);
95+
setGithubUserDetails(null);
96+
} else if (disconnectState.error) {
97+
toast({ variant: "destructive", title: "Error", description: disconnectState.error });
98+
}
99+
}
100+
}, [disconnectState, isDisconnectPending, toast]);
101+
102+
52103
if (authLoading) {
53104
return (
54105
<div className="space-y-6">
@@ -81,7 +132,9 @@ export default function ProfilePage() {
81132
}
82133

83134
if (!user) {
84-
return <p>User not found. Please log in.</p>;
135+
// Should be redirected by useAuth hook or AppLayout, but as a fallback:
136+
router.push('/login');
137+
return <p>Redirecting to login...</p>;
85138
}
86139

87140
const getInitials = (name: string) => {
@@ -112,12 +165,25 @@ export default function ProfilePage() {
112165
}
113166
};
114167

168+
const handleConnectGitHub = () => {
169+
// Redirect to the GitHub OAuth login flow
170+
window.location.href = `/api/auth/github/oauth/login?redirectTo=/profile`;
171+
};
172+
173+
const handleDisconnectGitHub = () => {
174+
const dummyFormData = new FormData(); // useActionState requires FormData
175+
ReactStartTransition(() => {
176+
disconnectFormAction(dummyFormData);
177+
});
178+
};
179+
180+
115181
return (
116-
<div className="space-y-6">
182+
<div className="space-y-8">
117183
<div className="flex justify-between items-center">
118184
<div>
119185
<h1 className="text-3xl font-headline font-semibold">My Profile</h1>
120-
<p className="text-muted-foreground">View and manage your personal information.</p>
186+
<p className="text-muted-foreground">View and manage your personal information and connections.</p>
121187
</div>
122188
{!isEditing && (
123189
<Button variant="outline" onClick={() => setIsEditing(true)}>
@@ -207,6 +273,67 @@ export default function ProfilePage() {
207273
)}
208274
</form>
209275
</Card>
276+
277+
<Card className="max-w-2xl mx-auto shadow-lg">
278+
<CardHeader>
279+
<CardTitle className="text-xl flex items-center"><Link2 className="mr-2 h-5 w-5 text-primary"/>External Connections</CardTitle>
280+
<CardDescription>Manage your connections to third-party services.</CardDescription>
281+
</CardHeader>
282+
<CardContent className="space-y-4">
283+
{/* GitHub Connection */}
284+
<Card className="p-4 bg-muted/30">
285+
<div className="flex items-center justify-between">
286+
<div className="flex items-center gap-3">
287+
<Github className="h-8 w-8" />
288+
<div>
289+
<h4 className="font-semibold">GitHub</h4>
290+
{isLoadingGithub ? (
291+
<Skeleton className="h-4 w-32 mt-1" />
292+
) : githubUserDetails ? (
293+
<div className="text-sm text-muted-foreground">
294+
Connected as: <a href={githubUserDetails.html_url} target="_blank" rel="noopener noreferrer" className="font-medium text-primary hover:underline">{githubUserDetails.login}</a> ({githubUserDetails.name || 'Name not public'})
295+
<Avatar className="h-5 w-5 inline-block ml-2 align-middle">
296+
<AvatarImage src={githubUserDetails.avatar_url} alt={githubUserDetails.login} data-ai-hint="github avatar" />
297+
<AvatarFallback>{getInitials(githubUserDetails.login)}</AvatarFallback>
298+
</Avatar>
299+
</div>
300+
) : (
301+
<p className="text-sm text-muted-foreground">Not Connected</p>
302+
)}
303+
</div>
304+
</div>
305+
{isLoadingGithub ? (
306+
<Skeleton className="h-9 w-24" />
307+
) : githubToken ? (
308+
<Button variant="outline" onClick={handleDisconnectGitHub} disabled={isDisconnectPending}>
309+
{isDisconnectPending ? <Loader2 className="h-4 w-4 animate-spin mr-2"/> : <PowerOff className="mr-2 h-4 w-4" />}
310+
Disconnect
311+
</Button>
312+
) : (
313+
<Button onClick={handleConnectGitHub}>
314+
<Github className="mr-2 h-4 w-4" /> Connect
315+
</Button>
316+
)}
317+
</div>
318+
</Card>
319+
320+
{/* Discord Connection (Placeholder) */}
321+
<Card className="p-4 bg-muted/30">
322+
<div className="flex items-center justify-between">
323+
<div className="flex items-center gap-3">
324+
<MessageSquare className="h-8 w-8 text-indigo-500" />
325+
<div>
326+
<h4 className="font-semibold">Discord</h4>
327+
<p className="text-sm text-muted-foreground">Connect to receive notifications (Coming Soon).</p>
328+
</div>
329+
</div>
330+
<Button disabled>
331+
<MessageSquare className="mr-2 h-4 w-4" /> Connect (Soon)
332+
</Button>
333+
</div>
334+
</Card>
335+
</CardContent>
336+
</Card>
210337
</div>
211338
);
212339
}

0 commit comments

Comments
 (0)