import React, { useState, useEffect } from "react"; import { View, Text, Modal, TouchableOpacity, StyleSheet, Platform, TextInput, ScrollView, ActivityIndicator, Animated, Dimensions, Alert, } from "react-native"; import { Ionicons } from "@expo/vector-icons"; import { useI18n } from "@/hooks/use-i18n"; import { useThemeContext } from "@/hooks/use-theme-context"; interface CrewFormData { personalId: string; name: string; phone: string; email: string; address: string; role: string; note: string; } interface AddEditCrewModalProps { visible: boolean; onClose: () => void; onSave: (data: CrewFormData) => Promise; mode: "add" | "edit"; initialData?: Partial; } const ROLES = ["captain", "crew", "engineer", "cook"]; export default function AddEditCrewModal({ visible, onClose, onSave, mode, initialData, }: AddEditCrewModalProps) { const { t } = useI18n(); const { colors } = useThemeContext(); // Animation values const fadeAnim = useState(new Animated.Value(0))[0]; const slideAnim = useState(new Animated.Value(Dimensions.get("window").height))[0]; // Form state const [formData, setFormData] = useState({ personalId: "", name: "", phone: "", email: "", address: "", role: "crew", note: "", }); const [isSubmitting, setIsSubmitting] = useState(false); // Pre-fill form when editing useEffect(() => { if (visible && initialData) { setFormData({ personalId: initialData.personalId || "", name: initialData.name || "", phone: initialData.phone || "", email: initialData.email || "", address: initialData.address || "", role: initialData.role || "crew", note: initialData.note || "", }); } else if (visible && mode === "add") { // Reset form for add mode setFormData({ personalId: "", name: "", phone: "", email: "", address: "", role: "crew", note: "", }); } }, [visible, initialData, mode]); // Handle animation useEffect(() => { if (visible) { Animated.parallel([ Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true, }), Animated.timing(slideAnim, { toValue: 0, duration: 300, useNativeDriver: true, }), ]).start(); } }, [visible, fadeAnim, slideAnim]); const handleClose = () => { Animated.parallel([ Animated.timing(fadeAnim, { toValue: 0, duration: 250, useNativeDriver: true, }), Animated.timing(slideAnim, { toValue: Dimensions.get("window").height, duration: 250, useNativeDriver: true, }), ]).start(() => { onClose(); }); }; const handleSave = async () => { // Validate required fields if (!formData.personalId.trim()) { Alert.alert(t("common.error"), t("diary.crew.form.personalIdRequired")); return; } if (!formData.name.trim()) { Alert.alert(t("common.error"), t("diary.crew.form.nameRequired")); return; } setIsSubmitting(true); try { await onSave(formData); handleClose(); } catch (error) { Alert.alert(t("common.error"), t("diary.crew.form.saveError")); } finally { setIsSubmitting(false); } }; const updateField = (field: keyof CrewFormData, value: string) => { setFormData((prev) => ({ ...prev, [field]: value })); }; const themedStyles = { modalContainer: { backgroundColor: colors.card }, header: { borderBottomColor: colors.separator }, title: { color: colors.text }, label: { color: colors.text }, input: { backgroundColor: colors.backgroundSecondary, color: colors.text, borderColor: colors.separator, }, placeholder: { color: colors.textSecondary }, roleButton: { backgroundColor: colors.backgroundSecondary, borderColor: colors.separator, }, roleButtonActive: { backgroundColor: colors.primary + "20", borderColor: colors.primary, }, roleText: { color: colors.textSecondary }, roleTextActive: { color: colors.primary }, }; return ( {/* Header */} {mode === "add" ? t("diary.crew.form.addTitle") : t("diary.crew.form.editTitle")} {/* Content */} {/* Personal ID */} {t("diary.crew.personalId")} * updateField("personalId", v)} placeholder={t("diary.crew.form.personalIdPlaceholder")} placeholderTextColor={themedStyles.placeholder.color} editable={mode === "add"} /> {/* Name */} {t("diary.crew.form.name")} * updateField("name", v)} placeholder={t("diary.crew.form.namePlaceholder")} placeholderTextColor={themedStyles.placeholder.color} /> {/* Phone */} {t("diary.crew.phone")} updateField("phone", v)} placeholder={t("diary.crew.form.phonePlaceholder")} placeholderTextColor={themedStyles.placeholder.color} keyboardType="phone-pad" /> {/* Role */} {t("diary.crew.form.role")} {ROLES.map((role) => ( updateField("role", role)} > {t(`diary.crew.roles.${role}`)} ))} {/* Address */} {t("diary.crew.form.address")} updateField("address", v)} placeholder={t("diary.crew.form.addressPlaceholder")} placeholderTextColor={themedStyles.placeholder.color} /> {/* Note */} {t("diary.crew.note")} updateField("note", v)} placeholder={t("diary.crew.form.notePlaceholder")} placeholderTextColor={themedStyles.placeholder.color} multiline numberOfLines={3} /> {/* Footer */} {t("common.cancel")} {isSubmitting ? ( ) : ( {t("common.save")} )} ); } const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: "rgba(0, 0, 0, 0.5)", justifyContent: "flex-end", }, modalContainer: { borderTopLeftRadius: 24, borderTopRightRadius: 24, maxHeight: "90%", }, header: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingHorizontal: 20, paddingVertical: 16, borderBottomWidth: 1, }, closeButton: { padding: 4, }, title: { fontSize: 18, fontWeight: "700", fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, headerPlaceholder: { width: 32, }, content: { padding: 20, }, formGroup: { marginBottom: 16, }, label: { fontSize: 14, fontWeight: "600", marginBottom: 8, fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, input: { height: 44, borderRadius: 10, borderWidth: 1, paddingHorizontal: 14, fontSize: 15, fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, textArea: { height: 80, paddingTop: 12, textAlignVertical: "top", }, roleContainer: { flexDirection: "row", flexWrap: "wrap", gap: 8, }, roleButton: { paddingHorizontal: 14, paddingVertical: 8, borderRadius: 20, borderWidth: 1, }, roleButtonText: { fontSize: 13, fontWeight: "500", fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, footer: { flexDirection: "row", gap: 12, padding: 20, borderTopWidth: 1, }, cancelButton: { flex: 1, paddingVertical: 14, borderRadius: 12, alignItems: "center", }, cancelButtonText: { fontSize: 16, fontWeight: "600", fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, saveButton: { flex: 1, paddingVertical: 14, borderRadius: 12, alignItems: "center", }, saveButtonText: { fontSize: 16, fontWeight: "600", color: "#FFFFFF", fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, buttonDisabled: { opacity: 0.7, }, });