/** * In-App Citizenship Application Modal * Self-contained modal with 3 steps: form → processing → success * Uses the already-connected wallet keypair (no seed phrase needed) */ import { useState, useEffect, useRef } from 'react'; import { X, Plus, Trash2, Shield, CheckCircle, Clock, ArrowRight, AlertCircle } from 'lucide-react'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; import { useTranslation } from '@/i18n'; import { KurdistanSun } from '@/components/KurdistanSun'; import { formatAddress } from '@/lib/utils'; import type { Region, MaritalStatus, ChildInfo } from '@/lib/citizenship'; import { calculateIdentityHash, saveCitizenshipLocally, uploadToIPFS, applyCitizenship, } from '@/lib/citizenship'; interface CitizenshipModalProps { isOpen: boolean; onClose: () => void; } type Step = 'form' | 'processing' | 'success'; const REGIONS: { value: Region; labelKey: string }[] = [ { value: 'bakur', labelKey: 'citizen.regionBakur' }, { value: 'basur', labelKey: 'citizen.regionBasur' }, { value: 'rojava', labelKey: 'citizen.regionRojava' }, { value: 'rojhelat', labelKey: 'citizen.regionRojhelat' }, { value: 'kurdistan_a_sor', labelKey: 'citizen.regionKurdistanASor' }, { value: 'diaspora', labelKey: 'citizen.regionDiaspora' }, ]; export function CitizenshipModal({ isOpen, onClose }: CitizenshipModalProps) { const { peopleApi, keypair, address } = useWallet(); const { hapticImpact, hapticNotification } = useTelegram(); const { t } = useTranslation(); const [step, setStep] = useState('form'); const [error, setError] = useState(''); // Form fields const [fullName, setFullName] = useState(''); const [fatherName, setFatherName] = useState(''); const [grandfatherName, setGrandfatherName] = useState(''); const [motherName, setMotherName] = useState(''); const [tribe, setTribe] = useState(''); const [maritalStatus, setMaritalStatus] = useState('nezewici'); const [childrenCount, setChildrenCount] = useState(0); const [children, setChildren] = useState([]); const [region, setRegion] = useState(''); const [email, setEmail] = useState(''); const [profession, setProfession] = useState(''); const [referrerAddress, setReferrerAddress] = useState(''); const [consent, setConsent] = useState(false); // Success data const [identityHash, setIdentityHash] = useState(''); // Processing cancel ref const cancelledRef = useRef(false); // Reset state when modal opens useEffect(() => { if (isOpen) { setStep('form'); setError(''); setFullName(''); setFatherName(''); setGrandfatherName(''); setMotherName(''); setTribe(''); setMaritalStatus('nezewici'); setChildrenCount(0); setChildren([]); setRegion(''); setEmail(''); setProfession(''); setReferrerAddress(''); setConsent(false); setIdentityHash(''); cancelledRef.current = false; } }, [isOpen]); // --- Form handlers --- const handleMaritalChange = (status: MaritalStatus) => { hapticImpact('light'); setMaritalStatus(status); if (status === 'nezewici') { setChildrenCount(0); setChildren([]); } }; const handleChildrenCountChange = (count: number) => { const c = Math.max(0, Math.min(20, count)); setChildrenCount(c); setChildren((prev) => { if (c > prev.length) { return [ ...prev, ...Array.from({ length: c - prev.length }, () => ({ name: '', birthYear: 2000 })), ]; } return prev.slice(0, c); }); }; const updateChild = (index: number, field: keyof ChildInfo, value: string | number) => { setChildren((prev) => prev.map((child, i) => (i === index ? { ...child, [field]: value } : child)) ); }; const addChild = () => { hapticImpact('light'); handleChildrenCountChange(childrenCount + 1); }; const removeChild = (index: number) => { hapticImpact('light'); setChildren((prev) => prev.filter((_, i) => i !== index)); setChildrenCount((prev) => prev - 1); }; const handleFormSubmit = () => { setError(''); if ( !fullName || !fatherName || !grandfatherName || !motherName || !tribe || !region || !email || !profession ) { setError(t('citizen.fillAllFields')); hapticNotification('error'); return; } if (!consent) { setError(t('citizen.acceptConsent')); hapticNotification('error'); return; } if (!peopleApi) { setError(t('citizen.peopleChainNotConnected')); hapticNotification('error'); return; } if (!keypair || !address) { setError(t('citizen.walletNotConnected')); hapticNotification('error'); return; } hapticImpact('medium'); setStep('processing'); }; // --- Processing logic --- useEffect(() => { if (step !== 'processing') return; cancelledRef.current = false; const process = async () => { try { if (!peopleApi || !keypair || !address) { setError(t('citizen.walletNotConnected')); setStep('form'); return; } // Build citizenship data for local save const citizenshipData = { fullName, fatherName, grandfatherName, motherName, tribe, maritalStatus, childrenCount: maritalStatus === 'zewici' ? childrenCount : undefined, children: maritalStatus === 'zewici' && children.length > 0 ? children : undefined, region: region as Region, email, profession, referrerAddress: referrerAddress || undefined, walletAddress: address, seedPhrase: '', timestamp: Date.now(), }; // Mock IPFS upload const ipfsCid = await uploadToIPFS(citizenshipData); if (cancelledRef.current) return; // Calculate identity hash const hash = calculateIdentityHash(fullName, email, [ipfsCid]); if (cancelledRef.current) return; setIdentityHash(hash); // Save encrypted data locally saveCitizenshipLocally(citizenshipData); // Sign and submit extrinsic const result = await applyCitizenship(peopleApi, keypair, hash, referrerAddress || null); if (cancelledRef.current) return; if (result.success) { hapticNotification('success'); setStep('success'); } else { hapticNotification('error'); setError(result.error || t('citizen.submissionFailed')); setStep('form'); } } catch (err) { if (cancelledRef.current) return; hapticNotification('error'); setError(err instanceof Error ? err.message : t('citizen.submissionFailed')); setStep('form'); } }; process(); return () => { cancelledRef.current = true; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [step]); if (!isOpen) return null; const inputClass = 'w-full px-4 py-3 bg-muted rounded-xl text-sm'; const labelClass = 'text-sm text-muted-foreground mb-1 block'; // --- Processing Step --- if (step === 'processing') { return (

{t('citizen.applyingCitizenship')}

{fullName}

); } // --- Success Step --- if (step === 'success') { return (
{/* Success Icon */}
{/* Title */}

{t('citizen.applicationSuccess')}

{/* 3-Step Process */}

{t('citizen.stepApplicationSent')}

{t('citizen.stepReferrerApproval')}

{t('citizen.stepConfirm')}

{/* Application Info */}

{t('citizen.identityHash')}

{formatAddress(identityHash)}

{t('citizen.walletAddress')}

{formatAddress(address || '')}

{/* Next Steps Info */}

{t('citizen.nextStepsInfo')}

{/* Close Button */}
); } // --- Form Step --- return (
{/* Header */}

{t('citizen.pageTitle')}

{/* Form Content */}
{/* Privacy Notice */}

{t('citizen.privacyNotice')}

{/* Full Name */}
setFullName(e.target.value)} className={inputClass} placeholder={t('citizen.fullNamePlaceholder')} />
{/* Father's Name */}
setFatherName(e.target.value)} className={inputClass} placeholder={t('citizen.fatherNamePlaceholder')} />
{/* Grandfather's Name */}
setGrandfatherName(e.target.value)} className={inputClass} placeholder={t('citizen.grandfatherNamePlaceholder')} />
{/* Mother's Name */}
setMotherName(e.target.value)} className={inputClass} placeholder={t('citizen.motherNamePlaceholder')} />
{/* Tribe */}
setTribe(e.target.value)} className={inputClass} placeholder={t('citizen.tribePlaceholder')} />
{/* Marital Status */}
{/* Children (if married) */} {maritalStatus === 'zewici' && (
{children.map((child, index) => (
updateChild(index, 'name', e.target.value)} className={inputClass} placeholder={t('citizen.childNamePlaceholder')} />
updateChild(index, 'birthYear', parseInt(e.target.value) || 2000) } className={inputClass} min={1950} max={2026} />
))}
)} {/* Region */}
{/* Email */}
setEmail(e.target.value)} className={inputClass} placeholder={t('citizen.emailPlaceholder')} />
{/* Profession */}
setProfession(e.target.value)} className={inputClass} placeholder={t('citizen.professionPlaceholder')} />
{/* Referrer Address */}
setReferrerAddress(e.target.value)} className={inputClass} placeholder={t('citizen.referrerPlaceholder')} />
{/* Consent */} {/* Error */} {error && (
{error}
)} {/* Submit Button */}
); }