import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { CheckCircle2, ArrowRight, ArrowLeft, Building2, UserCircle, Smartphone, SkipForward, Loader2, Eye, EyeOff } from 'lucide-react'; import { useAuth } from '../lib/auth'; import { api } from '../lib/api'; import { initMetaSDK, launchEmbeddedSignup } from '../lib/meta-signup'; import { useToast } from '../hooks/useToast'; import { logError, logWarn } from '../lib/logger'; // ─── Modes ─────────────────────────────────────────────────────────────────── const MODE_KEYS = [ { value: 'EDTECH', labelKey: 'onboarding.mode_edtech_label', descKey: 'onboarding.mode_edtech_desc' }, { value: 'CRM_MARKETING', labelKey: 'onboarding.mode_crm_label', descKey: 'onboarding.mode_crm_desc' }, { value: 'AI_AGENT', labelKey: 'onboarding.mode_ai_label', descKey: 'onboarding.mode_ai_desc' }, { value: 'CUSTOMER_SERVICE', labelKey: 'onboarding.mode_customer_service_label', descKey: 'onboarding.mode_customer_service_desc' }, ]; // ─── Slug helpers ───────────────────────────────────────────────────────────── function toSlug(name: string): string { return name .toLowerCase() .normalize('NFD').replace(/[̀-ͯ]/g, '') .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, '') .slice(0, 40); } // ─── Steps ─────────────────────────────────────────────────────────────────── const STEP_KEYS = [ { id: 'org', titleKey: 'onboarding.step_org', icon: Building2 }, { id: 'admin', titleKey: 'onboarding.step_admin', icon: UserCircle }, { id: 'whatsapp', titleKey: 'onboarding.step_whatsapp', icon: Smartphone }, ]; // ─── Wizard ────────────────────────────────────────────────────────────────── export default function OnboardingWizard() { const { t } = useTranslation(); const [step, setStep] = useState(0); const [loading, setLoading] = useState(false); const [showPass, setShowPass] = useState(false); const { token } = useAuth(); const navigate = useNavigate(); const toast = useToast(); const [org, setOrg] = useState({ name: '', slug: '', slugTouched: false, mode: 'EDTECH', }); const [admin, setAdmin] = useState({ adminName: '', adminEmail: '', password: '', }); const [wa, setWa] = useState({ wabaId: '', metaBusinessId: '', accessToken: '', skip: false, }); const [tokenValidState, setTokenValidState] = useState<'idle' | 'checking' | 'valid' | 'invalid'>('idle'); const validateToken = async (tok: string) => { if (!tok.trim() || !token) return; setTokenValidState('checking'); try { const res = await api.post('/v1/organizations/whatsapp-validate-token', { token: tok }, token); setTokenValidState(res.valid ? 'valid' : 'invalid'); } catch { setTokenValidState('idle'); } }; // Auto-generate slug from name unless user edited it manually useEffect(() => { if (!org.slugTouched) { setOrg(s => ({ ...s, slug: toSlug(s.name) })); } }, [org.name, org.slugTouched]); useEffect(() => { initMetaSDK(); }, []); // ── Navigation ────────────────────────────────────────────────────────────── const canNext = () => { if (step === 0) return org.name.trim().length >= 2 && org.slug.length >= 3; if (step === 1) return admin.adminEmail.includes('@') && admin.adminName.trim().length >= 2; return true; }; const next = () => setStep(s => Math.min(s + 1, STEP_KEYS.length - 1)); const back = () => setStep(s => Math.max(s - 1, 0)); // ── Submit ────────────────────────────────────────────────────────────────── const handleSubmit = async () => { setLoading(true); try { // 1. Create organisation + admin user const result = await api.post('/v1/organizations', { name: org.name.trim(), slug: org.slug, mode: org.mode, adminName: admin.adminName.trim(), adminEmail: admin.adminEmail.trim().toLowerCase(), ...(admin.password && { password: admin.password }), }, token) as { id: string; admin: { tempPassword: string } }; const newOrgId = result.id; // 2. Connect WhatsApp if provided if (!wa.skip && wa.wabaId) { await api.post(`/v1/organizations/${newOrgId}/whatsapp-setup`, { wabaId: wa.wabaId.trim(), ...(wa.accessToken && { accessToken: wa.accessToken.trim() }), }, token); if (wa.metaBusinessId) { await api.put(`/v1/organizations/${newOrgId}`, { metaBusinessId: wa.metaBusinessId.trim(), }, token); } } navigate('/clients'); } catch (err: any) { logError(err); toast.error(err.message || t('onboarding.create_error')); } finally { setLoading(false); } }; // ── Embedded Signup ───────────────────────────────────────────────────────── const handleEmbeddedSignup = async () => { try { const result = await launchEmbeddedSignup(); setWa(s => ({ ...s, wabaId: result.waba_id, accessToken: result.code, skip: false, })); } catch (err) { logWarn('[OnboardingWizard] Facebook login failed', err); toast.error(t('onboarding.fb_error')); } }; // ── Render ────────────────────────────────────────────────────────────────── return (
{t('onboarding.org_subtitle')}
{t('onboarding.slug_hint')}
{t('onboarding.admin_subtitle')}
{t('onboarding.admin_pass_hint')}
{t('onboarding.wa_subtitle')}
{t('onboarding.fb_account_connected')}
WABA : {wa.wabaId}
{t('onboarding.already_configured')}
WhatsApp Manager → colonne "Compte WhatsApp Business"
✅ {t('onboarding.token_valid_msg')}
)} {tokenValidState === 'invalid' && (❌ {t('onboarding.token_invalid_msg')}
)} {tokenValidState === 'idle' && ({t('onboarding.token_idle_hint')}
)}{t('onboarding.new_account_via_fb')}
{t('onboarding.new_account_desc')}