feat: prepaid/postpaid onboarding; prepaid payment gate on activation ticket; slide-to-confirm on all payments; pay button on dashboard invoices
This commit is contained in:
@@ -89,7 +89,8 @@ export default function NewClientScreen() {
|
||||
const [areaId, setAreaId] = useState('');
|
||||
|
||||
// Step 2
|
||||
const [planId, setPlanId] = useState('');
|
||||
const [planId, setPlanId] = useState('');
|
||||
const [subType, setSubType] = useState<'PREPAID' | 'POSTPAID'>('POSTPAID');
|
||||
|
||||
const { data: areas = [] } = useQuery({
|
||||
queryKey: ['areas'],
|
||||
@@ -142,12 +143,12 @@ export default function NewClientScreen() {
|
||||
|
||||
// 2. Create subscription (PENDING until installation confirmed)
|
||||
await api.post('/api/v1/subscriptions', {
|
||||
clientId: client.id,
|
||||
clientId: client.id,
|
||||
planId,
|
||||
type: 'POSTPAID',
|
||||
status: 'PENDING',
|
||||
billingDay: 5,
|
||||
startDate: new Date().toISOString(),
|
||||
type: subType,
|
||||
status: 'PENDING',
|
||||
billingDay: 5,
|
||||
startDate: new Date().toISOString(),
|
||||
});
|
||||
|
||||
// 3. Create installation ticket
|
||||
@@ -156,6 +157,8 @@ export default function NewClientScreen() {
|
||||
subject: `New Installation — ${firstName.trim()} ${lastName.trim()}`,
|
||||
type: 'INSTALLATION',
|
||||
priority: 'NORMAL',
|
||||
// Pass subType so activation ticket knows to gate on payment for PREPAID
|
||||
...(subType === 'PREPAID' ? { priority: 'HIGH' } : {}),
|
||||
});
|
||||
const ticket = ticketRes.data;
|
||||
|
||||
@@ -252,7 +255,27 @@ export default function NewClientScreen() {
|
||||
{step === 1 && (
|
||||
<View>
|
||||
<Text style={{ fontSize: 20, fontWeight: '700', color: '#1E293B', marginBottom: 4 }}>Select a Plan</Text>
|
||||
<Text style={{ fontSize: 15, color: '#64748B', marginBottom: 20 }}>Choose the internet plan for this subscriber.</Text>
|
||||
<Text style={{ fontSize: 15, color: '#64748B', marginBottom: 20 }}>Choose the internet plan and billing type.</Text>
|
||||
|
||||
{/* Subscription type toggle */}
|
||||
<View style={{ marginBottom: 20 }}>
|
||||
<Text style={{ fontSize: 13, fontWeight: '600', color: '#64748B', marginBottom: 8 }}>Billing Type <Text style={{ color: '#DC2626' }}>*</Text></Text>
|
||||
<View style={{ flexDirection: 'row', backgroundColor: '#F1F5F9', borderRadius: 12, padding: 4 }}>
|
||||
{(['POSTPAID', 'PREPAID'] as const).map(t => (
|
||||
<TouchableOpacity key={t} onPress={() => setSubType(t)} style={{ flex: 1, paddingVertical: 10, borderRadius: 10, alignItems: 'center', backgroundColor: subType === t ? '#fff' : 'transparent' }}>
|
||||
<Text style={{ fontSize: 14, fontWeight: '700', color: subType === t ? '#0891B2' : '#94A3B8' }}>{t}</Text>
|
||||
<Text style={{ fontSize: 11, color: subType === t ? '#64748B' : '#CBD5E1', marginTop: 1 }}>
|
||||
{t === 'POSTPAID' ? 'Pay after billing day' : 'Pay before activation'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
{subType === 'PREPAID' && (
|
||||
<View style={{ backgroundColor: '#FFFBEB', borderRadius: 10, padding: 10, marginTop: 8, borderWidth: 1, borderColor: '#FDE68A' }}>
|
||||
<Text style={{ fontSize: 13, color: '#92400E' }}>⚠️ Prepaid clients must settle their first payment before the account can be activated.</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{plansLoading
|
||||
? <ActivityIndicator color="#0891B2" />
|
||||
@@ -319,11 +342,19 @@ export default function NewClientScreen() {
|
||||
{/* Plan card */}
|
||||
<View style={{ backgroundColor: '#fff', borderRadius: 14, padding: 18, marginBottom: 12, borderWidth: 1, borderColor: '#E2E8F0' }}>
|
||||
<Text style={{ fontSize: 13, fontWeight: '700', color: '#94A3B8', marginBottom: 12, letterSpacing: 0.5 }}>PLAN</Text>
|
||||
<Row label="Plan" value={selectedPlan?.name ?? ''} />
|
||||
<Row label="Speed" value={`↓ ${selectedPlan?.speedDownMbps} Mbps ↑ ${selectedPlan?.speedUpMbps} Mbps`} />
|
||||
<Row label="Price" value={`₱${Number(selectedPlan?.monthlyPrice ?? 0).toLocaleString()}/month`} isLast />
|
||||
<Row label="Plan" value={selectedPlan?.name ?? ''} />
|
||||
<Row label="Speed" value={`↓ ${selectedPlan?.speedDownMbps} Mbps ↑ ${selectedPlan?.speedUpMbps} Mbps`} />
|
||||
<Row label="Price" value={`₱${Number(selectedPlan?.monthlyPrice ?? 0).toLocaleString()}/month`} />
|
||||
<Row label="Billing" value={subType} isLast />
|
||||
</View>
|
||||
|
||||
{subType === 'PREPAID' && (
|
||||
<View style={{ backgroundColor: '#FFFBEB', borderRadius: 12, padding: 14, marginBottom: 12, borderWidth: 1, borderColor: '#FDE68A' }}>
|
||||
<Text style={{ fontSize: 14, fontWeight: '700', color: '#92400E', marginBottom: 4 }}>⚠️ Prepaid — Payment Required Before Activation</Text>
|
||||
<Text style={{ fontSize: 13, color: '#92400E' }}>After installation, a payment of ₱{Number(selectedPlan?.monthlyPrice ?? 0).toLocaleString()} must be collected before the account goes active.</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* What will happen */}
|
||||
<View style={{ backgroundColor: '#ECFEFF', borderRadius: 12, padding: 16, borderWidth: 1, borderColor: '#A5F3FC' }}>
|
||||
<Text style={{ fontSize: 14, fontWeight: '700', color: '#0E7490', marginBottom: 8 }}>What happens next</Text>
|
||||
|
||||
Reference in New Issue
Block a user