looda3131 commited on
Commit
cb33096
·
1 Parent(s): 866d7b6

طيب اريدك ان تضيف معلومات كثير في الملف الشخصي يضيفها المستخدم تساعدنا ع

Browse files
src/app/login/page.tsx CHANGED
@@ -1,13 +1,16 @@
 
1
  'use client';
2
 
3
  import { Button } from "@/components/ui/button";
4
  import { Header } from "@/components/header";
5
- import { Loader2, LogIn, MessageSquare, Chrome, UserPlus, MapPin, Calendar } from "lucide-react";
6
  import { useAuth } from "@/contexts/auth-context";
7
  import { useEffect, useState } from "react";
8
  import { useRouter } from "next/navigation";
9
  import { Input } from "@/components/ui/input";
10
  import { Label } from "@/components/ui/label";
 
 
11
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
12
  import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
13
  import { useToast } from "@/hooks/use-toast";
@@ -17,10 +20,19 @@ export default function LoginPage() {
17
  const { user, userData, loading: authLoading, signInWithGoogle, signInWithUsername, completeProfile } = useAuth();
18
  const { t } = useLanguage();
19
  const [isSigningIn, setIsSigningIn] = useState(false);
 
 
20
  const [username, setUsername] = useState('');
21
  const [password, setPassword] = useState('');
22
  const [age, setAge] = useState('');
23
  const [location, setLocation] = useState('');
 
 
 
 
 
 
 
24
  const [showCompleteProfile, setShowCompleteProfile] = useState(false);
25
 
26
  const router = useRouter();
@@ -52,7 +64,9 @@ export default function LoginPage() {
52
  }
53
  setIsSigningIn(true);
54
  try {
55
- await signInWithUsername(username, password, parseInt(age), location);
 
 
56
  } catch (error) {
57
  console.error(error);
58
  } finally {
@@ -68,7 +82,14 @@ export default function LoginPage() {
68
  return;
69
  }
70
  setIsSigningIn(true);
71
- await completeProfile(parseInt(age), location);
 
 
 
 
 
 
 
72
  setIsSigningIn(false);
73
  };
74
 
@@ -84,38 +105,84 @@ export default function LoginPage() {
84
  return (
85
  <div className="flex h-screen w-full flex-col bg-muted/30">
86
  <Header title={t.loginTitle} />
87
- <div className="flex flex-1 items-center justify-center p-4">
88
- <Card className="w-full max-w-md radiant-card rounded-[2rem] border-none shadow-2xl overflow-hidden">
89
  <CardHeader className="bg-primary text-primary-foreground p-8">
90
- <CardTitle className="text-2xl font-black">{t.completeProfile}</CardTitle>
91
- <CardDescription className="text-primary-foreground/80">{t.chooseLogin}</CardDescription>
92
  </CardHeader>
93
  <form onSubmit={handleCompleteProfile}>
94
  <CardContent className="space-y-6 p-8">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  <div className="space-y-2">
96
- <Label className="font-bold flex items-center gap-2"><Calendar className="h-4 w-4 text-primary" /> {t.age}</Label>
97
  <Input
98
- type="number"
99
- value={age}
100
- onChange={e => setAge(e.target.value)}
101
- required
102
  className="rounded-xl h-12 bg-muted/50 border-none"
103
- placeholder="18"
104
  />
105
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  <div className="space-y-2">
107
- <Label className="font-bold flex items-center gap-2"><MapPin className="h-4 w-4 text-primary" /> {t.location}</Label>
108
  <Input
109
- value={location}
110
- onChange={e => setLocation(e.target.value)}
111
- placeholder={t.location}
112
- required
113
  className="rounded-xl h-12 bg-muted/50 border-none"
114
  />
115
  </div>
116
  </CardContent>
117
  <CardFooter className="p-8 pt-0">
118
- <Button type="submit" className="w-full h-14 rounded-2xl font-black text-lg shadow-xl shadow-primary/20" disabled={isSigningIn}>
119
  {isSigningIn ? <Loader2 className="animate-spin" /> : t.loginAction}
120
  </Button>
121
  </CardFooter>
@@ -168,7 +235,7 @@ export default function LoginPage() {
168
  </TabsContent>
169
 
170
  <TabsContent value="username">
171
- <Card className="radiant-card border-none rounded-[2rem] shadow-2xl">
172
  <form onSubmit={handleUsernameLogin}>
173
  <CardHeader className="pb-2">
174
  <CardTitle className="text-xl font-bold">{t.manual}</CardTitle>
@@ -215,6 +282,16 @@ export default function LoginPage() {
215
  />
216
  </div>
217
  </div>
 
 
 
 
 
 
 
 
 
 
218
  </CardContent>
219
  <CardFooter className="p-6 pt-0">
220
  <Button type="submit" className="w-full h-14 rounded-2xl font-black text-lg shadow-xl shadow-primary/20" disabled={isSigningIn}>
@@ -230,4 +307,4 @@ export default function LoginPage() {
230
  </div>
231
  </div>
232
  );
233
- }
 
1
+
2
  'use client';
3
 
4
  import { Button } from "@/components/ui/button";
5
  import { Header } from "@/components/header";
6
+ import { Loader2, LogIn, MessageSquare, Chrome, UserPlus, MapPin, Calendar, Briefcase, Heart, BookOpen } from "lucide-react";
7
  import { useAuth } from "@/contexts/auth-context";
8
  import { useEffect, useState } from "react";
9
  import { useRouter } from "next/navigation";
10
  import { Input } from "@/components/ui/input";
11
  import { Label } from "@/components/ui/label";
12
+ import { Textarea } from "@/components/ui/textarea";
13
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
14
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
15
  import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
16
  import { useToast } from "@/hooks/use-toast";
 
20
  const { user, userData, loading: authLoading, signInWithGoogle, signInWithUsername, completeProfile } = useAuth();
21
  const { t } = useLanguage();
22
  const [isSigningIn, setIsSigningIn] = useState(false);
23
+
24
+ // Basic Fields
25
  const [username, setUsername] = useState('');
26
  const [password, setPassword] = useState('');
27
  const [age, setAge] = useState('');
28
  const [location, setLocation] = useState('');
29
+
30
+ // Extended Fields for Personalization
31
+ const [bio, setBio] = useState('');
32
+ const [gender, setGender] = useState('');
33
+ const [occupation, setOccupation] = useState('');
34
+ const [interests, setInterests] = useState('');
35
+
36
  const [showCompleteProfile, setShowCompleteProfile] = useState(false);
37
 
38
  const router = useRouter();
 
64
  }
65
  setIsSigningIn(true);
66
  try {
67
+ await signInWithUsername(username, password, parseInt(age), location, {
68
+ bio, gender, occupation, interests
69
+ });
70
  } catch (error) {
71
  console.error(error);
72
  } finally {
 
82
  return;
83
  }
84
  setIsSigningIn(true);
85
+ await completeProfile({
86
+ age: parseInt(age),
87
+ location,
88
+ bio,
89
+ gender,
90
+ occupation,
91
+ interests
92
+ });
93
  setIsSigningIn(false);
94
  };
95
 
 
105
  return (
106
  <div className="flex h-screen w-full flex-col bg-muted/30">
107
  <Header title={t.loginTitle} />
108
+ <div className="flex flex-1 items-center justify-center p-4 pt-20">
109
+ <Card className="w-full max-w-lg radiant-card rounded-[2.5rem] border-none shadow-2xl overflow-hidden overflow-y-auto max-h-[85vh] scrollbar-hide">
110
  <CardHeader className="bg-primary text-primary-foreground p-8">
111
+ <CardTitle className="text-3xl font-black">{t.completeProfile}</CardTitle>
112
+ <CardDescription className="text-primary-foreground/90 font-bold">{t.chooseLogin}</CardDescription>
113
  </CardHeader>
114
  <form onSubmit={handleCompleteProfile}>
115
  <CardContent className="space-y-6 p-8">
116
+ <div className="grid grid-cols-2 gap-4">
117
+ <div className="space-y-2">
118
+ <Label className="font-bold flex items-center gap-2"><Calendar className="h-4 w-4 text-primary" /> {t.age}</Label>
119
+ <Input
120
+ type="number"
121
+ value={age}
122
+ onChange={e => setAge(e.target.value)}
123
+ required
124
+ className="rounded-xl h-12 bg-muted/50 border-none"
125
+ placeholder="18"
126
+ />
127
+ </div>
128
+ <div className="space-y-2">
129
+ <Label className="font-bold flex items-center gap-2"><MapPin className="h-4 w-4 text-primary" /> {t.location}</Label>
130
+ <Input
131
+ value={location}
132
+ onChange={e => setLocation(e.target.value)}
133
+ placeholder={t.location}
134
+ required
135
+ className="rounded-xl h-12 bg-muted/50 border-none"
136
+ />
137
+ </div>
138
+ </div>
139
+
140
  <div className="space-y-2">
141
+ <Label className="font-bold flex items-center gap-2"><Briefcase className="h-4 w-4 text-primary" /> {t.occupation}</Label>
142
  <Input
143
+ value={occupation}
144
+ onChange={e => setOccupation(e.target.value)}
145
+ placeholder={t.occupation}
 
146
  className="rounded-xl h-12 bg-muted/50 border-none"
 
147
  />
148
  </div>
149
+
150
+ <div className="space-y-2">
151
+ <Label className="font-bold">{t.gender}</Label>
152
+ <Select value={gender} onValueChange={setGender}>
153
+ <SelectTrigger className="rounded-xl h-12 bg-muted/50 border-none">
154
+ <SelectValue placeholder={t.gender} />
155
+ </SelectTrigger>
156
+ <SelectContent className="rounded-xl">
157
+ <SelectItem value="male">{t.male}</SelectItem>
158
+ <SelectItem value="female">{t.female}</SelectItem>
159
+ <SelectItem value="other">{t.other}</SelectItem>
160
+ </SelectContent>
161
+ </Select>
162
+ </div>
163
+
164
+ <div className="space-y-2">
165
+ <Label className="font-bold flex items-center gap-2"><BookOpen className="h-4 w-4 text-primary" /> {t.bio}</Label>
166
+ <Textarea
167
+ value={bio}
168
+ onChange={e => setBio(e.target.value)}
169
+ placeholder={t.bioPlaceholder}
170
+ className="rounded-xl bg-muted/50 border-none min-h-[80px]"
171
+ />
172
+ </div>
173
+
174
  <div className="space-y-2">
175
+ <Label className="font-bold flex items-center gap-2"><Heart className="h-4 w-4 text-primary" /> {t.interests}</Label>
176
  <Input
177
+ value={interests}
178
+ onChange={e => setInterests(e.target.value)}
179
+ placeholder={t.interestsPlaceholder}
 
180
  className="rounded-xl h-12 bg-muted/50 border-none"
181
  />
182
  </div>
183
  </CardContent>
184
  <CardFooter className="p-8 pt-0">
185
+ <Button type="submit" className="w-full h-16 rounded-2xl font-black text-xl shadow-xl shadow-primary/20" disabled={isSigningIn}>
186
  {isSigningIn ? <Loader2 className="animate-spin" /> : t.loginAction}
187
  </Button>
188
  </CardFooter>
 
235
  </TabsContent>
236
 
237
  <TabsContent value="username">
238
+ <Card className="radiant-card border-none rounded-[2.5rem] shadow-2xl max-h-[60vh] overflow-y-auto scrollbar-hide">
239
  <form onSubmit={handleUsernameLogin}>
240
  <CardHeader className="pb-2">
241
  <CardTitle className="text-xl font-bold">{t.manual}</CardTitle>
 
282
  />
283
  </div>
284
  </div>
285
+
286
+ <div className="space-y-2">
287
+ <Label className="font-bold">{t.occupation}</Label>
288
+ <Input
289
+ value={occupation}
290
+ onChange={e => setOccupation(e.target.value)}
291
+ placeholder={t.occupation}
292
+ className="rounded-xl h-12 bg-muted/50 border-none"
293
+ />
294
+ </div>
295
  </CardContent>
296
  <CardFooter className="p-6 pt-0">
297
  <Button type="submit" className="w-full h-14 rounded-2xl font-black text-lg shadow-xl shadow-primary/20" disabled={isSigningIn}>
 
307
  </div>
308
  </div>
309
  );
310
+ }
src/app/profile/page.tsx CHANGED
@@ -5,12 +5,14 @@ import { useState, useEffect } from 'react';
5
  import { useAuth } from '@/contexts/auth-context';
6
  import { useRouter } from 'next/navigation';
7
  import { Header } from '@/components/header';
8
- import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from '@/components/ui/card';
9
  import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
10
  import { Button } from '@/components/ui/button';
11
  import { Input } from '@/components/ui/input';
12
  import { Label } from '@/components/ui/label';
13
- import { Loader2, Trash2, AlertTriangle } from 'lucide-react';
 
 
14
  import { useToast } from '@/hooks/use-toast';
15
  import { useLanguage } from '@/contexts/language-context';
16
  import {
@@ -34,6 +36,10 @@ export default function ProfilePage() {
34
  const [displayName, setDisplayName] = useState('');
35
  const [age, setAge] = useState('');
36
  const [location, setLocation] = useState('');
 
 
 
 
37
  const [isSaving, setIsSaving] = useState(false);
38
  const [isDeleting, setIsDeleting] = useState(false);
39
 
@@ -47,6 +53,10 @@ export default function ProfilePage() {
47
  if (userData) {
48
  setAge(userData.age?.toString() || '');
49
  setLocation(userData.location || '');
 
 
 
 
50
  }
51
  }, [user, userData, loading, router]);
52
 
@@ -59,8 +69,12 @@ export default function ProfilePage() {
59
  setIsSaving(true);
60
  await updateUserProfile({
61
  displayName: displayName.trim(),
62
- age: parseInt(age),
63
- location: location.trim()
 
 
 
 
64
  });
65
  setIsSaving(false);
66
  };
@@ -88,77 +102,124 @@ export default function ProfilePage() {
88
  return (
89
  <div className="flex h-screen w-full flex-col bg-background">
90
  <Header title={t.profileTitle} />
91
- <main className="flex-1 overflow-y-auto bg-muted/40 p-4 md:p-8">
92
  <div className="mx-auto max-w-2xl space-y-6">
93
- <Card className="border-border/50 shadow-sm">
94
- <CardHeader>
95
- <CardTitle>{t.settings}</CardTitle>
 
 
 
96
  </CardHeader>
97
- <CardContent className="space-y-6">
98
  <div className="flex items-center gap-4">
99
- <Avatar className="h-20 w-20 border-2 border-primary/10">
100
  <AvatarImage src={user.photoURL!} alt={user.displayName!} />
101
- <AvatarFallback className="text-xl bg-primary/5 text-primary">
102
  {user.displayName?.charAt(0)}
103
  </AvatarFallback>
104
  </Avatar>
105
  <div>
106
- <h3 className="text-xl font-bold">{user.displayName}</h3>
107
- <p className="text-sm text-muted-foreground">{user.email || 'Manual Account'}</p>
108
  </div>
109
  </div>
110
- <div className="space-y-4">
 
 
 
 
 
 
111
  <div className="space-y-2">
112
- <Label htmlFor="displayName">{t.username}</Label>
113
- <Input id="displayName" value={displayName} onChange={(e) => setDisplayName(e.target.value)} />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  </div>
115
- <div className="grid grid-cols-2 gap-4">
 
116
  <div className="space-y-2">
117
- <Label htmlFor="age">{t.age}</Label>
118
- <Input id="age" type="number" value={age} onChange={(e) => setAge(e.target.value)} />
119
  </div>
120
  <div className="space-y-2">
121
- <Label htmlFor="location">{t.location}</Label>
122
- <Input id="location" value={location} onChange={(e) => setLocation(e.target.value)} />
123
  </div>
124
  </div>
 
 
 
 
 
 
 
 
 
 
 
125
  </div>
126
  </CardContent>
127
- <CardFooter className="border-t px-6 py-4 bg-muted/20">
128
- <Button onClick={handleSave} disabled={isSaving} className="rounded-xl px-8">
129
  {isSaving && <Loader2 className="mx-2 h-4 w-4 animate-spin" />}
130
  {t.saveChanges}
131
  </Button>
132
  </CardFooter>
133
  </Card>
134
 
135
- <Card className="border-destructive/20 shadow-sm overflow-hidden">
136
  <CardHeader className="bg-destructive/5">
137
  <div className="flex items-center gap-2 text-destructive">
138
  <AlertTriangle className="h-5 w-5" />
139
- <CardTitle className="text-lg">{t.dangerZone}</CardTitle>
140
  </div>
141
  </CardHeader>
142
  <CardContent className="pt-6">
143
  <div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
144
  <div className="space-y-1">
145
- <h4 className="font-bold">{t.deleteAccount}</h4>
146
  <p className="text-sm text-muted-foreground">{t.deleteConfirmDesc}</p>
147
  </div>
148
  <AlertDialog>
149
  <AlertDialogTrigger asChild>
150
- <Button variant="destructive" className="rounded-xl flex items-center gap-2">
151
  <Trash2 className="h-4 w-4" /> {t.deleteAccount}
152
  </Button>
153
  </AlertDialogTrigger>
154
- <AlertDialogContent className="rounded-2xl">
155
  <AlertDialogHeader>
156
- <AlertDialogTitle>{t.deleteConfirmTitle}</AlertDialogTitle>
157
- <AlertDialogDescription>{t.deleteConfirmDesc}</AlertDialogDescription>
158
  </AlertDialogHeader>
159
- <AlertDialogFooter>
160
- <AlertDialogCancel>{t.cancel}</AlertDialogCancel>
161
- <AlertDialogAction onClick={handleDeleteAccount} className="bg-destructive hover:bg-destructive/90" disabled={isDeleting}>
162
  {t.confirmDelete}
163
  </AlertDialogAction>
164
  </AlertDialogFooter>
 
5
  import { useAuth } from '@/contexts/auth-context';
6
  import { useRouter } from 'next/navigation';
7
  import { Header } from '@/components/header';
8
+ import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card';
9
  import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
10
  import { Button } from '@/components/ui/button';
11
  import { Input } from '@/components/ui/input';
12
  import { Label } from '@/components/ui/label';
13
+ import { Textarea } from '@/components/ui/textarea';
14
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
15
+ import { Loader2, Trash2, AlertTriangle, User, Briefcase, Heart, BookOpen } from 'lucide-react';
16
  import { useToast } from '@/hooks/use-toast';
17
  import { useLanguage } from '@/contexts/language-context';
18
  import {
 
36
  const [displayName, setDisplayName] = useState('');
37
  const [age, setAge] = useState('');
38
  const [location, setLocation] = useState('');
39
+ const [bio, setBio] = useState('');
40
+ const [gender, setGender] = useState('');
41
+ const [occupation, setOccupation] = useState('');
42
+ const [interests, setInterests] = useState('');
43
  const [isSaving, setIsSaving] = useState(false);
44
  const [isDeleting, setIsDeleting] = useState(false);
45
 
 
53
  if (userData) {
54
  setAge(userData.age?.toString() || '');
55
  setLocation(userData.location || '');
56
+ setBio(userData.bio || '');
57
+ setGender(userData.gender || '');
58
+ setOccupation(userData.occupation || '');
59
+ setInterests(userData.interests || '');
60
  }
61
  }, [user, userData, loading, router]);
62
 
 
69
  setIsSaving(true);
70
  await updateUserProfile({
71
  displayName: displayName.trim(),
72
+ age: parseInt(age) || 0,
73
+ location: location.trim(),
74
+ bio: bio.trim(),
75
+ gender,
76
+ occupation: occupation.trim(),
77
+ interests: interests.trim()
78
  });
79
  setIsSaving(false);
80
  };
 
102
  return (
103
  <div className="flex h-screen w-full flex-col bg-background">
104
  <Header title={t.profileTitle} />
105
+ <main className="flex-1 overflow-y-auto bg-muted/40 p-4 md:p-8 pt-20">
106
  <div className="mx-auto max-w-2xl space-y-6">
107
+ <Card className="border-border/50 shadow-sm rounded-[2rem] overflow-hidden">
108
+ <CardHeader className="bg-primary/5 border-b border-primary/10">
109
+ <CardTitle className="flex items-center gap-2">
110
+ <User className="h-5 w-5 text-primary" />
111
+ {t.settings}
112
+ </CardTitle>
113
  </CardHeader>
114
+ <CardContent className="space-y-6 pt-6">
115
  <div className="flex items-center gap-4">
116
+ <Avatar className="h-24 w-24 border-4 border-primary/10 shadow-lg">
117
  <AvatarImage src={user.photoURL!} alt={user.displayName!} />
118
+ <AvatarFallback className="text-2xl bg-primary/5 text-primary font-bold">
119
  {user.displayName?.charAt(0)}
120
  </AvatarFallback>
121
  </Avatar>
122
  <div>
123
+ <h3 className="text-2xl font-black tracking-tight">{user.displayName}</h3>
124
+ <p className="text-sm text-muted-foreground font-medium">{user.email || 'Manual Account'}</p>
125
  </div>
126
  </div>
127
+
128
+ <div className="space-y-5">
129
+ <div className="space-y-2">
130
+ <Label htmlFor="displayName" className="font-bold">{t.username}</Label>
131
+ <Input id="displayName" value={displayName} onChange={(e) => setDisplayName(e.target.value)} className="rounded-xl bg-background/50" />
132
+ </div>
133
+
134
  <div className="space-y-2">
135
+ <Label htmlFor="bio" className="font-bold flex items-center gap-2"><BookOpen className="h-4 w-4" /> {t.bio}</Label>
136
+ <Textarea
137
+ id="bio"
138
+ placeholder={t.bioPlaceholder}
139
+ value={bio}
140
+ onChange={(e) => setBio(e.target.value)}
141
+ className="rounded-xl bg-background/50 min-h-[100px]"
142
+ />
143
+ </div>
144
+
145
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
146
+ <div className="space-y-2">
147
+ <Label htmlFor="age" className="font-bold">{t.age}</Label>
148
+ <Input id="age" type="number" value={age} onChange={(e) => setAge(e.target.value)} className="rounded-xl bg-background/50" />
149
+ </div>
150
+ <div className="space-y-2">
151
+ <Label htmlFor="gender" className="font-bold">{t.gender}</Label>
152
+ <Select value={gender} onValueChange={setGender}>
153
+ <SelectTrigger className="rounded-xl bg-background/50">
154
+ <SelectValue placeholder={t.gender} />
155
+ </SelectTrigger>
156
+ <SelectContent className="rounded-xl">
157
+ <SelectItem value="male">{t.male}</SelectItem>
158
+ <SelectItem value="female">{t.female}</SelectItem>
159
+ <SelectItem value="other">{t.other}</SelectItem>
160
+ </SelectContent>
161
+ </Select>
162
+ </div>
163
  </div>
164
+
165
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
166
  <div className="space-y-2">
167
+ <Label htmlFor="occupation" className="font-bold flex items-center gap-2"><Briefcase className="h-4 w-4" /> {t.occupation}</Label>
168
+ <Input id="occupation" value={occupation} onChange={(e) => setOccupation(e.target.value)} className="rounded-xl bg-background/50" />
169
  </div>
170
  <div className="space-y-2">
171
+ <Label htmlFor="location" className="font-bold">{t.location}</Label>
172
+ <Input id="location" value={location} onChange={(e) => setLocation(e.target.value)} className="rounded-xl bg-background/50" />
173
  </div>
174
  </div>
175
+
176
+ <div className="space-y-2">
177
+ <Label htmlFor="interests" className="font-bold flex items-center gap-2"><Heart className="h-4 w-4" /> {t.interests}</Label>
178
+ <Input
179
+ id="interests"
180
+ placeholder={t.interestsPlaceholder}
181
+ value={interests}
182
+ onChange={(e) => setInterests(e.target.value)}
183
+ className="rounded-xl bg-background/50"
184
+ />
185
+ </div>
186
  </div>
187
  </CardContent>
188
+ <CardFooter className="border-t px-6 py-6 bg-muted/20">
189
+ <Button onClick={handleSave} disabled={isSaving} className="w-full md:w-auto rounded-xl px-12 font-bold h-12 shadow-lg shadow-primary/20">
190
  {isSaving && <Loader2 className="mx-2 h-4 w-4 animate-spin" />}
191
  {t.saveChanges}
192
  </Button>
193
  </CardFooter>
194
  </Card>
195
 
196
+ <Card className="border-destructive/20 shadow-sm rounded-[2rem] overflow-hidden">
197
  <CardHeader className="bg-destructive/5">
198
  <div className="flex items-center gap-2 text-destructive">
199
  <AlertTriangle className="h-5 w-5" />
200
+ <CardTitle className="text-lg font-bold">{t.dangerZone}</CardTitle>
201
  </div>
202
  </CardHeader>
203
  <CardContent className="pt-6">
204
  <div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
205
  <div className="space-y-1">
206
+ <h4 className="font-bold text-destructive">{t.deleteAccount}</h4>
207
  <p className="text-sm text-muted-foreground">{t.deleteConfirmDesc}</p>
208
  </div>
209
  <AlertDialog>
210
  <AlertDialogTrigger asChild>
211
+ <Button variant="destructive" className="rounded-xl flex items-center gap-2 px-6 h-12 font-bold">
212
  <Trash2 className="h-4 w-4" /> {t.deleteAccount}
213
  </Button>
214
  </AlertDialogTrigger>
215
+ <AlertDialogContent className="rounded-3xl border-none radiant-glass p-8">
216
  <AlertDialogHeader>
217
+ <AlertDialogTitle className="text-2xl font-black">{t.deleteConfirmTitle}</AlertDialogTitle>
218
+ <AlertDialogDescription className="text-base font-medium">{t.deleteConfirmDesc}</AlertDialogDescription>
219
  </AlertDialogHeader>
220
+ <AlertDialogFooter className="mt-6 gap-3">
221
+ <AlertDialogCancel className="rounded-xl h-12 font-bold">{t.cancel}</AlertDialogCancel>
222
+ <AlertDialogAction onClick={handleDeleteAccount} className="bg-destructive hover:bg-destructive/90 rounded-xl h-12 font-bold px-8" disabled={isDeleting}>
223
  {t.confirmDelete}
224
  </AlertDialogAction>
225
  </AlertDialogFooter>
src/contexts/auth-context.tsx CHANGED
@@ -7,19 +7,16 @@ import { auth, database } from '@/firebase/client';
7
  import {
8
  onAuthStateChanged,
9
  signInWithPopup,
10
- signInWithRedirect,
11
- getRedirectResult,
12
  GoogleAuthProvider,
13
  signOut as firebaseSignOut,
14
  updateProfile,
15
- signInWithCredential,
16
  signInWithEmailAndPassword,
17
  createUserWithEmailAndPassword,
18
  deleteUser
19
  } from 'firebase/auth';
20
  import { ref, set, get, update, remove } from 'firebase/database';
21
  import { useToast } from '@/hooks/use-toast';
22
- import { Loader2, ShieldCheck } from 'lucide-react';
23
 
24
  export interface UserMetadata {
25
  age: number;
@@ -28,6 +25,10 @@ export interface UserMetadata {
28
  displayName: string;
29
  email: string;
30
  photoURL: string;
 
 
 
 
31
  }
32
 
33
  interface AuthContextType {
@@ -35,17 +36,15 @@ interface AuthContextType {
35
  userData: UserMetadata | null;
36
  loading: boolean;
37
  signInWithGoogle: () => Promise<void>;
38
- signInWithUsername: (username: string, pass: string, age: number, location: string) => Promise<void>;
39
  signOut: () => Promise<void>;
40
- updateUserProfile: (data: { displayName: string, age?: number, location?: string }) => Promise<void>;
41
  deleteUserAccount: () => Promise<void>;
42
- completeProfile: (age: number, location: string) => Promise<void>;
43
  }
44
 
45
  const AuthContext = createContext<AuthContextType | undefined>(undefined);
46
 
47
- const GOOGLE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID;
48
-
49
  export const AuthProvider = ({ children }: { children: ReactNode }) => {
50
  const [user, setUser] = useState<User | null>(null);
51
  const [userData, setUserData] = useState<UserMetadata | null>(null);
@@ -76,15 +75,19 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
76
  return () => unsubscribe();
77
  }, []);
78
 
79
- const handleNewUser = async (user: User, data: { age: number, location: string, customName?: string }) => {
80
  const userRef = ref(database, 'users/' + user.uid);
81
  const payload: UserMetadata = {
82
  displayName: data.customName || user.displayName || 'مستخدم جديد',
83
  email: user.email || '',
84
  photoURL: user.photoURL || `https://api.dicebear.com/7.x/avataaars/svg?seed=${user.uid}`,
85
  createdAt: new Date().toISOString(),
86
- age: data.age,
87
- location: data.location
 
 
 
 
88
  };
89
  await set(userRef, payload);
90
  if (data.customName) {
@@ -97,11 +100,9 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
97
  const provider = new GoogleAuthProvider();
98
  try {
99
  const result = await signInWithPopup(auth, provider);
100
- // Check if user already exists in DB
101
  const userRef = ref(database, 'users/' + result.user.uid);
102
  const snapshot = await get(userRef);
103
  if (!snapshot.exists()) {
104
- // We will need a second step in the UI for new Google users to fill age/location
105
  toast({ title: "يرجى إكمال بياناتك للمتابعة" });
106
  } else {
107
  setUserData(snapshot.val());
@@ -113,16 +114,16 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
113
  }
114
  };
115
 
116
- const signInWithUsername = async (username: string, pass: string, age: number, location: string) => {
117
  const fakeEmail = `${username.toLowerCase().trim()}@proto.chat`;
118
  try {
119
  setLoading(true);
120
  const result = await signInWithEmailAndPassword(auth, fakeEmail, pass);
121
  await fetchUserData(result.user.uid);
122
  } catch (error: any) {
123
- if (error.code === 'auth/user-not-found' || error.code === 'auth/invalid-credential') {
124
  const result = await createUserWithEmailAndPassword(auth, fakeEmail, pass);
125
- await handleNewUser(result.user, { age, location, customName: username });
126
  } else {
127
  toast({ title: "خطأ في تسجيل الدخول", variant: "destructive" });
128
  }
@@ -131,19 +132,20 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
131
  }
132
  };
133
 
134
- const completeProfile = async (age: number, location: string) => {
135
  if (!user) return;
136
  const userRef = ref(database, 'users/' + user.uid);
 
137
  const newData = {
138
- age,
139
- location,
140
- displayName: user.displayName || 'مستخدم',
141
  email: user.email || '',
142
  photoURL: user.photoURL || `https://api.dicebear.com/7.x/avataaars/svg?seed=${user.uid}`,
143
- createdAt: new Date().toISOString(),
144
  };
145
  await set(userRef, newData);
146
- setUserData(newData);
147
  };
148
 
149
  const signOut = async () => {
@@ -152,9 +154,11 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
152
  setUserData(null);
153
  };
154
 
155
- const updateUserProfile = async (data: { displayName: string, age?: number, location?: string }) => {
156
  if (!user) return;
157
- await updateProfile(user, { displayName: data.displayName });
 
 
158
  const userRef = ref(database, 'users/' + user.uid);
159
  await update(userRef, data);
160
  await fetchUserData(user.uid);
 
7
  import {
8
  onAuthStateChanged,
9
  signInWithPopup,
 
 
10
  GoogleAuthProvider,
11
  signOut as firebaseSignOut,
12
  updateProfile,
 
13
  signInWithEmailAndPassword,
14
  createUserWithEmailAndPassword,
15
  deleteUser
16
  } from 'firebase/auth';
17
  import { ref, set, get, update, remove } from 'firebase/database';
18
  import { useToast } from '@/hooks/use-toast';
19
+ import { Loader2 } from 'lucide-react';
20
 
21
  export interface UserMetadata {
22
  age: number;
 
25
  displayName: string;
26
  email: string;
27
  photoURL: string;
28
+ bio?: string;
29
+ gender?: string;
30
+ occupation?: string;
31
+ interests?: string;
32
  }
33
 
34
  interface AuthContextType {
 
36
  userData: UserMetadata | null;
37
  loading: boolean;
38
  signInWithGoogle: () => Promise<void>;
39
+ signInWithUsername: (username: string, pass: string, age: number, location: string, extra?: Partial<UserMetadata>) => Promise<void>;
40
  signOut: () => Promise<void>;
41
+ updateUserProfile: (data: Partial<UserMetadata>) => Promise<void>;
42
  deleteUserAccount: () => Promise<void>;
43
+ completeProfile: (data: Partial<UserMetadata>) => Promise<void>;
44
  }
45
 
46
  const AuthContext = createContext<AuthContextType | undefined>(undefined);
47
 
 
 
48
  export const AuthProvider = ({ children }: { children: ReactNode }) => {
49
  const [user, setUser] = useState<User | null>(null);
50
  const [userData, setUserData] = useState<UserMetadata | null>(null);
 
75
  return () => unsubscribe();
76
  }, []);
77
 
78
+ const handleNewUser = async (user: User, data: Partial<UserMetadata> & { customName?: string }) => {
79
  const userRef = ref(database, 'users/' + user.uid);
80
  const payload: UserMetadata = {
81
  displayName: data.customName || user.displayName || 'مستخدم جديد',
82
  email: user.email || '',
83
  photoURL: user.photoURL || `https://api.dicebear.com/7.x/avataaars/svg?seed=${user.uid}`,
84
  createdAt: new Date().toISOString(),
85
+ age: data.age || 18,
86
+ location: data.location || '',
87
+ bio: data.bio || '',
88
+ gender: data.gender || '',
89
+ occupation: data.occupation || '',
90
+ interests: data.interests || ''
91
  };
92
  await set(userRef, payload);
93
  if (data.customName) {
 
100
  const provider = new GoogleAuthProvider();
101
  try {
102
  const result = await signInWithPopup(auth, provider);
 
103
  const userRef = ref(database, 'users/' + result.user.uid);
104
  const snapshot = await get(userRef);
105
  if (!snapshot.exists()) {
 
106
  toast({ title: "يرجى إكمال بياناتك للمتابعة" });
107
  } else {
108
  setUserData(snapshot.val());
 
114
  }
115
  };
116
 
117
+ const signInWithUsername = async (username: string, pass: string, age: number, location: string, extra?: Partial<UserMetadata>) => {
118
  const fakeEmail = `${username.toLowerCase().trim()}@proto.chat`;
119
  try {
120
  setLoading(true);
121
  const result = await signInWithEmailAndPassword(auth, fakeEmail, pass);
122
  await fetchUserData(result.user.uid);
123
  } catch (error: any) {
124
+ if (error.code === 'auth/user-not-found' || error.code === 'auth/invalid-credential' || error.code === 'auth/invalid-email') {
125
  const result = await createUserWithEmailAndPassword(auth, fakeEmail, pass);
126
+ await handleNewUser(result.user, { age, location, customName: username, ...extra });
127
  } else {
128
  toast({ title: "خطأ في تسجيل الدخول", variant: "destructive" });
129
  }
 
132
  }
133
  };
134
 
135
+ const completeProfile = async (data: Partial<UserMetadata>) => {
136
  if (!user) return;
137
  const userRef = ref(database, 'users/' + user.uid);
138
+ const existingData = userData || {};
139
  const newData = {
140
+ ...existingData,
141
+ ...data,
142
+ displayName: data.displayName || user.displayName || 'مستخدم',
143
  email: user.email || '',
144
  photoURL: user.photoURL || `https://api.dicebear.com/7.x/avataaars/svg?seed=${user.uid}`,
145
+ createdAt: existingData.createdAt || new Date().toISOString(),
146
  };
147
  await set(userRef, newData);
148
+ setUserData(newData as UserMetadata);
149
  };
150
 
151
  const signOut = async () => {
 
154
  setUserData(null);
155
  };
156
 
157
+ const updateUserProfile = async (data: Partial<UserMetadata>) => {
158
  if (!user) return;
159
+ if (data.displayName) {
160
+ await updateProfile(user, { displayName: data.displayName });
161
+ }
162
  const userRef = ref(database, 'users/' + user.uid);
163
  await update(userRef, data);
164
  await fetchUserData(user.uid);
src/lib/translations.ts CHANGED
@@ -71,6 +71,15 @@ export const translations = {
71
  primaryEngine: 'الأساسي (Gemini)',
72
  fallbackEngine: 'الاحتياطي (Groq)',
73
  advancedEngine: 'المتقدم (OpenRouter)',
 
 
 
 
 
 
 
 
 
74
  },
75
  en: {
76
  appTitle: 'AvadoraWorld',
@@ -141,5 +150,14 @@ export const translations = {
141
  primaryEngine: 'Primary (Gemini)',
142
  fallbackEngine: 'Fallback (Groq)',
143
  advancedEngine: 'Advanced (OpenRouter)',
 
 
 
 
 
 
 
 
 
144
  }
145
  };
 
71
  primaryEngine: 'الأساسي (Gemini)',
72
  fallbackEngine: 'الاحتياطي (Groq)',
73
  advancedEngine: 'المتقدم (OpenRouter)',
74
+ bio: 'نبذة شخصية',
75
+ gender: 'الجنس',
76
+ occupation: 'المهنة',
77
+ interests: 'الاهتمامات (افصل بينها بفاصلة)',
78
+ interestsPlaceholder: 'فلسفة، تقنية، فن، رياضة...',
79
+ male: 'ذكر',
80
+ female: 'أنثى',
81
+ other: 'آخر',
82
+ bioPlaceholder: 'أخبرنا عن فلسفتك في الحياة...',
83
  },
84
  en: {
85
  appTitle: 'AvadoraWorld',
 
150
  primaryEngine: 'Primary (Gemini)',
151
  fallbackEngine: 'Fallback (Groq)',
152
  advancedEngine: 'Advanced (OpenRouter)',
153
+ bio: 'Bio',
154
+ gender: 'Gender',
155
+ occupation: 'Occupation',
156
+ interests: 'Interests (comma separated)',
157
+ interestsPlaceholder: 'Philosophy, Tech, Art, Sports...',
158
+ male: 'Male',
159
+ female: 'Female',
160
+ other: 'Other',
161
+ bioPlaceholder: 'Tell us about your philosophy...',
162
  }
163
  };