diff --git a/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubProfileTab.tsx b/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubProfileTab.tsx index 8be2c58..ca2b4c9 100644 --- a/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubProfileTab.tsx +++ b/src/app/[locale]/admin/clubs/[club_id]/tabs/ClubProfileTab.tsx @@ -1,11 +1,72 @@ 'use client'; import { useState, useEffect } from 'react'; -import { Loader2, AlertCircle, CheckCircle, Info } from 'lucide-react'; +import { Loader2, AlertCircle, CheckCircle, Info, Pencil } from 'lucide-react'; import { getClubProfile, updateClubProfile } from '@/src/lib/api/courts'; import type { ClubProfile, ClubProfileUpdateRequest} from '@/src/types/courts'; import { COMMON_TIMEZONES, isValidEmail, isValidUrl } from '@/src/types/courts'; +/** + * Editable Field Component - Click to edit with pencil icon + */ +interface EditableFieldProps { + fieldName: string; + value: string; + onChange: (value: string) => void; + isEditing: boolean; + onToggleEdit: () => void; + placeholder?: string; + maxLength?: number; + type?: 'text' | 'email' | 'tel' | 'url'; + error?: string; + disabled?: boolean; +} + +function EditableField({ + fieldName, + value, + onChange, + isEditing, + onToggleEdit, + placeholder, + maxLength, + type = 'text', + error, + disabled = false, +}: EditableFieldProps) { + const hasValue = value.trim().length > 0; + + if (isEditing || !hasValue) { + return ( + onChange(e.target.value)} + onBlur={() => hasValue && onToggleEdit()} + autoFocus + placeholder={placeholder} + maxLength={maxLength} + className={`w-full px-4 py-3 border-2 rounded-lg font-medium transition-colors ${ + error + ? 'border-red-300 focus:border-red-500' + : 'border-slate-200 focus:border-slate-900' + } focus:outline-none`} + disabled={disabled} + /> + ); + } + + return ( +
+ {value} + +
+ ); +} + interface ClubProfileTabProps { clubId: number; onUpdate?: () => void; @@ -31,6 +92,9 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps const [email, setEmail] = useState(''); const [website, setWebsite] = useState(''); + // Edit mode tracking for each field + const [editingFields, setEditingFields] = useState>(new Set()); + useEffect(() => { loadProfile(); }, [clubId]); @@ -168,6 +232,27 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps setWebsite(profile.settings?.contact?.website || ''); setErrors({}); setError(null); + setEditingFields(new Set()); + } + + function toggleEditField(fieldName: string) { + setEditingFields(prev => { + const next = new Set(prev); + if (next.has(fieldName)) { + next.delete(fieldName); + } else { + next.add(fieldName); + } + return next; + }); + } + + function isFieldEditing(fieldName: string): boolean { + return editingFields.has(fieldName); + } + + function hasFieldValue(value: string): boolean { + return value.trim().length > 0; } // Loading state @@ -226,17 +311,29 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - setName(e.target.value)} - className={`w-full px-4 py-3 border-2 rounded-lg font-medium transition-colors ${ - errors.name - ? 'border-red-300 focus:border-red-500' - : 'border-slate-200 focus:border-slate-900' - } focus:outline-none`} - disabled={saving} - /> + {isFieldEditing('name') || !hasFieldValue(name) ? ( + setName(e.target.value)} + onBlur={() => hasFieldValue(name) && toggleEditField('name')} + autoFocus + className={`w-full px-4 py-3 border-2 rounded-lg font-medium transition-colors ${ + errors.name + ? 'border-red-300 focus:border-red-500' + : 'border-slate-200 focus:border-slate-900' + } focus:outline-none`} + disabled={saving} + /> + ) : ( +
toggleEditField('name')} + className="flex items-center justify-between px-4 py-3 border-2 border-slate-200 rounded-lg cursor-pointer hover:border-slate-300 hover:bg-slate-50 transition-colors group" + > + {name} + +
+ )} {errors.name && (

{errors.name}

)} @@ -247,22 +344,36 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - + {isFieldEditing('timezone') ? ( + + ) : ( +
toggleEditField('timezone')} + className="flex items-center justify-between px-4 py-3 border-2 border-slate-200 rounded-lg cursor-pointer hover:border-slate-300 hover:bg-slate-50 transition-colors group" + > + + {COMMON_TIMEZONES.find(tz => tz.value === timezone)?.label || timezone} + + +
+ )} {errors.timezone && (

{errors.timezone}

)} @@ -288,13 +399,14 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - setAddressLine1(e.target.value)} + onChange={setAddressLine1} + isEditing={isFieldEditing('addressLine1')} + onToggleEdit={() => toggleEditField('addressLine1')} placeholder="123 High Street" maxLength={200} - className="w-full px-4 py-3 border-2 border-slate-200 rounded-lg font-medium focus:border-slate-900 focus:outline-none transition-colors" disabled={saving} /> @@ -304,13 +416,14 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - setAddressLine2(e.target.value)} + onChange={setAddressLine2} + isEditing={isFieldEditing('addressLine2')} + onToggleEdit={() => toggleEditField('addressLine2')} placeholder="Building A" maxLength={200} - className="w-full px-4 py-3 border-2 border-slate-200 rounded-lg font-medium focus:border-slate-900 focus:outline-none transition-colors" disabled={saving} /> @@ -321,13 +434,14 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - setCity(e.target.value)} + onChange={setCity} + isEditing={isFieldEditing('city')} + onToggleEdit={() => toggleEditField('city')} placeholder="London" maxLength={100} - className="w-full px-4 py-3 border-2 border-slate-200 rounded-lg font-medium focus:border-slate-900 focus:outline-none transition-colors" disabled={saving} /> @@ -336,13 +450,14 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - setPostalCode(e.target.value)} + onChange={setPostalCode} + isEditing={isFieldEditing('postalCode')} + onToggleEdit={() => toggleEditField('postalCode')} placeholder="SW1A 1AA" maxLength={20} - className="w-full px-4 py-3 border-2 border-slate-200 rounded-lg font-medium focus:border-slate-900 focus:outline-none transition-colors" disabled={saving} /> @@ -353,13 +468,14 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - setCountry(e.target.value)} + onChange={setCountry} + isEditing={isFieldEditing('country')} + onToggleEdit={() => toggleEditField('country')} placeholder="United Kingdom" maxLength={100} - className="w-full px-4 py-3 border-2 border-slate-200 rounded-lg font-medium focus:border-slate-900 focus:outline-none transition-colors" disabled={saving} /> @@ -384,13 +500,15 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - setPhone(e.target.value)} + onChange={setPhone} + isEditing={isFieldEditing('phone')} + onToggleEdit={() => toggleEditField('phone')} placeholder="+44 20 1234 5678" maxLength={50} - className="w-full px-4 py-3 border-2 border-slate-200 rounded-lg font-medium focus:border-slate-900 focus:outline-none transition-colors" + type="tel" disabled={saving} /> @@ -400,17 +518,16 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - setEmail(e.target.value)} + onChange={setEmail} + isEditing={isFieldEditing('email')} + onToggleEdit={() => toggleEditField('email')} placeholder="info@centralpadel.com" maxLength={100} - className={`w-full px-4 py-3 border-2 rounded-lg font-medium transition-colors ${ - errors.email - ? 'border-red-300 focus:border-red-500' - : 'border-slate-200 focus:border-slate-900' - } focus:outline-none`} + type="email" + error={errors.email} disabled={saving} /> {errors.email && ( @@ -423,17 +540,16 @@ export default function ClubProfileTab({ clubId, onUpdate }: ClubProfileTabProps - setWebsite(e.target.value)} + onChange={setWebsite} + isEditing={isFieldEditing('website')} + onToggleEdit={() => toggleEditField('website')} placeholder="https://www.centralpadel.com" maxLength={200} - className={`w-full px-4 py-3 border-2 rounded-lg font-medium transition-colors ${ - errors.website - ? 'border-red-300 focus:border-red-500' - : 'border-slate-200 focus:border-slate-900' - } focus:outline-none`} + type="url" + error={errors.website} disabled={saving} /> {errors.website && (