SarahXia0405 commited on
Commit
24e6c4c
·
verified ·
1 Parent(s): 6546430

Update web/src/components/ProfileEditor.tsx

Browse files
Files changed (1) hide show
  1. web/src/components/ProfileEditor.tsx +48 -30
web/src/components/ProfileEditor.tsx CHANGED
@@ -15,27 +15,46 @@ interface ProfileEditorProps {
15
  }
16
 
17
  export function ProfileEditor({ user, onSave, onClose }: ProfileEditorProps) {
18
- const [name, setName] = useState(user.name);
19
- const [email, setEmail] = useState(user.email);
20
 
21
- // these can remain local-only for now
22
- const [studentId, setStudentId] = useState("S12345678");
23
- const [department, setDepartment] = useState("Computer Science");
24
- const [year, setYear] = useState("3rd Year");
25
- const [major, setMajor] = useState("Artificial Intelligence");
26
 
27
- // ✅ IMPORTANT: initialize from user.bio (so it reflects Clare-generated bio)
28
  const [bio, setBio] = useState(user.bio ?? "");
29
 
30
- const [photoPreview, setPhotoPreview] = useState<string | null>(null);
 
 
 
31
  const fileInputRef = useRef<HTMLInputElement>(null);
32
 
33
- // If user changes while dialog is open, keep fields in sync
34
  useEffect(() => {
35
- setName(user.name);
36
- setEmail(user.email);
 
 
 
 
37
  setBio(user.bio ?? "");
38
- }, [user.name, user.email, user.bio]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  const handleSave = () => {
41
  if (!name.trim() || !email.trim()) {
@@ -47,7 +66,14 @@ export function ProfileEditor({ user, onSave, onClose }: ProfileEditorProps) {
47
  ...user,
48
  name: name.trim(),
49
  email: email.trim(),
50
- bio: (bio ?? "").slice(0, 200), // enforce 200 chars UI limit
 
 
 
 
 
 
 
51
  };
52
 
53
  onSave(next);
@@ -76,9 +102,7 @@ export function ProfileEditor({ user, onSave, onClose }: ProfileEditorProps) {
76
  reader.readAsDataURL(file);
77
  };
78
 
79
- const handleChangePhotoClick = () => {
80
- fileInputRef.current?.click();
81
- };
82
 
83
  return (
84
  <Dialog
@@ -91,14 +115,7 @@ export function ProfileEditor({ user, onSave, onClose }: ProfileEditorProps) {
91
  className="sm:max-w-[800px] p-0 gap-0 max-h-[90vh] overflow-hidden"
92
  style={{ zIndex: 1001, maxWidth: "800px", width: "800px" }}
93
  overlayClassName="!top-16 !left-0 !right-0 !bottom-0 !z-[99]"
94
- overlayStyle={{
95
- top: "64px",
96
- left: 0,
97
- right: 0,
98
- bottom: 0,
99
- zIndex: 99,
100
- position: "fixed",
101
- }}
102
  >
103
  <div className="flex flex-col max-h-[90vh]">
104
  {/* Header */}
@@ -114,7 +131,7 @@ export function ProfileEditor({ user, onSave, onClose }: ProfileEditorProps) {
114
  {photoPreview ? (
115
  <img src={photoPreview} alt="Profile" className="w-full h-full object-cover" />
116
  ) : (
117
- name.charAt(0).toUpperCase()
118
  )}
119
  </div>
120
  <div>
@@ -182,9 +199,9 @@ export function ProfileEditor({ user, onSave, onClose }: ProfileEditorProps) {
182
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
183
  <div className="space-y-2">
184
  <Label htmlFor="edit-year">Year Level</Label>
185
- <Select value={year} onValueChange={setYear}>
186
  <SelectTrigger id="edit-year">
187
- <SelectValue />
188
  </SelectTrigger>
189
  <SelectContent>
190
  <SelectItem value="1st Year">1st Year</SelectItem>
@@ -227,7 +244,7 @@ export function ProfileEditor({ user, onSave, onClose }: ProfileEditorProps) {
227
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
228
  <div className="space-y-2">
229
  <Label htmlFor="edit-learning-style">Preferred Learning Style</Label>
230
- <Select defaultValue="visual">
231
  <SelectTrigger id="edit-learning-style">
232
  <SelectValue />
233
  </SelectTrigger>
@@ -239,9 +256,10 @@ export function ProfileEditor({ user, onSave, onClose }: ProfileEditorProps) {
239
  </SelectContent>
240
  </Select>
241
  </div>
 
242
  <div className="space-y-2">
243
  <Label htmlFor="edit-pace">Learning Pace</Label>
244
- <Select defaultValue="moderate">
245
  <SelectTrigger id="edit-pace">
246
  <SelectValue />
247
  </SelectTrigger>
 
15
  }
16
 
17
  export function ProfileEditor({ user, onSave, onClose }: ProfileEditorProps) {
18
+ const [name, setName] = useState(user.name ?? "");
19
+ const [email, setEmail] = useState(user.email ?? "");
20
 
21
+ const [studentId, setStudentId] = useState(user.studentId ?? "");
22
+ const [department, setDepartment] = useState(user.department ?? "");
23
+ const [yearLevel, setYearLevel] = useState(user.yearLevel ?? "");
24
+ const [major, setMajor] = useState(user.major ?? "");
 
25
 
 
26
  const [bio, setBio] = useState(user.bio ?? "");
27
 
28
+ const [learningStyle, setLearningStyle] = useState(user.learningStyle ?? "visual");
29
+ const [learningPace, setLearningPace] = useState(user.learningPace ?? "moderate");
30
+
31
+ const [photoPreview, setPhotoPreview] = useState<string | null>(user.avatarUrl ?? null);
32
  const fileInputRef = useRef<HTMLInputElement>(null);
33
 
34
+ // keep in sync if user changes while dialog is open
35
  useEffect(() => {
36
+ setName(user.name ?? "");
37
+ setEmail(user.email ?? "");
38
+ setStudentId(user.studentId ?? "");
39
+ setDepartment(user.department ?? "");
40
+ setYearLevel(user.yearLevel ?? "");
41
+ setMajor(user.major ?? "");
42
  setBio(user.bio ?? "");
43
+ setLearningStyle(user.learningStyle ?? "visual");
44
+ setLearningPace(user.learningPace ?? "moderate");
45
+ setPhotoPreview(user.avatarUrl ?? null);
46
+ }, [
47
+ user.name,
48
+ user.email,
49
+ user.studentId,
50
+ user.department,
51
+ user.yearLevel,
52
+ user.major,
53
+ user.bio,
54
+ user.learningStyle,
55
+ user.learningPace,
56
+ user.avatarUrl,
57
+ ]);
58
 
59
  const handleSave = () => {
60
  if (!name.trim() || !email.trim()) {
 
66
  ...user,
67
  name: name.trim(),
68
  email: email.trim(),
69
+ studentId: studentId.trim() || undefined,
70
+ department: department.trim() || undefined,
71
+ yearLevel: yearLevel || undefined,
72
+ major: major.trim() || undefined,
73
+ bio: (bio ?? "").slice(0, 200) || undefined,
74
+ learningStyle: learningStyle || undefined,
75
+ learningPace: learningPace || undefined,
76
+ avatarUrl: photoPreview || undefined,
77
  };
78
 
79
  onSave(next);
 
102
  reader.readAsDataURL(file);
103
  };
104
 
105
+ const handleChangePhotoClick = () => fileInputRef.current?.click();
 
 
106
 
107
  return (
108
  <Dialog
 
115
  className="sm:max-w-[800px] p-0 gap-0 max-h-[90vh] overflow-hidden"
116
  style={{ zIndex: 1001, maxWidth: "800px", width: "800px" }}
117
  overlayClassName="!top-16 !left-0 !right-0 !bottom-0 !z-[99]"
118
+ overlayStyle={{ top: "64px", left: 0, right: 0, bottom: 0, zIndex: 99, position: "fixed" }}
 
 
 
 
 
 
 
119
  >
120
  <div className="flex flex-col max-h-[90vh]">
121
  {/* Header */}
 
131
  {photoPreview ? (
132
  <img src={photoPreview} alt="Profile" className="w-full h-full object-cover" />
133
  ) : (
134
+ (name?.charAt(0) || "U").toUpperCase()
135
  )}
136
  </div>
137
  <div>
 
199
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
200
  <div className="space-y-2">
201
  <Label htmlFor="edit-year">Year Level</Label>
202
+ <Select value={yearLevel} onValueChange={setYearLevel}>
203
  <SelectTrigger id="edit-year">
204
+ <SelectValue placeholder="Select year level" />
205
  </SelectTrigger>
206
  <SelectContent>
207
  <SelectItem value="1st Year">1st Year</SelectItem>
 
244
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
245
  <div className="space-y-2">
246
  <Label htmlFor="edit-learning-style">Preferred Learning Style</Label>
247
+ <Select value={learningStyle} onValueChange={setLearningStyle}>
248
  <SelectTrigger id="edit-learning-style">
249
  <SelectValue />
250
  </SelectTrigger>
 
256
  </SelectContent>
257
  </Select>
258
  </div>
259
+
260
  <div className="space-y-2">
261
  <Label htmlFor="edit-pace">Learning Pace</Label>
262
+ <Select value={learningPace} onValueChange={setLearningPace}>
263
  <SelectTrigger id="edit-pace">
264
  <SelectValue />
265
  </SelectTrigger>