Skip to content

Commit 5e6316d

Browse files
authored
Updated ProfileEditor.tsx
1 parent 2b71ddc commit 5e6316d

File tree

1 file changed

+108
-66
lines changed

1 file changed

+108
-66
lines changed

src/components/ProfileEditor.tsx

Lines changed: 108 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,84 @@ interface ProfileEditorProps {
88
onNext: () => void;
99
}
1010

11+
type InputKind = 'text' | 'url' | 'email' | 'textarea';
12+
13+
interface InputFieldProps {
14+
label: string;
15+
field: keyof NostrProfile;
16+
type?: InputKind;
17+
placeholder: string;
18+
validation?: 'url' | 'email';
19+
maxLength?: number;
20+
localProfile: NostrProfile;
21+
validationErrors: Record<string, string>;
22+
handleChange: (field: keyof NostrProfile, value: string) => void;
23+
handleUrlBlur: (field: keyof NostrProfile, value: string) => void;
24+
handleEmailBlur: (field: keyof NostrProfile, value: string) => void;
25+
}
26+
27+
const InputField = ({
28+
label,
29+
field,
30+
type = 'text',
31+
placeholder,
32+
validation,
33+
maxLength,
34+
localProfile,
35+
validationErrors,
36+
handleChange,
37+
handleUrlBlur,
38+
handleEmailBlur
39+
}: InputFieldProps) => (
40+
<div className="space-y-2">
41+
<label className="block text-sm font-medium text-gray-800">
42+
{label}
43+
{typeof maxLength === 'number' && (
44+
<span className="text-xs text-gray-500 ml-2">
45+
({(localProfile[field] as string)?.length || 0}/{maxLength})
46+
</span>
47+
)}
48+
</label>
49+
50+
<div className="relative">
51+
{type === 'textarea' ? (
52+
<textarea
53+
value={(localProfile[field] as string) || ''}
54+
onChange={(e) => handleChange(field, e.target.value)}
55+
placeholder={placeholder}
56+
maxLength={maxLength}
57+
rows={4}
58+
className={`w-full p-3 rounded-xl border bg-white text-gray-900 placeholder-gray-400
59+
focus:outline-none focus:ring-2 focus:ring-black focus:border-black transition
60+
${validationErrors[field] ? 'border-red-300' : 'border-gray-300 hover:border-gray-400'} resize-none text-sm`}
61+
/>
62+
) : (
63+
<input
64+
type={type}
65+
value={(localProfile[field] as string) || ''}
66+
onChange={(e) => handleChange(field, e.target.value)}
67+
onBlur={(e) => {
68+
if (validation === 'url') handleUrlBlur(field, e.target.value);
69+
if (validation === 'email') handleEmailBlur(field, e.target.value);
70+
}}
71+
placeholder={placeholder}
72+
maxLength={maxLength}
73+
className={`w-full p-3 rounded-xl border bg-white text-gray-900 placeholder-gray-400
74+
focus:outline-none focus:ring-2 focus:ring-black focus:border-black transition
75+
${validationErrors[field] ? 'border-red-300' : 'border-gray-300 hover:border-gray-400'} text-sm`}
76+
/>
77+
)}
78+
79+
{validationErrors[field] && (
80+
<div className="absolute -bottom-5 left-0 flex items-center text-red-600 text-xs">
81+
<AlertCircle className="w-4 h-4 mr-1.5" />
82+
{validationErrors[field]}
83+
</div>
84+
)}
85+
</div>
86+
</div>
87+
);
88+
1189
export default function ProfileEditor({ profile, onProfileUpdate, onNext }: ProfileEditorProps) {
1290
const [localProfile, setLocalProfile] = useState<NostrProfile>(profile);
1391
const [validationErrors, setValidationErrors] = useState<Record<string, string>>({});
@@ -66,72 +144,6 @@ export default function ProfileEditor({ profile, onProfileUpdate, onNext }: Prof
66144
}
67145
};
68146

69-
type InputKind = 'text' | 'url' | 'email' | 'textarea';
70-
71-
const InputField = ({
72-
label,
73-
field,
74-
type = 'text',
75-
placeholder,
76-
validation,
77-
maxLength
78-
}: {
79-
label: string;
80-
field: keyof NostrProfile;
81-
type?: InputKind;
82-
placeholder: string;
83-
validation?: 'url' | 'email';
84-
maxLength?: number;
85-
}) => (
86-
<div className="space-y-2">
87-
<label className="block text-sm font-medium text-gray-800">
88-
{label}
89-
{typeof maxLength === 'number' && (
90-
<span className="text-xs text-gray-500 ml-2">
91-
({(localProfile[field] as string)?.length || 0}/{maxLength})
92-
</span>
93-
)}
94-
</label>
95-
96-
<div className="relative">
97-
{type === 'textarea' ? (
98-
<textarea
99-
value={(localProfile[field] as string) || ''}
100-
onChange={(e) => handleChange(field, e.target.value)}
101-
placeholder={placeholder}
102-
maxLength={maxLength}
103-
rows={4}
104-
className={`w-full p-3 rounded-xl border bg-white text-gray-900 placeholder-gray-400
105-
focus:outline-none focus:ring-2 focus:ring-black focus:border-black transition
106-
${validationErrors[field] ? 'border-red-300' : 'border-gray-300 hover:border-gray-400'} resize-none text-sm`}
107-
/>
108-
) : (
109-
<input
110-
type={type}
111-
value={(localProfile[field] as string) || ''}
112-
onChange={(e) => handleChange(field, e.target.value)}
113-
onBlur={(e) => {
114-
if (validation === 'url') handleUrlBlur(field, e.target.value);
115-
if (validation === 'email') handleEmailBlur(field, e.target.value);
116-
}}
117-
placeholder={placeholder}
118-
maxLength={maxLength}
119-
className={`w-full p-3 rounded-xl border bg-white text-gray-900 placeholder-gray-400
120-
focus:outline-none focus:ring-2 focus:ring-black focus:border-black transition
121-
${validationErrors[field] ? 'border-red-300' : 'border-gray-300 hover:border-gray-400'} text-sm`}
122-
/>
123-
)}
124-
125-
{validationErrors[field] && (
126-
<div className="absolute -bottom-5 left-0 flex items-center text-red-600 text-xs">
127-
<AlertCircle className="w-4 h-4 mr-1.5" />
128-
{validationErrors[field]}
129-
</div>
130-
)}
131-
</div>
132-
</div>
133-
);
134-
135147
return (
136148
<div className="min-h-screen bg-white flex items-center justify-center p-6">
137149
<div className="max-w-2xl mx-auto w-full">
@@ -154,13 +166,23 @@ export default function ProfileEditor({ profile, onProfileUpdate, onNext }: Prof
154166
field="display_name"
155167
placeholder="John Doe"
156168
maxLength={100}
169+
localProfile={localProfile}
170+
validationErrors={validationErrors}
171+
handleChange={handleChange}
172+
handleUrlBlur={handleUrlBlur}
173+
handleEmailBlur={handleEmailBlur}
157174
/>
158175

159176
<InputField
160177
label="Username"
161178
field="name"
162179
placeholder="johndoe"
163180
maxLength={50}
181+
localProfile={localProfile}
182+
validationErrors={validationErrors}
183+
handleChange={handleChange}
184+
handleUrlBlur={handleUrlBlur}
185+
handleEmailBlur={handleEmailBlur}
164186
/>
165187

166188
<InputField
@@ -169,6 +191,11 @@ export default function ProfileEditor({ profile, onProfileUpdate, onNext }: Prof
169191
type="textarea"
170192
placeholder="Tell people about yourself..."
171193
maxLength={500}
194+
localProfile={localProfile}
195+
validationErrors={validationErrors}
196+
handleChange={handleChange}
197+
handleUrlBlur={handleUrlBlur}
198+
handleEmailBlur={handleEmailBlur}
172199
/>
173200

174201
<InputField
@@ -177,6 +204,11 @@ export default function ProfileEditor({ profile, onProfileUpdate, onNext }: Prof
177204
type="url"
178205
placeholder="https://example.com/photo.jpg"
179206
validation="url"
207+
localProfile={localProfile}
208+
validationErrors={validationErrors}
209+
handleChange={handleChange}
210+
handleUrlBlur={handleUrlBlur}
211+
handleEmailBlur={handleEmailBlur}
180212
/>
181213

182214
<InputField
@@ -185,6 +217,11 @@ export default function ProfileEditor({ profile, onProfileUpdate, onNext }: Prof
185217
type="url"
186218
placeholder="https://yoursite.com"
187219
validation="url"
220+
localProfile={localProfile}
221+
validationErrors={validationErrors}
222+
handleChange={handleChange}
223+
handleUrlBlur={handleUrlBlur}
224+
handleEmailBlur={handleEmailBlur}
188225
/>
189226

190227
<InputField
@@ -193,6 +230,11 @@ export default function ProfileEditor({ profile, onProfileUpdate, onNext }: Prof
193230
type="email"
194231
placeholder="you@getalby.com"
195232
validation="email"
233+
localProfile={localProfile}
234+
validationErrors={validationErrors}
235+
handleChange={handleChange}
236+
handleUrlBlur={handleUrlBlur}
237+
handleEmailBlur={handleEmailBlur}
196238
/>
197239
</div>
198240
</div>

0 commit comments

Comments
 (0)