Files
mariani_mobile/components/AlertComponent.tsx

181 lines
5.7 KiB
TypeScript

import React, { createContext, useContext, useState, ReactNode } from 'react';
import { Modal, View, Text, TouchableOpacity, TouchableWithoutFeedback } from 'react-native';
import { CheckCircle, XCircle, Info, AlertTriangle } from 'lucide-react-native';
type AlertType = 'success' | 'error' | 'info' | 'warning';
type ConfirmButtonStyle = 'default' | 'destructive' | 'cancel';
interface ConfirmButton {
text: string;
onPress: () => void;
style?: ConfirmButtonStyle;
}
interface AlertContextData {
showAlert: (type: AlertType, title: string, message: string) => void;
showConfirm: (
title: string,
message: string,
buttons: [ConfirmButton, ConfirmButton]
) => void;
hideAlert: () => void;
}
const AlertContext = createContext<AlertContextData>({} as AlertContextData);
// TODO: Move this config to a separate file
const ALERT_CONFIG = {
success: {
icon: CheckCircle,
color: 'text-green-600',
bgColor: 'bg-green-100',
btnColor: 'bg-green-600',
},
error: {
icon: XCircle,
color: 'text-red-600',
bgColor: 'bg-red-100',
btnColor: 'bg-red-600',
},
info: {
icon: Info,
color: 'text-sky-600',
bgColor: 'bg-sky-100',
btnColor: 'bg-sky-600',
},
warning: {
icon: AlertTriangle,
color: 'text-orange-600',
bgColor: 'bg-orange-100',
btnColor: 'bg-orange-600',
},
};
export const AlertProvider = ({ children }: { children: ReactNode }) => {
const [visible, setVisible] = useState(false);
const [title, setTitle] = useState('');
const [message, setMessage] = useState('');
const [type, setType] = useState<AlertType>('info');
const [isConfirmMode, setIsConfirmMode] = useState(false);
const [confirmButtons, setConfirmButtons] = useState<[ConfirmButton, ConfirmButton]>([
{ text: 'Annulla', onPress: () => {}, style: 'cancel' },
{ text: 'Conferma', onPress: () => {}, style: 'default' }
]);
const showAlert = (newType: AlertType, newTitle: string, newMessage: string) => {
setType(newType);
setTitle(newTitle);
setMessage(newMessage);
setIsConfirmMode(false);
setVisible(true);
};
const showConfirm = (
newTitle: string,
newMessage: string,
buttons: [ConfirmButton, ConfirmButton]
) => {
setTitle(newTitle);
setMessage(newMessage);
setConfirmButtons(buttons);
setIsConfirmMode(true);
setVisible(true);
};
const hideAlert = () => {
setVisible(false);
};
const { icon: Icon, color, bgColor, btnColor } = ALERT_CONFIG[type];
// TODO: Need to refactor component styles
return (
<AlertContext.Provider value={{ showAlert, showConfirm, hideAlert }}>
{children}
<Modal
transparent
visible={visible}
animationType="fade"
onRequestClose={hideAlert}
>
{/* Dark Backdrop */}
<TouchableOpacity
activeOpacity={1}
onPress={hideAlert} // Closes if you click outside (optional)
className="flex-1 bg-black/60 justify-center items-center px-6"
>
{/* Alert Container */}
<TouchableWithoutFeedback>
<View className="bg-white w-full max-w-sm rounded-3xl p-6 items-center shadow-2xl">
{/* Icon Circle - Solo per alert normali */}
{!isConfirmMode && (
<View className={`${bgColor} p-4 rounded-full mb-4`}>
<Icon size={32} className={color} strokeWidth={2.5} pointerEvents="none" />
</View>
)}
{/* Texts */}
<Text className="text-xl font-bold text-gray-900 text-center mb-2">
{title}
</Text>
<Text className="text-lg text-gray-500 text-center leading-relaxed mb-8">
{message}
</Text>
{/* Buttons - Condizionale */}
{isConfirmMode ? (
// Conferma: 2 bottoni orizzontali
<View className="flex-row gap-3 w-full">
{confirmButtons.map((button, index) => {
const isDestructive = button.style === 'destructive';
const isCancel = button.style === 'cancel';
return (
<TouchableOpacity
key={index}
onPress={() => {
hideAlert();
button.onPress();
}}
className={`flex-1 py-3.5 rounded-3xl ${
isDestructive
? 'bg-red-600'
: isCancel
? 'bg-gray-200'
: 'bg-[#099499]'
} active:opacity-90 shadow-sm`}
>
<Text className={`text-center font-bold text-lg ${
isCancel ? 'text-gray-700' : 'text-white'
}`}>
{button.text}
</Text>
</TouchableOpacity>
);
})}
</View>
) : (
// Alert normale: singolo bottone OK
<TouchableOpacity
onPress={hideAlert}
className={`w-full py-3.5 rounded-3xl ${btnColor} active:opacity-90 shadow-sm`}
>
<Text className="text-white text-center font-bold text-lg">
Ok, ho capito
</Text>
</TouchableOpacity>
)}
</View>
</TouchableWithoutFeedback>
</TouchableOpacity>
</Modal>
</AlertContext.Provider>
);
};
export const useAlert = () => useContext(AlertContext);