import React, { useEffect, useRef, useState } from "react"; import { View, Text, Modal, TouchableOpacity, StyleSheet, Platform, 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"; import { queryTripCrew } from "@/controller/TripCrewController"; import CrewList from "./CrewList"; import AddEditCrewModal from "./AddEditCrewModal"; interface TripCrewModalProps { visible: boolean; onClose: () => void; tripId: string | null; tripName?: string; } export default function TripCrewModal({ visible, onClose, tripId, tripName, }: TripCrewModalProps) { const { t } = useI18n(); const { colors } = useThemeContext(); // Animation values const fadeAnim = useRef(new Animated.Value(0)).current; const slideAnim = useRef(new Animated.Value(Dimensions.get("window").height)).current; // State const [loading, setLoading] = useState(false); const [crews, setCrews] = useState([]); const [error, setError] = useState(null); // Add/Edit modal state const [showAddEditModal, setShowAddEditModal] = useState(false); const [editingCrew, setEditingCrew] = useState(null); // Fetch crew data when modal opens useEffect(() => { if (visible && tripId) { fetchCrewData(); } }, [visible, tripId]); // Handle animation when modal visibility changes useEffect(() => { if (visible) { setError(null); 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 fetchCrewData = async () => { if (!tripId) return; setLoading(true); setError(null); try { const response = await queryTripCrew(tripId); const data = response.data as any; if (data?.trip_crews && Array.isArray(data.trip_crews)) { setCrews(data.trip_crews); } else if (Array.isArray(data)) { setCrews(data); } else { setCrews([]); } } catch (err) { console.error("Error fetching crew:", err); setError(t("diary.crew.fetchError")); setCrews([]); } finally { setLoading(false); } }; 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(); setTimeout(() => { setCrews([]); setError(null); }, 100); }); }; // Add crew handler const handleAddCrew = () => { setEditingCrew(null); setShowAddEditModal(true); }; // Edit crew handler const handleEditCrew = (crew: Model.TripCrews) => { setEditingCrew(crew); setShowAddEditModal(true); }; // Delete crew handler const handleDeleteCrew = (crew: Model.TripCrews) => { Alert.alert( t("diary.crew.deleteConfirmTitle"), t("diary.crew.deleteConfirmMessage", { name: crew.Person?.name || "" }), [ { text: t("common.cancel"), style: "cancel" }, { text: t("common.delete"), style: "destructive", onPress: async () => { // TODO: Call delete API when available // For now, just remove from local state setCrews((prev) => prev.filter((c) => c.PersonalID !== crew.PersonalID)); Alert.alert(t("common.success"), t("diary.crew.deleteSuccess")); }, }, ] ); }; // Save crew handler (add or edit) const handleSaveCrew = async (formData: any) => { // TODO: Call API to add/edit crew when available // For now, refresh the list await fetchCrewData(); }; const themedStyles = { modalContainer: { backgroundColor: colors.card }, header: { borderBottomColor: colors.separator }, title: { color: colors.text }, subtitle: { color: colors.textSecondary }, content: { backgroundColor: colors.background }, }; return ( <> {/* Header */} {t("diary.crew.title")} {tripName && ( {tripName} )} {/* Add Button */} {/* Content */} {loading ? ( {t("diary.crew.loading")} ) : error ? ( {error} {t("common.retry")} ) : ( )} {/* Footer - Crew count */} {t("diary.crew.totalMembers", { count: crews.length })} {/* Add/Edit Crew Modal */} { setShowAddEditModal(false); setEditingCrew(null); }} onSave={handleSaveCrew} mode={editingCrew ? "edit" : "add"} initialData={ editingCrew ? { personalId: editingCrew.PersonalID, name: editingCrew.Person?.name || "", phone: editingCrew.Person?.phone || "", email: editingCrew.Person?.email || "", address: editingCrew.Person?.address || "", role: editingCrew.role || "crew", note: editingCrew.note || "", } : undefined } /> ); } const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: "rgba(0, 0, 0, 0.5)", justifyContent: "flex-end", }, modalContainer: { borderTopLeftRadius: 24, borderTopRightRadius: 24, maxHeight: "92%", minHeight: "80%", shadowColor: "#000", shadowOffset: { width: 0, height: -4 }, shadowOpacity: 0.1, shadowRadius: 12, elevation: 8, }, header: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingHorizontal: 20, paddingVertical: 16, borderBottomWidth: 1, }, closeButton: { padding: 4, }, addButton: { padding: 4, }, headerTitles: { flex: 1, alignItems: "center", }, title: { fontSize: 18, fontWeight: "700", fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, subtitle: { fontSize: 13, marginTop: 2, fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, content: { flex: 1, padding: 16, }, loadingContainer: { flex: 1, justifyContent: "center", alignItems: "center", gap: 12, }, loadingText: { fontSize: 14, fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, errorContainer: { flex: 1, justifyContent: "center", alignItems: "center", gap: 12, paddingHorizontal: 20, }, errorText: { fontSize: 14, textAlign: "center", fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, retryButton: { marginTop: 8, paddingHorizontal: 24, paddingVertical: 10, borderRadius: 8, }, retryButtonText: { color: "#FFFFFF", fontSize: 14, fontWeight: "600", fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, footer: { borderTopWidth: 1, paddingHorizontal: 20, paddingVertical: 16, }, countContainer: { flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 8, }, countText: { fontSize: 14, fontWeight: "600", fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }), }, });