'use client'; import React, { useState } from 'react'; import Link from 'next/link'; import { Club, UserPortalPermissions } from './types'; import { updateClubProfile, sanitizePortalError } from '../../lib/club-data'; interface FounderProfileEditorProps { club: Club; permissions: UserPortalPermissions; callerUid?: string; isDemoFixture?: boolean; onProfileUpdated?: (updated: Partial) => void; } export function FounderProfileEditor({ club, permissions, callerUid, isDemoFixture = false, onProfileUpdated, }: FounderProfileEditorProps) { // Form fields matching Section 1 & 2 const [name, setName] = useState(club.name || ''); const [description, setDescription] = useState(club.description || ''); const [homeRegion, setHomeRegion] = useState(club.homeRegion || ''); const [motorcycleFocus, setMotorcycleFocus] = useState(club.motorcycleFocus || ''); const [logoUrl, setLogoUrl] = useState(club.logoUrl || ''); const [bannerUrl, setBannerUrl] = useState(club.bannerUrl || ''); // Save states const [isSaving, setIsSaving] = useState(false); const [saveStatus, setSaveStatus] = useState<'idle' | 'success' | 'error'>('idle'); const [errorMessage, setErrorMessage] = useState(null); // Image URL validation (HTTPS only or empty to clear) function isValidHttpsImageUrl(url: string): boolean { const trimmed = url.trim(); if (!trimmed) return true; try { const parsed = new URL(trimmed); return parsed.protocol === 'https:'; } catch { return false; } } // Validation const trimmedName = name.trim(); const isNameValid = trimmedName.length >= 3 && trimmedName.length <= 50; const isDescValid = description.trim().length <= 500; const isRegionValid = homeRegion.trim().length <= 100; const isFocusValid = motorcycleFocus.trim().length <= 100; const isLogoUrlValid = isValidHttpsImageUrl(logoUrl); const isBannerUrlValid = isValidHttpsImageUrl(bannerUrl); const canSave = isNameValid && isDescValid && isRegionValid && isFocusValid && isLogoUrlValid && isBannerUrlValid && !isSaving && permissions.canManageSettings; const isDirty = trimmedName !== (club.name || '').trim() || description.trim() !== (club.description || '').trim() || homeRegion.trim() !== (club.homeRegion || '').trim() || motorcycleFocus.trim() !== (club.motorcycleFocus || '').trim() || logoUrl.trim() !== (club.logoUrl || '').trim() || bannerUrl.trim() !== (club.bannerUrl || '').trim(); // Short initials for preview emblem const initials = name .split(/\s+/) .filter(Boolean) .map((w) => w[0].toUpperCase()) .slice(0, 3) .join('') || 'MSR'; async function handleSave(e: React.FormEvent) { e.preventDefault(); if (!canSave) return; setIsSaving(true); setSaveStatus('idle'); setErrorMessage(null); const trimmedLogo = logoUrl.trim(); const trimmedBanner = bannerUrl.trim(); try { if (isDemoFixture) { // Simulated latency in development demo preview mode await new Promise((resolve) => setTimeout(resolve, 600)); setSaveStatus('success'); onProfileUpdated?.({ name: trimmedName, description: description.trim(), homeRegion: homeRegion.trim(), motorcycleFocus: motorcycleFocus.trim(), logoUrl: trimmedLogo || null, bannerUrl: trimmedBanner || null, }); } else { if (!callerUid) { throw new Error('Authentication required to save profile.'); } await updateClubProfile(club.id, callerUid, { name: trimmedName, description: description.trim(), homeRegion: homeRegion.trim(), motorcycleFocus: motorcycleFocus.trim(), logoUrl: trimmedLogo, bannerUrl: trimmedBanner, }); setSaveStatus('success'); onProfileUpdated?.({ name: trimmedName, description: description.trim(), homeRegion: homeRegion.trim(), motorcycleFocus: motorcycleFocus.trim(), logoUrl: trimmedLogo || null, bannerUrl: trimmedBanner || null, }); } } catch (err) { setSaveStatus('error'); setErrorMessage(sanitizePortalError(err, 'Failed to update club profile. Please try again.')); } finally { setIsSaving(false); } } return (
{/* 3. PAGE HEADER */}
Precision, Not Aggression // {homeRegion ? `${homeRegion} Zone` : 'Regional Squadron'}

Club Profile

Manage public-facing club identity, branding presentation, and discovery presence.

{/* 4. TOP 4 METRIC CARDS */}
{/* Card 1: Club Name */}
Club Name
{name || club.name}
3-50 chars valid
{/* Card 2: Home Region */}
Home Region location_on
{homeRegion || 'Not specified'}
Home Region
{/* Card 3: Motorcycle Focus */}
Motorcycle Focus sports_motorsports
{motorcycleFocus || 'General'}
Motorcycle Focus
{/* Card 4: Discovery Presence */}
Discovery Presence
{club.visibility}
{club.visibility === 'public' ? 'Listed in public club index & directory' : club.visibility === 'unlisted' ? 'Accessible via direct handle only' : 'Restricted private club'}
{/* 5. MAIN WORKSPACE (12-Column Grid) */}
{/* LEFT MAIN (8 cols) */}
{/* Status Feedback Banner */} {saveStatus === 'success' && (
check_circle
Club profile changes have been saved successfully.
)} {saveStatus === 'error' && errorMessage && (
error
{errorMessage}
)} {/* SECTION 1: PUBLIC CLUB IDENTITY */}
badge

Section 1: Public Club Identity

{/* Club Name */}
setName(e.target.value)} disabled={!permissions.canManageSettings || isSaving} placeholder="e.g. MotorSignal Riders Atlanta" className="w-full bg-surface-container-low/90 border border-brand-border/80 focus:border-brand-cyan rounded-xl px-3.5 py-2.5 text-sm font-body text-white outline-none transition-colors" /> {isNameValid ? 'Valid' : `${trimmedName.length}/50`}

3-50 characters. Displayed on public discovery, ride manifests, and club roster.

{/* Club Handle / Identifier (Locked) */}
Immutable
lock

Club handles are permanently reserved and cannot be renamed or reassigned.

{/* Club Description */}
{description.length}/500