import { useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, ScrollView, ActivityIndicator, Alert, KeyboardAvoidingView, Platform } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { router } from 'expo-router'; import { useQuery } from '@tanstack/react-query'; import { api } from '../../../services/api'; import { Icon } from '../../../components/Icon'; const STEP_LABELS = ['Client Info', 'Plan', 'Confirm']; // ── Step indicator ───────────────────────────────────────────────────────────── function StepBar({ step }: { step: number }) { return ( {STEP_LABELS.map((label, i) => { const active = i === step; const done = i < step; const circleColor = done || active ? '#0891B2' : '#CBD5E1'; const textColor = done || active ? '#0891B2' : '#94A3B8'; return ( {i > 0 && ( )} {done ? : {i + 1} } {i < STEP_LABELS.length - 1 && ( )} {label} ); })} ); } // ── Field ────────────────────────────────────────────────────────────────────── function Field({ label, value, onChangeText, placeholder, required = false, keyboardType = 'default', autoCapitalize = 'words', }: any) { return ( {label}{required && *} ); } export default function NewClientScreen() { const [step, setStep] = useState(0); const [submitting, setSubmitting] = useState(false); // Step 1 fields const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const [phone, setPhone] = useState(''); const [email, setEmail] = useState(''); const [address, setAddress] = useState(''); const [areaId, setAreaId] = useState(''); // Step 2 const [planId, setPlanId] = useState(''); const { data: areas = [] } = useQuery({ queryKey: ['areas'], queryFn: () => api.get('/api/v1/areas').then(r => r.data?.data ?? r.data ?? []), }); const { data: plans = [], isLoading: plansLoading } = useQuery({ queryKey: ['plans'], queryFn: () => api.get('/api/v1/plans').then(r => r.data?.data ?? r.data ?? []), }); const selectedPlan = (plans as any[]).find((p: any) => p.id === planId); // ── Validation ───────────────────────────────────────────────────────────── const validateStep1 = () => { if (!firstName.trim()) { Alert.alert('Required', 'First name is required.'); return false; } if (!lastName.trim()) { Alert.alert('Required', 'Last name is required.'); return false; } if (!phone.trim()) { Alert.alert('Required', 'Contact number is required.'); return false; } return true; }; const validateStep2 = () => { if (!planId) { Alert.alert('Required', 'Please select a plan.'); return false; } return true; }; const next = () => { if (step === 0 && !validateStep1()) return; if (step === 1 && !validateStep2()) return; setStep(s => s + 1); }; const back = () => { if (step === 0) router.back(); else setStep(s => s - 1); }; // ── Submit ───────────────────────────────────────────────────────────────── const submit = async () => { setSubmitting(true); try { // 1. Create client const clientRes = await api.post('/api/v1/clients', { firstName: firstName.trim(), lastName: lastName.trim(), phone: phone.trim(), ...(email.trim() ? { email: email.trim() } : {}), ...(address.trim() ? { address: address.trim() } : {}), ...(areaId ? { areaId } : {}), }); const client = clientRes.data; // 2. Create subscription (PENDING until installation confirmed) await api.post('/api/v1/subscriptions', { clientId: client.id, planId, type: 'POSTPAID', status: 'PENDING', billingDay: 5, startDate: new Date().toISOString(), }); // 3. Create installation ticket const ticketRes = await api.post('/api/v1/tickets', { clientId: client.id, subject: `New Installation — ${firstName.trim()} ${lastName.trim()}`, type: 'INSTALLATION', priority: 'NORMAL', }); const ticket = ticketRes.data; Alert.alert( 'Client Onboarded! 🎉', `${firstName} ${lastName} has been registered.\n\nAn installation ticket has been created.`, [{ text: 'View Ticket', onPress: () => { router.replace('/(app)/clients'); setTimeout(() => router.push(`/(app)/tasks/${ticket.id}`), 300); }, }, { text: 'Done', onPress: () => router.replace('/(app)/clients'), }] ); } catch (e: any) { const msg = e?.response?.data?.message ?? 'Something went wrong. Please try again.'; Alert.alert('Error', Array.isArray(msg) ? msg.join('\n') : msg); } finally { setSubmitting(false); } }; return ( {/* Header */} New Client Onboarding {/* ── Step 1: Client Info ─────────────────────────────────────────── */} {step === 0 && ( Client Information Fill in the new subscriber's details. {/* Area picker */} Area / Zone {(areas as any[]).map((a: any) => ( setAreaId(areaId === a.id ? '' : a.id)} style={{ paddingHorizontal: 14, paddingVertical: 8, borderRadius: 20, backgroundColor: areaId === a.id ? '#0891B2' : '#F1F5F9', borderWidth: 1, borderColor: areaId === a.id ? '#0891B2' : '#E2E8F0', }} > {a.name} ))} )} {/* ── Step 2: Plan Selection ──────────────────────────────────────── */} {step === 1 && ( Select a Plan Choose the internet plan for this subscriber. {plansLoading ? : (plans as any[]).filter((p: any) => p.isActive !== false).map((p: any) => { const selected = planId === p.id; return ( setPlanId(p.id)} style={{ backgroundColor: selected ? '#ECFEFF' : '#fff', borderWidth: 2, borderColor: selected ? '#0891B2' : '#E2E8F0', borderRadius: 14, padding: 18, marginBottom: 12, flexDirection: 'row', alignItems: 'center', }} > {p.name} ↓ {p.speedDownMbps} Mbps ↑ {p.speedUpMbps} Mbps {p.description ? ( {p.description} ) : null} ₱{Number(p.monthlyPrice).toLocaleString()} /month {selected && ( )} ); }) } )} {/* ── Step 3: Confirm ─────────────────────────────────────────────── */} {step === 2 && ( Confirm & Submit Review the details before creating the account. {/* Client card */} CLIENT {email ? : null} {address ? : null} {areaId ? a.id === areaId)?.name ?? ''} /> : null} {/* Plan card */} PLAN {/* What will happen */} What happens next {['Client record will be created', 'Subscription set to Pending (activates after install)', 'Installation ticket created automatically'].map((s, i) => ( {s} ))} )} {/* Footer buttons */} {step > 0 && ( Back )} {step < 2 ? ( {step === 0 ? 'Next: Select Plan →' : 'Next: Review →'} ) : ( {submitting ? : ✓ Create & Schedule Install } ) } ); } function Row({ label, value, isLast = false }: { label: string; value: string; isLast?: boolean }) { if (!value) return null; return ( {label} {value} ); }