import { useState, useRef } from 'react' import { AnimatePresence, motion } from 'framer-motion' import { ArrowRight, ArrowLeft, Check, Loader2, Sparkles, Camera } from 'lucide-react' import { supa } from '../lib/supabase' import { useApp } from '../lib/AppContext' import { useFeedback } from '../lib/feedback' import { uploadAvatar } from '../lib/avatar' import { MemberRole, Profile, POLE_LABELS, poleColor, SELF_ASSIGNABLE_POLES, CRITICAL_POLES, memberPoles } from '../lib/types' import { Avatar } from '../components/ui' import Logo from '../components/Logo' const COLORS = ['#7c5cff', '#00d2b8', '#ff5c8a', '#ffa53c', '#3ca8ff', '#9bdb4d', '#e15cff', '#ff6b6b'] export default function Onboarding(): JSX.Element { const { profile, refreshProfile } = useApp() const { toast } = useFeedback() // Rôles critiques déjà attribués par l'admin (ex : chef de projet) : on les // conserve, mais le membre ne peut pas se les donner lui-même. const keptCritical = memberPoles(profile ?? {}).filter((p) => CRITICAL_POLES.includes(p)) // Découpe le nom existant (« Prénom Nom ») s'il y en a un. const existingName = profile && profile.full_name !== 'Membre' ? profile.full_name : '' const [step, setStep] = useState(0) const [firstName, setFirstName] = useState(existingName.split(' ')[0] ?? '') const [lastName, setLastName] = useState(existingName.split(' ').slice(1).join(' ')) const [color, setColor] = useState(profile?.avatar_color ?? COLORS[0]) const [avatarUrl, setAvatarUrl] = useState(profile?.avatar_url ?? null) const [uploading, setUploading] = useState(false) const [poles, setPoles] = useState( memberPoles(profile ?? {}).filter((p) => SELF_ASSIGNABLE_POLES.includes(p)) ) const [busy, setBusy] = useState(false) const fileRef = useRef(null) const togglePole = (p: MemberRole): void => setPoles((cur) => (cur.includes(p) ? cur.filter((x) => x !== p) : [...cur, p])) const fullName = `${firstName.trim()} ${lastName.trim()}`.trim() const previewProfile = { full_name: fullName || '?', avatar_color: color, avatar_url: avatarUrl } as unknown as Profile const pickPhoto = async (e: React.ChangeEvent): Promise => { const file = e.target.files?.[0] if (!file || !profile) return if (!file.type.startsWith('image/')) { toast('Choisis un fichier image.', 'error') return } setUploading(true) try { const url = await uploadAvatar(file, profile.id) setAvatarUrl(url) } catch (err) { toast((err as Error).message, 'error') } finally { setUploading(false) } } const steps = ['Ton nom', 'Ta photo', 'Tes pôles'] const canNext = step === 0 ? firstName.trim().length > 0 : true const finish = async (): Promise => { if (!profile) return setBusy(true) const roles = Array.from(new Set([...poles, ...keptCritical])) const finalRoles = roles.length ? roles : (['other'] as MemberRole[]) const { error } = await supa() .from('profiles') .update({ full_name: fullName || 'Membre', avatar_color: color, avatar_url: avatarUrl, roles: finalRoles, role: finalRoles[0], onboarded: true }) .eq('id', profile.id) if (error) { setBusy(false) toast(error.message, 'error') return } await refreshProfile() // Le passage onboarded=true bascule automatiquement vers l'app. } const next = (): void => { if (step < steps.length - 1) setStep((s) => s + 1) else finish() } return (
{/* En-tête */}

Bienvenue dans l'équipe 👋

Configurons ton profil en 3 étapes.

{/* Barre de progression */}
{steps.map((_, i) => (
))}
{step === 0 && (
setFirstName(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && canNext && next()} />
setLastName(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && canNext && next()} />

C'est le nom que tes coéquipiers verront sur les tâches.

)} {step === 1 && (
{uploading && (
)}
{avatarUrl && ( )}
{/* Repli : couleur des initiales si aucune photo */} {!avatarUrl && (

Ou choisis une couleur

{COLORS.map((c) => (
)}

Optionnel — tu pourras la changer plus tard depuis « Équipe ».

)} {step === 2 && (
{SELF_ASSIGNABLE_POLES.map((p) => { const on = poles.includes(p) return ( ) })}
{keptCritical.length > 0 && (

Ton rôle {keptCritical.map((p) => POLE_LABELS[p]).join(', ')} t'a été attribué par l'administrateur.

)}

Tu recevras une notification quand une tâche est confiée à un de tes pôles.

)}
{/* Navigation */}
{step > 0 ? ( ) : ( )}
) }