Saandraahh commited on
Commit
411b8bd
·
unverified ·
1 Parent(s): ea9ca44

Update ProfileTab.jsx

Browse files

Key Changes Applied:

TagInput Component: Added for cleaner management of comma-separated lists (Skills, Certifications, Languages).
Enhanced Styling: Inputs now have nicer borders, background colors, and focus states.
Projects Section: Full support for adding, editing, and removing projects with TagInput for technologies.
Education Section: Updated to match the new styling and structure.

Files changed (1) hide show
  1. src/components/ProfileTab.jsx +267 -43
src/components/ProfileTab.jsx CHANGED
@@ -1,12 +1,93 @@
1
- import React from 'react';
2
  import { motion, AnimatePresence } from 'framer-motion';
3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  const ProfileTab = ({
5
  profileData,
6
  isEditing,
7
  handleProfileChange,
8
  handleExperienceChange,
9
  handleAddExperience,
 
 
10
  showFullProfile,
11
  }) => {
12
  if (!profileData) return null;
@@ -16,10 +97,8 @@ const ProfileTab = ({
16
  border: '1px solid rgba(251, 191, 36, 0.3)',
17
  backgroundColor: 'rgba(255,255,255,0.1)', color: 'white'
18
  };
19
-
20
  const labelStyles = { display: 'block', marginBottom: '0.5rem', color: '#d1d5db' };
21
-
22
- // --- Styles for checkboxes ---
23
  const checkboxLabelStyles = { display: 'flex', alignItems: 'center', gap: '0.5rem', color: '#d1d5db' };
24
  const checkboxStyles = { width: '1.15em', height: '1.15em', accentColor: '#FBBF24' };
25
 
@@ -29,18 +108,18 @@ const ProfileTab = ({
29
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '1.5rem' }}>
30
  <div>
31
  <label style={labelStyles}>Full Name</label>
32
- {isEditing ? ( <input type="text" name="full_name" value={profileData?.full_name || ''} onChange={handleProfileChange} style={inputStyles} placeholder="e.g., John Doe" /> ) : ( <p>{profileData?.full_name || 'Not set'}</p> )}
33
  </div>
34
  <div>
35
  <label style={labelStyles}>Headline</label>
36
- {isEditing ? ( <input type="text" name="headline" value={profileData?.headline || ''} onChange={handleProfileChange} style={inputStyles} placeholder="e.g., Senior Software Engineer"/> ) : ( <p>{profileData?.headline || 'Not set'}</p> )}
37
  </div>
38
  </div>
39
 
40
  {/* Summary */}
41
  <div>
42
  <label style={labelStyles}>Summary</label>
43
- {isEditing ? ( <textarea name="summary" value={profileData?.summary || ''} onChange={handleProfileChange} rows="4" style={inputStyles} placeholder="Tell us about yourself..."/> ) : ( <p>{profileData?.summary || 'Not set'}</p> )}
44
  </div>
45
 
46
  {/* Extended Profile Fields */}
@@ -50,54 +129,83 @@ const ProfileTab = ({
50
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '1.5rem', marginTop: '1.5rem' }}>
51
  <div>
52
  <label style={labelStyles}>Email</label>
53
- {isEditing ? ( <input type="email" name="email" value={profileData?.email || ''} onChange={handleProfileChange} style={inputStyles} /> ) : ( <p>{profileData?.email || 'Not set'}</p> )}
54
  </div>
55
  <div>
56
  <label style={labelStyles}>Phone</label>
57
- {isEditing ? ( <input type="tel" name="phone" value={profileData?.phone || ''} onChange={handleProfileChange} style={inputStyles} /> ) : ( <p>{profileData?.phone || 'Not set'}</p> )}
58
  </div>
59
- <div>
60
  <label style={labelStyles}>Address</label>
61
- {isEditing ? ( <input type="text" name="address" value={profileData?.address || ''} onChange={handleProfileChange} style={inputStyles} /> ) : ( <p>{profileData?.address || 'Not set'}</p> )}
62
  </div>
63
  <div>
64
  <label style={labelStyles}>Current Position</label>
65
- {isEditing ? ( <input type="text" name="current_position" value={profileData?.current_position || ''} onChange={handleProfileChange} style={inputStyles} /> ) : ( <p>{profileData?.current_position || 'Not set'}</p> )}
66
  </div>
67
  <div>
68
  <label style={labelStyles}>Years of Experience</label>
69
- {isEditing ? ( <input type="text" name="experience_years" value={profileData?.experience_years || ''} onChange={handleProfileChange} style={inputStyles} /> ) : ( <p>{profileData?.experience_years || 'Not set'}</p> )}
70
  </div>
71
  <div>
72
  <label style={labelStyles}>Desired Salary</label>
73
- {isEditing ? ( <input type="text" name="desired_salary" value={profileData?.desired_salary || ''} onChange={handleProfileChange} style={inputStyles} /> ) : ( <p>{profileData?.desired_salary || 'Not set'}</p> )}
74
  </div>
75
  <div>
76
  <label style={labelStyles}>LinkedIn</label>
77
- {isEditing ? ( <input type="url" name="linkedin" value={profileData?.linkedin || ''} onChange={handleProfileChange} style={inputStyles} /> ) : ( <a href={profileData?.linkedin || '#'} target="_blank" rel="noreferrer" style={{color: '#93C5FD'}}>{profileData?.linkedin || 'Not set'}</a> )}
78
  </div>
79
  <div>
80
  <label style={labelStyles}>GitHub</label>
81
- {isEditing ? ( <input type="url" name="github" value={profileData?.github || ''} onChange={handleProfileChange} style={inputStyles} /> ) : ( <a href={profileData?.github || '#'} target="_blank" rel="noreferrer" style={{color: '#93C5FD'}}>{profileData?.github || 'Not set'}</a> )}
82
  </div>
83
- <div>
84
  <label style={labelStyles}>Portfolio</label>
85
- {isEditing ? ( <input type="url" name="portfolio" value={profileData?.portfolio || ''} onChange={handleProfileChange} style={inputStyles} /> ) : ( <a href={profileData?.portfolio || '#'} target="_blank" rel="noreferrer" style={{color: '#93C5FD'}}>{profileData?.portfolio || 'Not set'}</a> )}
86
  </div>
87
- <div style={{gridColumn: 'span 2'}}>
 
 
88
  <label style={labelStyles}>Technical Skills</label>
89
- {isEditing ? ( <textarea name="technical_skills" value={profileData?.technical_skills || ''} onChange={handleProfileChange} rows="3" style={inputStyles} /> ) : ( <p>{profileData?.technical_skills || 'Not set'}</p> )}
90
- </div>
91
- <div style={{ alignSelf: 'center' }}>
92
- {isEditing ? (
93
- <label style={checkboxLabelStyles}><input type="checkbox" name="willing_to_relocate" checked={!!profileData?.willing_to_relocate} onChange={handleProfileChange} style={checkboxStyles}/> Willing to Relocate</label>
94
- ) : ( <p>{profileData?.willing_to_relocate ? 'Willing to relocate' : 'Not willing to relocate'}</p> )}
95
- </div>
96
- <div style={{ alignSelf: 'center' }}>
97
- {isEditing ? (
98
- <label style={checkboxLabelStyles}><input type="checkbox" name="available_remote" checked={!!profileData?.available_remote} onChange={handleProfileChange} style={checkboxStyles}/> Available for Remote Work</label>
99
- ) : ( <p>{profileData?.available_remote ? 'Available for remote' : 'Not available for remote'}</p> )}
100
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  </div>
102
  </motion.div>
103
  )}
@@ -115,15 +223,15 @@ const ProfileTab = ({
115
  <input type="text" name="years" value={exp.years || ''} onChange={(e) => handleExperienceChange(index, e)} placeholder="Years" style={inputStyles} />
116
  </div>
117
  ))}
118
- <button
119
- onClick={handleAddExperience}
120
- style={{
121
- backgroundColor: 'rgba(251, 191, 36, 0.2)',
122
- color: '#FCD34D',
123
- padding: '0.5rem 1rem',
124
- borderRadius: '0.5rem',
125
- border: 'none',
126
- cursor: 'pointer'
127
  }}
128
  >
129
  + Add More Experience
@@ -133,7 +241,7 @@ const ProfileTab = ({
133
  <div>
134
  {profileData?.work_experience && profileData.work_experience.length > 0 ? (
135
  profileData.work_experience.map((exp, index) => (
136
- <div key={exp.id || index} style={{marginBottom: '1rem'}}>
137
  <p style={{ fontWeight: 'bold', margin: 0 }}>{exp.role}</p>
138
  <p style={{ color: '#d1d5db', margin: 0 }}>{exp.company} • {exp.years} years</p>
139
  </div>
@@ -144,8 +252,124 @@ const ProfileTab = ({
144
  </div>
145
  )}
146
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  </div>
148
  );
149
  };
150
-
151
- export default ProfileTab;
 
1
+ import React, { useState } from 'react';
2
  import { motion, AnimatePresence } from 'framer-motion';
3
 
4
+ // --- Helper Component for Tag Inputs ---
5
+ const TagInput = ({ name, value, onChange, placeholder, isEditing }) => {
6
+ const [inputValue, setInputValue] = useState("");
7
+
8
+ // Convert string "A, B, C" to array ["A", "B", "C"]
9
+ const tags = value ? value.split(',').map(s => s.trim()).filter(Boolean) : [];
10
+
11
+ const handleAddParam = (val) => {
12
+ const trimmed = val.trim();
13
+ if (trimmed && !tags.includes(trimmed)) {
14
+ const newTags = [...tags, trimmed];
15
+ onChange({ target: { name, value: newTags.join(', ') } });
16
+ }
17
+ setInputValue("");
18
+ };
19
+
20
+ const handleKeyDown = (e) => {
21
+ if (e.key === 'Enter' || e.key === ',') {
22
+ e.preventDefault();
23
+ handleAddParam(inputValue);
24
+ } else if (e.key === 'Backspace' && !inputValue && tags.length > 0) {
25
+ handleRemoveTag(tags.length - 1);
26
+ }
27
+ };
28
+
29
+ const handleRemoveTag = (index) => {
30
+ const newTags = tags.filter((_, i) => i !== index);
31
+ onChange({ target: { name, value: newTags.join(', ') } });
32
+ };
33
+
34
+ return (
35
+ <div style={{
36
+ display: 'flex', flexWrap: 'wrap', gap: '0.5rem',
37
+ padding: '0.5rem', borderRadius: '0.5rem',
38
+ border: isEditing ? '1px solid rgba(251, 191, 36, 0.3)' : 'none',
39
+ backgroundColor: isEditing ? 'rgba(255,255,255,0.05)' : 'transparent',
40
+ minHeight: '2.5rem'
41
+ }}>
42
+ {tags.map((tag, index) => (
43
+ <span key={index} style={{
44
+ backgroundColor: 'rgba(251, 191, 36, 0.15)',
45
+ color: '#FCD34D',
46
+ padding: '0.25rem 0.75rem',
47
+ borderRadius: '9999px',
48
+ fontSize: '0.875rem',
49
+ display: 'flex', alignItems: 'center', gap: '0.5rem'
50
+ }}>
51
+ {tag}
52
+ {isEditing && (
53
+ <button
54
+ onClick={() => handleRemoveTag(index)}
55
+ style={{ background: 'none', border: 'none', color: '#FCD34D', cursor: 'pointer', fontSize: '1rem', padding: 0 }}
56
+ >
57
+ ×
58
+ </button>
59
+ )}
60
+ </span>
61
+ ))}
62
+
63
+ {isEditing && (
64
+ <input
65
+ type="text"
66
+ value={inputValue}
67
+ onChange={(e) => setInputValue(e.target.value)}
68
+ onKeyDown={handleKeyDown}
69
+ onBlur={() => handleAddParam(inputValue)} // Add on blur too
70
+ placeholder={tags.length === 0 ? placeholder : ""}
71
+ style={{
72
+ background: 'transparent', border: 'none', color: 'white',
73
+ outline: 'none', flex: 1, minWidth: '100px'
74
+ }}
75
+ />
76
+ )}
77
+ {!isEditing && tags.length === 0 && <span style={{ color: '#6B7280' }}>Not set</span>}
78
+ </div>
79
+ );
80
+ };
81
+
82
+
83
  const ProfileTab = ({
84
  profileData,
85
  isEditing,
86
  handleProfileChange,
87
  handleExperienceChange,
88
  handleAddExperience,
89
+ handleAddEducation,
90
+ handleEducationChange,
91
  showFullProfile,
92
  }) => {
93
  if (!profileData) return null;
 
97
  border: '1px solid rgba(251, 191, 36, 0.3)',
98
  backgroundColor: 'rgba(255,255,255,0.1)', color: 'white'
99
  };
100
+
101
  const labelStyles = { display: 'block', marginBottom: '0.5rem', color: '#d1d5db' };
 
 
102
  const checkboxLabelStyles = { display: 'flex', alignItems: 'center', gap: '0.5rem', color: '#d1d5db' };
103
  const checkboxStyles = { width: '1.15em', height: '1.15em', accentColor: '#FBBF24' };
104
 
 
108
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '1.5rem' }}>
109
  <div>
110
  <label style={labelStyles}>Full Name</label>
111
+ {isEditing ? (<input type="text" name="full_name" value={profileData?.full_name || ''} onChange={handleProfileChange} style={inputStyles} placeholder="e.g., John Doe" />) : (<p>{profileData?.full_name || 'Not set'}</p>)}
112
  </div>
113
  <div>
114
  <label style={labelStyles}>Headline</label>
115
+ {isEditing ? (<input type="text" name="headline" value={profileData?.headline || ''} onChange={handleProfileChange} style={inputStyles} placeholder="e.g., Senior Software Engineer" />) : (<p>{profileData?.headline || 'Not set'}</p>)}
116
  </div>
117
  </div>
118
 
119
  {/* Summary */}
120
  <div>
121
  <label style={labelStyles}>Summary</label>
122
+ {isEditing ? (<textarea name="summary" value={profileData?.summary || ''} onChange={handleProfileChange} rows="4" style={inputStyles} placeholder="Tell us about yourself..." />) : (<p>{profileData?.summary || 'Not set'}</p>)}
123
  </div>
124
 
125
  {/* Extended Profile Fields */}
 
129
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '1.5rem', marginTop: '1.5rem' }}>
130
  <div>
131
  <label style={labelStyles}>Email</label>
132
+ {isEditing ? (<input type="email" name="email" value={profileData?.email || ''} onChange={handleProfileChange} style={inputStyles} />) : (<p>{profileData?.email || 'Not set'}</p>)}
133
  </div>
134
  <div>
135
  <label style={labelStyles}>Phone</label>
136
+ {isEditing ? (<input type="tel" name="phone" value={profileData?.phone || ''} onChange={handleProfileChange} style={inputStyles} />) : (<p>{profileData?.phone || 'Not set'}</p>)}
137
  </div>
138
+ <div>
139
  <label style={labelStyles}>Address</label>
140
+ {isEditing ? (<input type="text" name="address" value={profileData?.address || ''} onChange={handleProfileChange} style={inputStyles} />) : (<p>{profileData?.address || 'Not set'}</p>)}
141
  </div>
142
  <div>
143
  <label style={labelStyles}>Current Position</label>
144
+ {isEditing ? (<input type="text" name="current_position" value={profileData?.current_position || ''} onChange={handleProfileChange} style={inputStyles} />) : (<p>{profileData?.current_position || 'Not set'}</p>)}
145
  </div>
146
  <div>
147
  <label style={labelStyles}>Years of Experience</label>
148
+ {isEditing ? (<input type="text" name="experience_years" value={profileData?.experience_years || ''} onChange={handleProfileChange} style={inputStyles} />) : (<p>{profileData?.experience_years || 'Not set'}</p>)}
149
  </div>
150
  <div>
151
  <label style={labelStyles}>Desired Salary</label>
152
+ {isEditing ? (<input type="text" name="desired_salary" value={profileData?.desired_salary || ''} onChange={handleProfileChange} style={inputStyles} />) : (<p>{profileData?.desired_salary || 'Not set'}</p>)}
153
  </div>
154
  <div>
155
  <label style={labelStyles}>LinkedIn</label>
156
+ {isEditing ? (<input type="url" name="linkedin" value={profileData?.linkedin || ''} onChange={handleProfileChange} style={inputStyles} />) : (<a href={profileData?.linkedin || '#'} target="_blank" rel="noreferrer" style={{ color: '#93C5FD' }}>{profileData?.linkedin || 'Not set'}</a>)}
157
  </div>
158
  <div>
159
  <label style={labelStyles}>GitHub</label>
160
+ {isEditing ? (<input type="url" name="github" value={profileData?.github || ''} onChange={handleProfileChange} style={inputStyles} />) : (<a href={profileData?.github || '#'} target="_blank" rel="noreferrer" style={{ color: '#93C5FD' }}>{profileData?.github || 'Not set'}</a>)}
161
  </div>
162
+ <div>
163
  <label style={labelStyles}>Portfolio</label>
164
+ {isEditing ? (<input type="url" name="portfolio" value={profileData?.portfolio || ''} onChange={handleProfileChange} style={inputStyles} />) : (<a href={profileData?.portfolio || '#'} target="_blank" rel="noreferrer" style={{ color: '#93C5FD' }}>{profileData?.portfolio || 'Not set'}</a>)}
165
  </div>
166
+
167
+ {/* TAG INPUTS */}
168
+ <div style={{ gridColumn: 'span 2' }}>
169
  <label style={labelStyles}>Technical Skills</label>
170
+ <TagInput
171
+ name="technical_skills"
172
+ value={profileData?.technical_skills}
173
+ onChange={handleProfileChange}
174
+ isEditing={isEditing}
175
+ placeholder="Add skill (press Enter)..."
176
+ />
177
+ </div>
178
+ <div style={{ gridColumn: 'span 2' }}>
179
+ <label style={labelStyles}>Certifications</label>
180
+ <TagInput
181
+ name="certifications"
182
+ value={profileData?.certifications}
183
+ onChange={handleProfileChange}
184
+ isEditing={isEditing}
185
+ placeholder="Add certification (press Enter)..."
186
+ />
187
+ </div>
188
+ <div style={{ gridColumn: 'span 2' }}>
189
+ <label style={labelStyles}>Languages</label>
190
+ <TagInput
191
+ name="languages"
192
+ value={profileData?.languages}
193
+ onChange={handleProfileChange}
194
+ isEditing={isEditing}
195
+ placeholder="Add language (press Enter)..."
196
+ />
197
+ </div>
198
+
199
+ <div style={{ alignSelf: 'center' }}>
200
+ {isEditing ? (
201
+ <label style={checkboxLabelStyles}><input type="checkbox" name="willing_to_relocate" checked={!!profileData?.willing_to_relocate} onChange={handleProfileChange} style={checkboxStyles} /> Willing to Relocate</label>
202
+ ) : (<p>{profileData?.willing_to_relocate ? 'Willing to relocate' : 'Not willing to relocate'}</p>)}
203
+ </div>
204
+ <div style={{ alignSelf: 'center' }}>
205
+ {isEditing ? (
206
+ <label style={checkboxLabelStyles}><input type="checkbox" name="available_remote" checked={!!profileData?.available_remote} onChange={handleProfileChange} style={checkboxStyles} /> Available for Remote Work</label>
207
+ ) : (<p>{profileData?.available_remote ? 'Available for remote' : 'Not available for remote'}</p>)}
208
+ </div>
209
  </div>
210
  </motion.div>
211
  )}
 
223
  <input type="text" name="years" value={exp.years || ''} onChange={(e) => handleExperienceChange(index, e)} placeholder="Years" style={inputStyles} />
224
  </div>
225
  ))}
226
+ <button
227
+ onClick={handleAddExperience}
228
+ style={{
229
+ backgroundColor: 'rgba(251, 191, 36, 0.2)',
230
+ color: '#FCD34D',
231
+ padding: '0.5rem 1rem',
232
+ borderRadius: '0.5rem',
233
+ border: 'none',
234
+ cursor: 'pointer'
235
  }}
236
  >
237
  + Add More Experience
 
241
  <div>
242
  {profileData?.work_experience && profileData.work_experience.length > 0 ? (
243
  profileData.work_experience.map((exp, index) => (
244
+ <div key={exp.id || index} style={{ marginBottom: '1rem' }}>
245
  <p style={{ fontWeight: 'bold', margin: 0 }}>{exp.role}</p>
246
  <p style={{ color: '#d1d5db', margin: 0 }}>{exp.company} • {exp.years} years</p>
247
  </div>
 
252
  </div>
253
  )}
254
  </div>
255
+
256
+ {/* Education Section */}
257
+ <div>
258
+ <h3 style={{ fontSize: '1.25rem', fontWeight: 'bold', marginBottom: '1.5rem', marginTop: '1.5rem' }}>Education</h3>
259
+ {isEditing ? (
260
+ <>
261
+ {(profileData?.education || []).map((edu, index) => (
262
+ <div key={edu.id || index} style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: '1rem', marginBottom: '1rem' }}>
263
+ <input type="text" name="course" value={edu.course || ''} onChange={(e) => handleEducationChange(index, e)} placeholder="Course/Degree" style={inputStyles} />
264
+ <input type="text" name="institution" value={edu.institution || ''} onChange={(e) => handleEducationChange(index, e)} placeholder="Institution" style={inputStyles} />
265
+ <input type="text" name="year" value={edu.year || ''} onChange={(e) => handleEducationChange(index, e)} placeholder="Year" style={inputStyles} />
266
+ </div>
267
+ ))}
268
+ <button
269
+ onClick={handleAddEducation}
270
+ style={{
271
+ backgroundColor: 'rgba(251, 191, 36, 0.2)',
272
+ color: '#FCD34D',
273
+ padding: '0.5rem 1rem',
274
+ borderRadius: '0.5rem',
275
+ border: 'none',
276
+ cursor: 'pointer'
277
+ }}
278
+ >
279
+ + Add More Education
280
+ </button>
281
+ </>
282
+ ) : (
283
+ <div>
284
+ {profileData?.education && profileData.education.length > 0 ? (
285
+ profileData.education.map((edu, index) => (
286
+ <div key={edu.id || index} style={{ marginBottom: '1rem' }}>
287
+ <p style={{ fontWeight: 'bold', margin: 0 }}>{edu.course}</p>
288
+ <p style={{ color: '#d1d5db', margin: 0 }}>{edu.institution} • {edu.year}</p>
289
+ </div>
290
+ ))
291
+ ) : (
292
+ <p>No education added.</p>
293
+ )}
294
+ </div>
295
+ )}
296
+ </div>
297
+
298
+ {/* Projects Section */}
299
+ <div>
300
+ <h3 style={{ fontSize: '1.25rem', fontWeight: 'bold', marginBottom: '1.5rem', marginTop: '1.5rem' }}>Projects</h3>
301
+ {isEditing ? (
302
+ <>
303
+ {(profileData?.projects || []).map((proj, index) => (
304
+ <div key={index} style={{ marginBottom: '1.5rem', padding: '1rem', backgroundColor: 'rgba(255,255,255,0.05)', borderRadius: '0.5rem' }}>
305
+ <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: '0.5rem', marginBottom: '0.5rem' }}>
306
+ <input type="text" name="title" value={proj.title || ''} onChange={(e) => {
307
+ const newProjects = [...(profileData.projects || [])];
308
+ newProjects[index] = { ...newProjects[index], title: e.target.value };
309
+ handleProfileChange({ target: { name: 'projects', value: newProjects } });
310
+ }} placeholder="Project Title" style={{ ...inputStyles, marginBottom: '0.5rem' }} />
311
+
312
+ <textarea name="description" value={proj.description || ''} onChange={(e) => {
313
+ const newProjects = [...(profileData.projects || [])];
314
+ newProjects[index] = { ...newProjects[index], description: e.target.value };
315
+ handleProfileChange({ target: { name: 'projects', value: newProjects } });
316
+ }} placeholder="Description" rows="2" style={{ ...inputStyles, marginBottom: '0.5rem' }} />
317
+
318
+ <TagInput
319
+ name={`projects[${index}].technologies_used`}
320
+ value={Array.isArray(proj.technologies_used) ? proj.technologies_used.join(', ') : (proj.technologies_used || '')}
321
+ onChange={(e) => {
322
+ const newProjects = [...(profileData.projects || [])];
323
+ const val = e.target.value;
324
+ newProjects[index] = { ...newProjects[index], technologies_used: val.split(',').map(s => s.trim()).filter(Boolean) };
325
+ handleProfileChange({ target: { name: 'projects', value: newProjects } });
326
+ }}
327
+ isEditing={true}
328
+ placeholder="Technologies (comma separated)..."
329
+ />
330
+ </div>
331
+ <button onClick={() => {
332
+ const newProjects = profileData.projects.filter((_, i) => i !== index);
333
+ handleProfileChange({ target: { name: 'projects', value: newProjects } });
334
+ }} style={{ color: '#EF4444', background: 'none', border: 'none', cursor: 'pointer', fontSize: '0.875rem' }}>Remove Project</button>
335
+ </div>
336
+ ))}
337
+ <button
338
+ onClick={() => {
339
+ const newProjects = [...(profileData.projects || []), { title: '', technologies_used: [], description: '' }];
340
+ handleProfileChange({ target: { name: 'projects', value: newProjects } });
341
+ }}
342
+ style={{
343
+ backgroundColor: 'rgba(251, 191, 36, 0.2)',
344
+ color: '#FCD34D',
345
+ padding: '0.5rem 1rem',
346
+ borderRadius: '0.5rem',
347
+ border: 'none',
348
+ cursor: 'pointer'
349
+ }}
350
+ >
351
+ + Add Project
352
+ </button>
353
+ </>
354
+ ) : (
355
+ <div>
356
+ {profileData?.projects && profileData.projects.length > 0 ? (
357
+ profileData.projects.map((proj, index) => (
358
+ <div key={index} style={{ marginBottom: '1.5rem' }}>
359
+ <p style={{ fontWeight: 'bold', margin: 0, color: '#FCD34D' }}>{proj.title}</p>
360
+ <p style={{ fontSize: '0.875rem', color: '#9CA3AF', margin: '0.25rem 0' }}>
361
+ {Array.isArray(proj.technologies_used) ? proj.technologies_used.join(', ') : proj.technologies_used}
362
+ </p>
363
+ <p style={{ color: '#d1d5db', margin: 0 }}>{proj.description}</p>
364
+ </div>
365
+ ))
366
+ ) : (
367
+ <p>No projects added.</p>
368
+ )}
369
+ </div>
370
+ )}
371
+ </div>
372
  </div>
373
  );
374
  };
375
+ export default ProfileTab;