553 lines
27 KiB
TypeScript
553 lines
27 KiB
TypeScript
'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<Club>) => 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 || '');
|
|
|
|
// Save states
|
|
const [isSaving, setIsSaving] = useState(false);
|
|
const [saveStatus, setSaveStatus] = useState<'idle' | 'success' | 'error'>('idle');
|
|
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
|
|
|
// 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 canSave = isNameValid && isDescValid && isRegionValid && isFocusValid && !isSaving && permissions.canManageSettings;
|
|
|
|
const isDirty =
|
|
trimmedName !== (club.name || '').trim() ||
|
|
description.trim() !== (club.description || '').trim() ||
|
|
homeRegion.trim() !== (club.homeRegion || '').trim() ||
|
|
motorcycleFocus.trim() !== (club.motorcycleFocus || '').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);
|
|
|
|
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(),
|
|
});
|
|
} 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(),
|
|
});
|
|
setSaveStatus('success');
|
|
onProfileUpdated?.({
|
|
name: trimmedName,
|
|
description: description.trim(),
|
|
homeRegion: homeRegion.trim(),
|
|
motorcycleFocus: motorcycleFocus.trim(),
|
|
});
|
|
}
|
|
} catch (err) {
|
|
setSaveStatus('error');
|
|
setErrorMessage(sanitizePortalError(err, 'Failed to update club profile. Please try again.'));
|
|
} finally {
|
|
setIsSaving(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6 pb-12">
|
|
{/* 3. PAGE HEADER */}
|
|
<section className="border-b border-outline-variant pb-6 flex flex-col md:flex-row md:items-end justify-between gap-4">
|
|
<div>
|
|
<div className="flex items-center gap-3">
|
|
<span className="font-mono text-xs text-secondary tracking-widest uppercase bg-surface-container px-2 py-0.5 rounded border border-secondary/30">
|
|
PRECISION, NOT AGGRESSION
|
|
</span>
|
|
<span className="font-mono text-xs text-outline tracking-wider uppercase">
|
|
// {homeRegion ? `${homeRegion.toUpperCase()} ZONE` : 'REGIONAL SQUADRON'}
|
|
</span>
|
|
</div>
|
|
<h1 className="font-headline font-bold text-2xl sm:text-3xl text-on-surface mt-2 uppercase tracking-tight">
|
|
CLUB PROFILE
|
|
</h1>
|
|
<p className="font-body text-sm text-on-surface-variant mt-1">
|
|
Manage public-facing club identity, branding presentation, and discovery presence.
|
|
</p>
|
|
</div>
|
|
</section>
|
|
|
|
{/* 4. TOP 4 METRIC CARDS */}
|
|
<section className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
{/* Card 1: Club Name */}
|
|
<div className="bg-surface-container-low border border-outline-variant p-3.5 rounded flex flex-col justify-between">
|
|
<div className="flex items-center justify-between">
|
|
<span className="font-mono text-[11px] uppercase text-outline">CLUB NAME</span>
|
|
<span className="w-1.5 h-1.5 bg-secondary rounded-full" />
|
|
</div>
|
|
<div className="mt-2">
|
|
<div className="font-headline text-sm font-semibold text-on-surface truncate">{name || club.name}</div>
|
|
<div className="font-mono text-[11px] text-secondary mt-1">3-50 chars validated</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 2: Home Region */}
|
|
<div className="bg-surface-container-low border border-outline-variant p-3.5 rounded flex flex-col justify-between">
|
|
<div className="flex items-center justify-between">
|
|
<span className="font-mono text-[11px] uppercase text-outline">HOME REGION</span>
|
|
<span className="material-symbols-outlined text-outline text-sm">location_on</span>
|
|
</div>
|
|
<div className="mt-2">
|
|
<div className="font-headline text-sm font-semibold text-on-surface truncate">
|
|
{homeRegion || 'Not specified'}
|
|
</div>
|
|
<div className="font-mono text-[11px] text-outline mt-1">Home Region</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 3: Motorcycle Focus */}
|
|
<div className="bg-surface-container-low border border-outline-variant p-3.5 rounded flex flex-col justify-between">
|
|
<div className="flex items-center justify-between">
|
|
<span className="font-mono text-[11px] uppercase text-outline">MOTORCYCLE FOCUS</span>
|
|
<span className="material-symbols-outlined text-outline text-sm">sports_motorsports</span>
|
|
</div>
|
|
<div className="mt-2">
|
|
<div className="font-headline text-sm font-semibold text-on-surface truncate">
|
|
{motorcycleFocus || 'General'}
|
|
</div>
|
|
<div className="font-mono text-[11px] text-outline mt-1">Motorcycle Focus</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 4: Discovery Presence */}
|
|
<div className="bg-surface-container-low border border-outline-variant p-3.5 rounded flex flex-col justify-between">
|
|
<div className="flex items-center justify-between">
|
|
<span className="font-mono text-[11px] uppercase text-outline">DISCOVERY PRESENCE</span>
|
|
<span
|
|
className={`w-2 h-2 rounded-full ${
|
|
club.visibility === 'public' ? 'bg-emerald-400' : club.visibility === 'unlisted' ? 'bg-amber-400' : 'bg-outline'
|
|
}`}
|
|
/>
|
|
</div>
|
|
<div className="mt-2">
|
|
<div
|
|
className={`font-headline text-sm font-semibold uppercase ${
|
|
club.visibility === 'public' ? 'text-emerald-400' : club.visibility === 'unlisted' ? 'text-amber-400' : 'text-on-surface'
|
|
}`}
|
|
>
|
|
{club.visibility}
|
|
</div>
|
|
<div className="font-mono text-[11px] text-outline mt-1">
|
|
{club.visibility === 'public'
|
|
? 'Listed in public club index & directory'
|
|
: club.visibility === 'unlisted'
|
|
? 'Accessible via direct handle only'
|
|
: 'Restricted private club'}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* 5. MAIN WORKSPACE (12-Column Grid) */}
|
|
<form onSubmit={handleSave} className="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
|
{/* LEFT MAIN (8 cols) */}
|
|
<div className="lg:col-span-8 space-y-6">
|
|
{/* Status Feedback Banner */}
|
|
{saveStatus === 'success' && (
|
|
<div className="p-4 rounded bg-secondary/10 border border-secondary/30 flex items-center gap-3 text-secondary">
|
|
<span className="material-symbols-outlined text-xl">check_circle</span>
|
|
<div className="text-xs font-body font-medium">
|
|
Club profile changes have been saved successfully.
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{saveStatus === 'error' && errorMessage && (
|
|
<div className="p-4 rounded bg-error-container border border-error/30 flex items-center gap-3 text-error">
|
|
<span className="material-symbols-outlined text-xl">error</span>
|
|
<div className="text-xs font-body font-medium">{errorMessage}</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* SECTION 1: PUBLIC CLUB IDENTITY */}
|
|
<div className="bg-surface-container-low border border-outline-variant rounded p-5 space-y-4">
|
|
<div className="flex items-center justify-between border-b border-outline-variant pb-3">
|
|
<div className="flex items-center gap-2">
|
|
<span className="material-symbols-outlined text-secondary text-lg">badge</span>
|
|
<h2 className="font-headline text-sm uppercase font-semibold text-on-surface">
|
|
SECTION 1: PUBLIC CLUB IDENTITY
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Club Name */}
|
|
<div className="space-y-1.5">
|
|
<label htmlFor="club-name-input" className="font-mono text-[11px] text-outline uppercase block font-medium">
|
|
Club Name
|
|
</label>
|
|
<div className="relative">
|
|
<input
|
|
id="club-name-input"
|
|
type="text"
|
|
value={name}
|
|
onChange={(e) => setName(e.target.value)}
|
|
disabled={!permissions.canManageSettings || isSaving}
|
|
placeholder="e.g. MotorSignal Riders Atlanta"
|
|
className="w-full bg-surface-dim border border-outline-variant rounded px-3 py-2 text-sm font-body text-on-surface focus:border-primary focus:ring-0 outline-none transition-colors"
|
|
/>
|
|
<span
|
|
className={`absolute right-3 top-2.5 font-mono text-[10px] uppercase font-semibold ${
|
|
isNameValid ? 'text-secondary' : 'text-error'
|
|
}`}
|
|
>
|
|
{isNameValid ? 'VALID' : `${trimmedName.length}/50`}
|
|
</span>
|
|
</div>
|
|
<p className="font-body text-xs text-outline">
|
|
3-50 characters. Displayed on public discovery, ride manifests, and club roster.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Club Handle / Identifier (Locked) */}
|
|
<div className="space-y-1.5">
|
|
<div className="flex items-center justify-between">
|
|
<label className="font-mono text-[11px] text-outline uppercase font-medium">
|
|
Club Handle / Identifier
|
|
</label>
|
|
<span className="font-mono text-[10px] px-1.5 py-0.5 bg-surface-container-highest text-outline border border-outline-variant rounded">
|
|
IMMUTABLE
|
|
</span>
|
|
</div>
|
|
<div className="relative flex items-center">
|
|
<span className="material-symbols-outlined absolute left-3 text-outline text-base">lock</span>
|
|
<input
|
|
type="text"
|
|
value={`@${club.slug}`}
|
|
readOnly
|
|
disabled
|
|
className="w-full bg-surface-container-lowest border border-outline-variant rounded pl-9 pr-3 py-2 text-xs font-mono text-on-surface-variant cursor-not-allowed opacity-90"
|
|
/>
|
|
</div>
|
|
<p className="font-body text-xs text-outline">
|
|
Club handles are permanently reserved and cannot be renamed or reassigned.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Club Description */}
|
|
<div className="space-y-1.5">
|
|
<div className="flex items-center justify-between">
|
|
<label htmlFor="club-desc-input" className="font-mono text-[11px] text-outline uppercase block font-medium">
|
|
Club Description
|
|
</label>
|
|
<span className="font-mono text-[10px] text-outline">
|
|
{description.length}/500
|
|
</span>
|
|
</div>
|
|
<textarea
|
|
id="club-desc-input"
|
|
rows={3}
|
|
value={description}
|
|
onChange={(e) => setDescription(e.target.value)}
|
|
disabled={!permissions.canManageSettings || isSaving}
|
|
placeholder="Describe your club's ethos, riding discipline, and mission..."
|
|
className="w-full bg-surface-dim border border-outline-variant rounded p-3 text-sm font-body text-on-surface focus:border-primary focus:ring-0 outline-none transition-colors leading-relaxed"
|
|
/>
|
|
<p className="font-body text-xs text-outline">
|
|
Displayed on your public Club profile.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* SECTION 2: REGIONAL & MOTORCYCLE FOCUS */}
|
|
<div className="bg-surface-container-low border border-outline-variant rounded p-5 space-y-4">
|
|
<div className="flex items-center justify-between border-b border-outline-variant pb-3">
|
|
<div className="flex items-center gap-2">
|
|
<span className="material-symbols-outlined text-secondary text-lg">explore</span>
|
|
<h2 className="font-headline text-sm uppercase font-semibold text-on-surface">
|
|
SECTION 2: REGIONAL & MOTORCYCLE FOCUS
|
|
</h2>
|
|
</div>
|
|
<span className="font-mono text-[11px] text-outline">GEO / DISCIPLINE</span>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
{/* Home Region */}
|
|
<div className="space-y-1.5">
|
|
<label htmlFor="club-region-input" className="font-mono text-[11px] text-outline uppercase block font-medium">
|
|
Home Region
|
|
</label>
|
|
<input
|
|
id="club-region-input"
|
|
type="text"
|
|
value={homeRegion}
|
|
onChange={(e) => setHomeRegion(e.target.value)}
|
|
disabled={!permissions.canManageSettings || isSaving}
|
|
placeholder="e.g. Atlanta, Georgia"
|
|
className="w-full bg-surface-dim border border-outline-variant rounded px-3 py-2 text-sm font-body text-on-surface focus:border-primary focus:ring-0 outline-none transition-colors"
|
|
/>
|
|
<p className="font-body text-xs text-outline">Primary area where your Club is based.</p>
|
|
</div>
|
|
|
|
{/* Motorcycle Focus */}
|
|
<div className="space-y-1.5">
|
|
<label htmlFor="club-focus-input" className="font-mono text-[11px] text-outline uppercase block font-medium">
|
|
Motorcycle Focus
|
|
</label>
|
|
<input
|
|
id="club-focus-input"
|
|
type="text"
|
|
value={motorcycleFocus}
|
|
onChange={(e) => setMotorcycleFocus(e.target.value)}
|
|
disabled={!permissions.canManageSettings || isSaving}
|
|
placeholder="e.g. Sport / Touring"
|
|
className="w-full bg-surface-dim border border-outline-variant rounded px-3 py-2 text-sm font-body text-on-surface focus:border-primary focus:ring-0 outline-none transition-colors"
|
|
/>
|
|
<p className="font-body text-xs text-outline">
|
|
Main riding style or motorcycle focus for your Club.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* SECTION 3: LOGO & BANNER (Presentation Only) */}
|
|
<div className="bg-surface-container-low border border-outline-variant rounded p-5 space-y-4">
|
|
<div className="flex items-center justify-between border-b border-outline-variant pb-3">
|
|
<div className="flex items-center gap-2">
|
|
<span className="material-symbols-outlined text-secondary text-lg">palette</span>
|
|
<h2 className="font-headline text-sm uppercase font-semibold text-on-surface">
|
|
SECTION 3: LOGO & BANNER
|
|
</h2>
|
|
</div>
|
|
<span className="font-mono text-[11px] text-outline">VISUAL ASSETS</span>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
|
{/* Logo Presentation Card */}
|
|
<div className="bg-surface-dim border border-outline-variant rounded p-4 flex flex-col justify-between space-y-3">
|
|
<div className="font-mono text-[11px] text-outline uppercase">
|
|
<span>CLUB EMBLEM</span>
|
|
</div>
|
|
<div className="h-36 bg-surface-container-lowest border border-dashed border-outline-variant rounded flex flex-col items-center justify-center relative overflow-hidden">
|
|
{club.logoUrl ? (
|
|
<img src={club.logoUrl} alt="Club logo" className="max-h-24 max-w-24 object-contain" />
|
|
) : (
|
|
<div className="w-20 h-20 rounded-lg border-2 border-secondary bg-surface-container-high flex flex-col items-center justify-center shadow-lg relative">
|
|
<span className="material-symbols-outlined text-secondary text-2xl">two_wheeler</span>
|
|
<span className="font-headline text-secondary font-bold text-xs tracking-widest mt-1">
|
|
{initials}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center gap-1.5 font-mono text-[11px] text-outline">
|
|
<span className="material-symbols-outlined text-xs">info</span>
|
|
<span>Logo and banner editing is not available yet.</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Banner Presentation Card */}
|
|
<div className="bg-surface-dim border border-outline-variant rounded p-4 flex flex-col justify-between space-y-3">
|
|
<div className="font-mono text-[11px] text-outline uppercase">
|
|
<span>BANNER PRESENTATION</span>
|
|
</div>
|
|
<div className="h-36 bg-surface-container-lowest border border-dashed border-outline-variant rounded relative overflow-hidden flex items-center justify-center">
|
|
{club.bannerUrl ? (
|
|
<img
|
|
src={club.bannerUrl}
|
|
alt="Club banner presentation"
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full bg-surface-container-low flex items-center justify-center relative overflow-hidden">
|
|
<div className="absolute inset-0 bg-[radial-gradient(#3491ff_1px,transparent_1px)] [background-size:16px_16px] opacity-10" />
|
|
<div className="flex items-center gap-2 font-mono text-xs text-outline z-10">
|
|
<span className="material-symbols-outlined text-base text-secondary">image</span>
|
|
<span className="uppercase tracking-wider font-semibold">{club.name}</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center gap-1.5 font-mono text-[11px] text-outline">
|
|
<span className="material-symbols-outlined text-xs">info</span>
|
|
<span>Logo and banner editing is not available yet.</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* ACTION DOCKED FOOTER */}
|
|
<div className="bg-surface-container-low border border-outline-variant rounded p-4 flex flex-col sm:flex-row items-center justify-between gap-4">
|
|
<div className="flex items-center gap-2 font-body text-xs text-outline">
|
|
<span className="material-symbols-outlined text-secondary text-base">check_circle</span>
|
|
<span>Saves public club profile information.</span>
|
|
</div>
|
|
<button
|
|
type="submit"
|
|
disabled={!canSave || (!isDirty && saveStatus !== 'error')}
|
|
className={`w-full sm:w-auto flex items-center justify-center gap-2 px-5 py-2.5 rounded font-headline text-xs font-semibold uppercase tracking-wider transition-all duration-150 ${
|
|
canSave && (isDirty || saveStatus === 'error')
|
|
? 'bg-primary-container hover:bg-primary text-on-primary active:scale-[0.99] shadow-[0_0_15px_rgba(52,145,255,0.3)] cursor-pointer'
|
|
: 'bg-surface-container-high text-outline cursor-not-allowed opacity-60'
|
|
}`}
|
|
>
|
|
{isSaving ? (
|
|
<>
|
|
<span className="material-symbols-outlined text-base animate-spin">progress_activity</span>
|
|
<span>Saving Changes...</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<span className="material-symbols-outlined text-base">check</span>
|
|
<span>Save Profile Changes</span>
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* RIGHT RAIL (4 cols) */}
|
|
<div className="lg:col-span-4 space-y-6">
|
|
{/* CARD A: PUBLIC DIRECTORY PREVIEW (Live Simulation) */}
|
|
<div className="bg-surface-container-low border border-outline-variant rounded p-4 space-y-4">
|
|
<div className="flex items-center justify-between border-b border-outline-variant pb-2.5">
|
|
<div className="flex items-center gap-2">
|
|
<span className="material-symbols-outlined text-secondary text-base">visibility</span>
|
|
<span className="font-headline text-xs text-on-surface font-semibold uppercase">
|
|
DIRECTORY PREVIEW
|
|
</span>
|
|
</div>
|
|
<span className="font-mono text-[10px] bg-surface-container-high text-secondary px-2 py-0.5 rounded border border-secondary/30">
|
|
LIVE SIMULATION
|
|
</span>
|
|
</div>
|
|
|
|
{/* Embedded Public Card Mockup (IDENTITY ONLY, ZERO METRICS) */}
|
|
<div className="bg-surface-container border border-outline-variant rounded overflow-hidden shadow-lg">
|
|
{/* Banner Mockup */}
|
|
<div className="h-24 bg-surface-container-high relative overflow-hidden">
|
|
{club.bannerUrl ? (
|
|
<img
|
|
src={club.bannerUrl}
|
|
alt="Directory banner preview"
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full bg-surface-container-low flex items-center justify-center relative overflow-hidden">
|
|
<div className="absolute inset-0 bg-[radial-gradient(#3491ff_1px,transparent_1px)] [background-size:16px_16px] opacity-10" />
|
|
</div>
|
|
)}
|
|
<div className="absolute inset-0 bg-gradient-to-b from-transparent to-surface-container" />
|
|
</div>
|
|
|
|
<div className="p-4 pt-0 relative">
|
|
{/* Emblem overlapping */}
|
|
<div className="-mt-8 w-14 h-14 rounded bg-surface-dim border-2 border-secondary flex flex-col items-center justify-center text-secondary shadow-md">
|
|
<span className="material-symbols-outlined text-xl">two_wheeler</span>
|
|
<span className="font-mono text-[10px] font-bold leading-none">{initials}</span>
|
|
</div>
|
|
|
|
<div className="mt-2 flex items-center">
|
|
<h3 className="font-headline text-sm text-on-surface font-bold truncate">
|
|
{name || club.name}
|
|
</h3>
|
|
</div>
|
|
|
|
<div className="font-mono text-[11px] text-outline mt-0.5">@{club.slug}</div>
|
|
|
|
<div className="mt-2 inline-flex items-center gap-1.5 font-mono text-[10px] text-secondary bg-surface-container-highest px-2 py-0.5 rounded">
|
|
<span className="material-symbols-outlined text-xs">location_on</span>
|
|
<span className="truncate">
|
|
{homeRegion || 'Global'} • {motorcycleFocus || 'General'}
|
|
</span>
|
|
</div>
|
|
|
|
<p className="mt-3 font-body text-xs text-on-surface-variant line-clamp-2 leading-relaxed">
|
|
{description || 'No club description provided yet.'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<p className="font-mono text-[10px] text-outline text-center">
|
|
Rendered in standard public directory feed (1:1 responsive layout)
|
|
</p>
|
|
</div>
|
|
|
|
{/* CARD B: ACCESS & DISCOVERY BOUNDARY */}
|
|
<div className="bg-surface-container-low border border-outline-variant rounded p-4 space-y-3">
|
|
<div className="flex items-center gap-2 text-on-surface border-b border-outline-variant pb-2.5">
|
|
<span className="material-symbols-outlined text-secondary text-base">admin_panel_settings</span>
|
|
<h3 className="font-headline text-xs uppercase font-semibold">ACCESS CONTROLS</h3>
|
|
</div>
|
|
<p className="font-body text-xs text-on-surface-variant leading-relaxed">
|
|
Access settings (Visibility & Admission Policy) are managed separately under Club Settings.
|
|
</p>
|
|
<div className="pt-1 flex items-center">
|
|
<span className="inline-flex items-center gap-1.5 text-secondary font-mono text-xs cursor-default">
|
|
<span>Manage Access Settings</span>
|
|
<span className="material-symbols-outlined text-sm">arrow_forward</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* CARD C: PRIVACY CONTRACT */}
|
|
<div className="bg-surface-dim border border-outline-variant rounded p-4 space-y-3">
|
|
<div className="flex items-center gap-2 text-secondary">
|
|
<span className="material-symbols-outlined text-base">lock</span>
|
|
<span className="font-mono text-xs uppercase font-bold tracking-wider">PRIVACY CONTRACT</span>
|
|
</div>
|
|
<blockquote className="font-body text-xs italic text-on-surface border-l-2 border-secondary pl-3 py-1 bg-surface-container-lowest/50 rounded-r leading-relaxed">
|
|
“Public Club Profile is organizational identity only. Member telemetry, GPS tracks, personal ride logs, and private account data are not included.”
|
|
</blockquote>
|
|
<p className="font-mono text-[10px] text-outline">
|
|
Telemetry and member activity are strictly isolated.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|