fix: SlideToConfirm gesture blocked by modal backdrop - restructure all payment modals

This commit is contained in:
Nemo
2026-03-24 13:09:53 +08:00
parent 065844b579
commit 024bb06205
4 changed files with 21 additions and 14 deletions

View File

@@ -68,9 +68,10 @@ function PayInvoiceModal({ invoice, onClose, onSuccess }: { invoice: any; onClos
return ( return (
<Modal visible animationType="slide" transparent onRequestClose={onClose}> <Modal visible animationType="slide" transparent onRequestClose={onClose}>
<KeyboardAvoidingView style={{ flex: 1 }} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}> <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end' }}>
<TouchableOpacity style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end' }} activeOpacity={1} onPress={onClose}> <TouchableOpacity style={{ flex: 1 }} activeOpacity={1} onPress={onClose} />
<TouchableOpacity activeOpacity={1} style={{ backgroundColor: '#FFF', borderTopLeftRadius: 28, borderTopRightRadius: 28, padding: 24 }}> <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<View style={{ backgroundColor: '#FFF', borderTopLeftRadius: 28, borderTopRightRadius: 28, padding: 24 }}>
<Text style={{ fontSize: 20, fontWeight: '800', color: '#0F172A', marginBottom: 4 }}>Record Payment</Text> <Text style={{ fontSize: 20, fontWeight: '800', color: '#0F172A', marginBottom: 4 }}>Record Payment</Text>
<Text style={{ fontSize: 15, color: '#64748B', marginBottom: 20 }}> <Text style={{ fontSize: 15, color: '#64748B', marginBottom: 20 }}>
{invoice.invoiceNumber} · Balance: <Text style={{ fontWeight: '700', color: '#991B1B' }}>{Number(invoice.balance).toLocaleString()}</Text> {invoice.invoiceNumber} · Balance: <Text style={{ fontWeight: '700', color: '#991B1B' }}>{Number(invoice.balance).toLocaleString()}</Text>
@@ -113,9 +114,9 @@ function PayInvoiceModal({ invoice, onClose, onSuccess }: { invoice: any; onClos
onConfirm={submit} onConfirm={submit}
disabled={loading || !amount || Number(amount) <= 0} disabled={loading || !amount || Number(amount) <= 0}
/> />
</TouchableOpacity> </View>
</TouchableOpacity>
</KeyboardAvoidingView> </KeyboardAvoidingView>
</View>
</Modal> </Modal>
); );
} }

View File

@@ -289,7 +289,9 @@ export default function DashboardScreen() {
{/* ── Payment Modal ──────────────────────────────────────────────────── */} {/* ── Payment Modal ──────────────────────────────────────────────────── */}
<Modal visible={payModal} transparent animationType="slide" onRequestClose={closePay}> <Modal visible={payModal} transparent animationType="slide" onRequestClose={closePay}>
<TouchableOpacity style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.4)' }} activeOpacity={1} onPress={closePay} /> <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.4)', justifyContent: 'flex-end' }}>
{/* Tap outside to dismiss — only on the dark area above the sheet */}
<TouchableOpacity style={{ flex: 1 }} activeOpacity={1} onPress={closePay} />
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined}> <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined}>
<View style={{ backgroundColor: '#fff', borderTopLeftRadius: 24, borderTopRightRadius: 24, padding: 24, paddingBottom: 40 }}> <View style={{ backgroundColor: '#fff', borderTopLeftRadius: 24, borderTopRightRadius: 24, padding: 24, paddingBottom: 40 }}>
{/* Handle */} {/* Handle */}
@@ -341,6 +343,7 @@ export default function DashboardScreen() {
/> />
</View> </View>
</KeyboardAvoidingView> </KeyboardAvoidingView>
</View>
</Modal> </Modal>
</SafeAreaView> </SafeAreaView>
); );

View File

@@ -41,9 +41,10 @@ function PayInvoiceModal({ invoice, onClose, onSuccess }: { invoice: any; onClos
return ( return (
<Modal visible animationType="slide" transparent onRequestClose={onClose}> <Modal visible animationType="slide" transparent onRequestClose={onClose}>
<KeyboardAvoidingView style={{ flex: 1 }} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}> <View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end' }}>
<TouchableOpacity style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end' }} activeOpacity={1} onPress={onClose}> <TouchableOpacity style={{ flex: 1 }} activeOpacity={1} onPress={onClose} />
<TouchableOpacity activeOpacity={1} style={{ backgroundColor: '#FFF', borderTopLeftRadius: 28, borderTopRightRadius: 28, padding: 24 }}> <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<View style={{ backgroundColor: '#FFF', borderTopLeftRadius: 28, borderTopRightRadius: 28, padding: 24 }}>
<Text style={{ fontSize: 20, fontWeight: '800', color: '#0F172A', marginBottom: 2 }}>Record Payment</Text> <Text style={{ fontSize: 20, fontWeight: '800', color: '#0F172A', marginBottom: 2 }}>Record Payment</Text>
<Text style={{ fontSize: 14, color: '#64748B', marginBottom: 4 }}>{invoice.client?.firstName} {invoice.client?.lastName} · {invoice.client?.accountNumber}</Text> <Text style={{ fontSize: 14, color: '#64748B', marginBottom: 4 }}>{invoice.client?.firstName} {invoice.client?.lastName} · {invoice.client?.accountNumber}</Text>
<Text style={{ fontSize: 15, color: '#64748B', marginBottom: 20 }}> <Text style={{ fontSize: 15, color: '#64748B', marginBottom: 20 }}>
@@ -82,9 +83,9 @@ function PayInvoiceModal({ invoice, onClose, onSuccess }: { invoice: any; onClos
onConfirm={submit} onConfirm={submit}
disabled={loading || !amount || Number(amount) <= 0} disabled={loading || !amount || Number(amount) <= 0}
/> />
</TouchableOpacity> </View>
</TouchableOpacity>
</KeyboardAvoidingView> </KeyboardAvoidingView>
</View>
</Modal> </Modal>
); );
} }

View File

@@ -23,7 +23,9 @@ export function SlideToConfirm({ label = 'Slide to confirm', color = '#059669',
const panResponder = useRef( const panResponder = useRef(
PanResponder.create({ PanResponder.create({
onStartShouldSetPanResponder: () => !disabled && !done, onStartShouldSetPanResponder: () => !disabled && !done,
onStartShouldSetPanResponderCapture: () => !disabled && !done,
onMoveShouldSetPanResponder: () => !disabled && !done, onMoveShouldSetPanResponder: () => !disabled && !done,
onMoveShouldSetPanResponderCapture: () => !disabled && !done,
onPanResponderMove: (_, gs) => { onPanResponderMove: (_, gs) => {
const x = Math.max(0, Math.min(gs.dx, maxX)); const x = Math.max(0, Math.min(gs.dx, maxX));
pan.setValue(x); pan.setValue(x);