import React, { useEffect, useMemo, useState } from 'react'; import { ScrollView, StyleSheet, Text, View } from 'react-native'; import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useAppDispatch, useAppSelector } from '../../../app/hooks'; import { Button, Card, Input, ScreenShell } from '../../../components'; import { ToggleSwitch } from '../../cards/components/ToggleSwitch'; import { useToast } from '../../../hooks/useToast'; import type { InsuranceStackParamList } from '../../../navigation/types'; import { useTheme, fontFamily } from '../../../theme'; import { formatCompactCurrency, formatCurrency } from '../../../utils/formatters'; import { InsuranceCategoryChip } from '../components/InsuranceCategoryChip'; import { InsuranceOtpModal } from '../components/InsuranceOtpModal'; import { InsurancePaymentMethodTile } from '../components/InsurancePaymentMethodTile'; import { InsurancePlanCard } from '../components/InsurancePlanCard'; import { useInsurancePlans } from '../hooks/useInsurancePlans'; import { usePurchaseInsurancePolicyMutation, useRequestInsuranceOtpMutation, } from '../services/insuranceApi'; import { selectInsuranceComparedPlanIds, selectInsuranceDraft, selectInsurancePurchaseStep, } from '../store/insuranceSelectors'; import { insuranceActions } from '../store/insuranceSlice'; import { INSURANCE_CATEGORIES, INSURANCE_CATEGORY_META } from '../types'; import { validateInsuranceOtp, validateInsurancePurchaseDraft } from '../utils/insuranceValidation'; type Props = NativeStackScreenProps; const STEP_LABELS = [ { id: 'details', label: 'Details' }, { id: 'plans', label: 'Plans' }, { id: 'payment', label: 'Payment' }, ] as const; export default function BuyInsuranceScreen({ navigation, route }: Props) { const dispatch = useAppDispatch(); const theme = useTheme(); const toast = useToast(); const draft = useAppSelector(selectInsuranceDraft); const comparedPlanIds = useAppSelector(selectInsuranceComparedPlanIds); const purchaseStep = useAppSelector(selectInsurancePurchaseStep); const { data: plans = [], isLoading } = useInsurancePlans(draft.category); const [requestOtp, requestOtpState] = useRequestInsuranceOtpMutation(); const [purchasePolicy, purchasePolicyState] = usePurchaseInsurancePolicyMutation(); const [errors, setErrors] = useState>({}); const [otp, setOtp] = useState(''); const [otpVisible, setOtpVisible] = useState(false); const [otpError, setOtpError] = useState(); const [mockCodeHint, setMockCodeHint] = useState(); useEffect(() => { if (route.params?.category) { dispatch(insuranceActions.setInsuranceCategory(route.params.category)); } }, [dispatch, route.params?.category]); const selectedPlan = useMemo( () => plans.find((plan) => plan.id === draft.selectedPlanId) ?? null, [draft.selectedPlanId, plans], ); const handleContinueFromDetails = () => { const validationErrors = validateInsurancePurchaseDraft(draft, draft.category); setErrors(validationErrors); if (Object.keys(validationErrors).length) { return; } dispatch(insuranceActions.setInsurancePurchaseStep('plans')); }; const handleContinueFromPlans = () => { if (!draft.selectedPlanId) { setErrors({ selectedPlanId: 'Select a plan to continue.' }); return; } setErrors({}); dispatch(insuranceActions.setInsurancePurchaseStep('payment')); }; const handleRequestOtp = async () => { const error = !draft.selectedPlanId ? 'Select a plan to continue.' : undefined; if (error) { setErrors({ selectedPlanId: error }); return; } const result = await requestOtp({ action: 'purchase' }); if ('data' in result && result.data) { setMockCodeHint(result.data.mockCodeHint); setOtpVisible(true); setOtpError(undefined); return; } toast('Unable to send OTP', 'error', 'We could not send your code right now. Please try again.'); }; const handleConfirmPurchase = async () => { const error = validateInsuranceOtp(otp); if (error) { setOtpError(error); return; } const result = await purchasePolicy({ draft, otp }); if ('data' in result && result.data) { setOtpVisible(false); setOtp(''); setOtpError(undefined); toast( 'Policy issued', 'success', `${result.data.policy.planName} is now active under ${result.data.policy.policyNumber}.`, ); dispatch(insuranceActions.resetInsuranceDraft()); navigation.replace('InsurancePolicyDetails', { policyId: result.data.policy.id }); return; } setOtpError('Verification failed. Please try again.'); }; const renderStepPills = () => ( {STEP_LABELS.map((step) => { const isActive = purchaseStep === step.id; return ( {step.label} ); })} ); return ( {renderStepPills()} Choose category {INSURANCE_CATEGORIES.map((category) => ( { dispatch(insuranceActions.setInsuranceCategory(category)); setErrors({}); }} /> ))} {INSURANCE_CATEGORY_META[draft.category].description} {purchaseStep === 'details' ? ( <> Personal details dispatch( insuranceActions.updateInsurancePersonal({ field: 'fullName', value }), ) } error={errors.personalFullName} /> dispatch( insuranceActions.updateInsurancePersonal({ field: 'age', value }), ) } error={errors.personalAge} /> dispatch( insuranceActions.updateInsurancePersonal({ field: 'gender', value }), ) } error={errors.personalGender} /> dispatch( insuranceActions.updateInsurancePersonal({ field: 'email', value }), ) } error={errors.personalEmail} /> dispatch( insuranceActions.updateInsurancePersonal({ field: 'phone', value }), ) } error={errors.personalPhone} /> Nominee and address dispatch( insuranceActions.updateInsuranceNominee({ field: 'name', value }), ) } error={errors.nomineeName} /> dispatch( insuranceActions.updateInsuranceNominee({ field: 'relationship', value, }), ) } error={errors.nomineeRelationship} /> dispatch( insuranceActions.updateInsuranceNominee({ field: 'age', value }), ) } error={errors.nomineeAge} /> dispatch( insuranceActions.updateInsuranceAddress({ field: 'line1', value }), ) } error={errors.addressLine1} /> dispatch( insuranceActions.updateInsuranceAddress({ field: 'city', value }), ) } error={errors.addressCity} /> dispatch( insuranceActions.updateInsuranceAddress({ field: 'state', value }), ) } error={errors.addressState} /> dispatch( insuranceActions.updateInsuranceAddress({ field: 'postalCode', value, }), ) } error={errors.addressPostalCode} /> KYC and policy-specific details dispatch(insuranceActions.updateInsuranceKyc({ field: 'aadhaarNumber', value })) } error={errors.kycAadhaar} /> dispatch(insuranceActions.updateInsuranceKyc({ field: 'panNumber', value })) } error={errors.kycPan} /> {INSURANCE_CATEGORY_META[draft.category].specificFields.map((field) => ( dispatch( insuranceActions.updateInsuranceSpecificDetail({ key: field.key, value, }), ) } keyboardType={field.keyboardType} placeholder={field.placeholder} multiline={field.multiline} error={errors[`specific_${field.key}`]} /> ))}