Files
territory-log/components/ui/ConfirmDialog.tsx

167 lines
3.7 KiB
TypeScript

import { Modal, View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { AlertTriangle } from 'lucide-react-native';
interface Props {
visible: boolean;
title: string;
message: string;
confirmText?: string;
confirmStyle?: 'danger' | 'default';
onConfirm: () => void;
onCancel: () => void;
impactCount?: number;
}
export function ConfirmDialog({
visible,
title,
message,
confirmText = 'Confirm',
confirmStyle = 'default',
onConfirm,
onCancel,
impactCount,
}: Props) {
const isDanger = confirmStyle === 'danger';
return (
<Modal
visible={visible}
transparent
animationType="fade"
onRequestClose={onCancel}
accessibilityViewIsModal
>
<View style={styles.overlay}>
<View
style={styles.dialog}
accessibilityRole="alert"
accessibilityLabel={title}
>
{isDanger && (
<View style={styles.iconWrap}>
<AlertTriangle size={28} color="#C0392B" />
</View>
)}
<Text style={styles.title}>{title}</Text>
<Text style={styles.message}>{message}</Text>
{impactCount !== undefined && impactCount > 0 && (
<View style={styles.impactBadge}>
<Text style={styles.impactText}>
This will affect {impactCount} record{impactCount !== 1 ? 's' : ''}
</Text>
</View>
)}
<View style={styles.buttons}>
<TouchableOpacity
style={[styles.btn, styles.cancelBtn]}
onPress={onCancel}
accessibilityRole="button"
accessibilityLabel="Cancel"
>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.btn, isDanger ? styles.dangerBtn : styles.confirmBtn]}
onPress={onConfirm}
accessibilityRole="button"
accessibilityLabel={confirmText}
>
<Text style={styles.confirmText}>{confirmText}</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
);
}
const styles = StyleSheet.create({
overlay: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.5)',
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 24,
},
dialog: {
backgroundColor: 'white',
borderRadius: 20,
padding: 24,
width: '100%',
maxWidth: 400,
shadowColor: '#000',
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.2,
shadowRadius: 16,
elevation: 10,
},
iconWrap: {
alignItems: 'center',
marginBottom: 12,
},
title: {
fontSize: 18,
fontWeight: '700',
color: '#2C3E50',
textAlign: 'center',
marginBottom: 8,
},
message: {
fontSize: 14,
color: '#6B7280',
textAlign: 'center',
lineHeight: 20,
marginBottom: 12,
},
impactBadge: {
backgroundColor: '#FEF3C7',
borderRadius: 8,
paddingVertical: 8,
paddingHorizontal: 12,
marginBottom: 20,
alignItems: 'center',
},
impactText: {
fontSize: 12,
color: '#92400E',
fontWeight: '500',
},
buttons: {
flexDirection: 'row',
gap: 12,
marginTop: 4,
},
btn: {
flex: 1,
paddingVertical: 14,
borderRadius: 12,
alignItems: 'center',
minHeight: 48,
justifyContent: 'center',
},
cancelBtn: {
backgroundColor: '#F3F4F6',
},
confirmBtn: {
backgroundColor: '#1A6B72',
},
dangerBtn: {
backgroundColor: '#C0392B',
},
cancelText: {
fontSize: 15,
fontWeight: '600',
color: '#374151',
},
confirmText: {
fontSize: 15,
fontWeight: '600',
color: 'white',
},
});