181 lines
5.7 KiB
TypeScript
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); |