import { strings } from '@/common/strings'; import { createContext, ReactNode, useCallback, useContext, useState } from 'react'; import { Modal, Platform, Pressable, Alert as RNAlert, StyleSheet, View } from 'react-native'; import { font, radius, useColors } from './styles'; import { Text } from './Text'; type AlertButton = { text: string; onPress?: () => void; style?: 'default' | 'cancel' | 'destructive'; }; type AlertConfig = { title: string; message?: string; buttons?: AlertButton[]; }; type AlertContextType = { alert: (title: string, message?: string, buttons?: AlertButton[]) => void; showAlert: (title: string, message?: string) => void; showConfirm: (title: string, message: string, onConfirm: () => void) => void; }; const AlertContext = createContext(null); export function useAlert() { const ctx = useContext(AlertContext); if (!ctx) throw new Error('useAlert must be used within AlertProvider'); return ctx; } export function AlertProvider({ children }: { children: ReactNode }) { const [config, setConfig] = useState(null); const c = useColors(); const alert = useCallback((title: string, message?: string, buttons?: AlertButton[]) => { if (Platform.OS === 'ios') { RNAlert.alert(title, message, buttons); return; } setConfig({ title, message, buttons: buttons || [{ text: strings.common.ok }] }); }, []); const showAlert = useCallback( (title: string, message?: string) => { alert(title, message, [{ text: strings.common.ok }]); }, [alert] ); const showConfirm = useCallback( (title: string, message: string, onConfirm: () => void) => { alert(title, message, [ { text: strings.common.cancel, style: 'cancel' }, { text: strings.common.confirm, style: 'destructive', onPress: onConfirm }, ]); }, [alert] ); const close = useCallback(() => setConfig(null), []); const handlePress = (button: AlertButton) => { close(); button.onPress?.(); }; const buttons = config?.buttons || [{ text: strings.common.ok }]; const isHorizontal = buttons.length === 2; return ( {children} {Platform.OS === 'android' && config && ( {config.title} {config.message && ( {config.message} )} {buttons.map((btn, i) => { const isDestructive = btn.style === 'destructive'; const isCancel = btn.style === 'cancel'; const showSeparator = isHorizontal && i === 0; return ( {!isHorizontal && i > 0 && ( )} [styles.button, pressed && styles.pressed]} onPress={() => handlePress(btn)} > {btn.text} ); })} )} ); } const styles = StyleSheet.create({ backdrop: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.4)', justifyContent: 'center', alignItems: 'center', paddingHorizontal: 48, }, dialog: { width: '100%', maxWidth: 300, borderRadius: radius.lg, overflow: 'hidden', }, body: { paddingHorizontal: 20, paddingTop: 20, paddingBottom: 16, alignItems: 'center', }, title: { fontSize: font.lg, fontWeight: '600', textAlign: 'center', }, message: { fontSize: font.sm, textAlign: 'center', marginTop: 4, lineHeight: 18, }, separator: { height: StyleSheet.hairlineWidth, }, buttonsRow: { flexDirection: 'row', }, buttonsColumn: { flexDirection: 'column', }, buttonWrapperRow: { flex: 1, }, buttonWrapperColumn: {}, verticalSeparator: { borderRightWidth: StyleSheet.hairlineWidth, }, button: { paddingVertical: 12, alignItems: 'center', justifyContent: 'center', }, buttonText: { fontSize: font.lg, fontWeight: '400', }, cancelText: { fontWeight: '600', }, pressed: { backgroundColor: 'rgba(0, 0, 0, 0.05)', }, });