cập nhật modal CRUD thuyền viên trong trip

This commit is contained in:
2025-12-24 21:58:18 +07:00
parent 24847504b1
commit 190e44b09e
13 changed files with 822 additions and 68 deletions

View File

@@ -13,7 +13,7 @@ import { useLocalSearchParams, useRouter } from "expo-router";
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 { queryTripCrew, deleteTripCrew } from "@/controller/TripCrewController";
import CrewList from "@/components/diary/TripCrewModal/CrewList";
import AddEditCrewModal from "@/components/diary/TripCrewModal/AddEditCrewModal";
@@ -21,7 +21,10 @@ export default function TripCrewPage() {
const { t } = useI18n();
const { colors } = useThemeContext();
const router = useRouter();
const { tripId, tripName } = useLocalSearchParams<{ tripId: string; tripName?: string }>();
const { tripId, tripName } = useLocalSearchParams<{
tripId: string;
tripName?: string;
}>();
// State
const [loading, setLoading] = useState(false);
@@ -85,9 +88,16 @@ export default function TripCrewPage() {
text: t("common.delete"),
style: "destructive",
onPress: async () => {
// TODO: Call delete API when available
setCrews((prev) => prev.filter((c) => c.PersonalID !== crew.PersonalID));
Alert.alert(t("common.success"), t("diary.crew.deleteSuccess"));
try {
// Call delete API
await deleteTripCrew(tripId, crew.PersonalID || "");
// Reload list
await fetchCrewData();
Alert.alert(t("common.success"), t("diary.crew.deleteSuccess"));
} catch (error) {
console.error("Error deleting crew:", error);
Alert.alert(t("common.error"), t("diary.crew.form.saveError"));
}
},
},
]
@@ -102,16 +112,25 @@ export default function TripCrewPage() {
const themedStyles = {
container: { backgroundColor: colors.background },
header: { backgroundColor: colors.card, borderBottomColor: colors.separator },
header: {
backgroundColor: colors.card,
borderBottomColor: colors.separator,
},
title: { color: colors.text },
subtitle: { color: colors.textSecondary },
};
return (
<SafeAreaView style={[styles.container, themedStyles.container]} edges={["top"]}>
<SafeAreaView
style={[styles.container, themedStyles.container]}
edges={["top"]}
>
{/* Header */}
<View style={[styles.header, themedStyles.header]}>
<TouchableOpacity onPress={() => router.back()} style={styles.backButton}>
<TouchableOpacity
onPress={() => router.back()}
style={styles.backButton}
>
<Ionicons name="arrow-back" size={24} color={colors.text} />
</TouchableOpacity>
<View style={styles.headerTitles}>
@@ -119,7 +138,10 @@ export default function TripCrewPage() {
{t("diary.crew.title")}
</Text>
{tripName && (
<Text style={[styles.subtitle, themedStyles.subtitle]} numberOfLines={1}>
<Text
style={[styles.subtitle, themedStyles.subtitle]}
numberOfLines={1}
>
{tripName}
</Text>
)}
@@ -140,8 +162,14 @@ export default function TripCrewPage() {
</View>
) : error ? (
<View style={styles.errorContainer}>
<Ionicons name="alert-circle-outline" size={48} color={colors.error || "#FF3B30"} />
<Text style={[styles.errorText, { color: colors.error || "#FF3B30" }]}>
<Ionicons
name="alert-circle-outline"
size={48}
color={colors.error || "#FF3B30"}
/>
<Text
style={[styles.errorText, { color: colors.error || "#FF3B30" }]}
>
{error}
</Text>
<TouchableOpacity
@@ -152,12 +180,21 @@ export default function TripCrewPage() {
</TouchableOpacity>
</View>
) : (
<CrewList crews={crews} onEdit={handleEditCrew} onDelete={handleDeleteCrew} />
<CrewList
crews={crews}
onEdit={handleEditCrew}
onDelete={handleDeleteCrew}
/>
)}
</View>
{/* Footer - Crew count */}
<View style={[styles.footer, { backgroundColor: colors.card, borderTopColor: colors.separator }]}>
<View
style={[
styles.footer,
{ backgroundColor: colors.card, borderTopColor: colors.separator },
]}
>
<View style={styles.countContainer}>
<Ionicons name="people-outline" size={20} color={colors.primary} />
<Text style={[styles.countText, { color: colors.text }]}>
@@ -175,6 +212,8 @@ export default function TripCrewPage() {
}}
onSave={handleSaveCrew}
mode={editingCrew ? "edit" : "add"}
tripId={tripId}
existingCrewIds={crews.map((c) => c.PersonalID || "")}
initialData={
editingCrew
? {
@@ -184,7 +223,8 @@ export default function TripCrewPage() {
email: editingCrew.Person?.email || "",
address: editingCrew.Person?.address || "",
role: editingCrew.role || "crew",
note: editingCrew.note || "",
// Note lấy từ trip (ghi chú chuyến đi), fallback về note từ Person
note: editingCrew.note || editingCrew.Person?.note || "",
}
: undefined
}
@@ -218,12 +258,20 @@ const styles = StyleSheet.create({
title: {
fontSize: 18,
fontWeight: "700",
fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }),
fontFamily: Platform.select({
ios: "System",
android: "Roboto",
default: "System",
}),
},
subtitle: {
fontSize: 13,
marginTop: 2,
fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }),
fontFamily: Platform.select({
ios: "System",
android: "Roboto",
default: "System",
}),
},
content: {
flex: 1,
@@ -237,7 +285,11 @@ const styles = StyleSheet.create({
},
loadingText: {
fontSize: 14,
fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }),
fontFamily: Platform.select({
ios: "System",
android: "Roboto",
default: "System",
}),
},
errorContainer: {
flex: 1,
@@ -249,7 +301,11 @@ const styles = StyleSheet.create({
errorText: {
fontSize: 14,
textAlign: "center",
fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }),
fontFamily: Platform.select({
ios: "System",
android: "Roboto",
default: "System",
}),
},
retryButton: {
marginTop: 8,
@@ -261,7 +317,11 @@ const styles = StyleSheet.create({
color: "#FFFFFF",
fontSize: 14,
fontWeight: "600",
fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }),
fontFamily: Platform.select({
ios: "System",
android: "Roboto",
default: "System",
}),
},
footer: {
borderTopWidth: 1,
@@ -278,6 +338,10 @@ const styles = StyleSheet.create({
countText: {
fontSize: 14,
fontWeight: "600",
fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }),
fontFamily: Platform.select({
ios: "System",
android: "Roboto",
default: "System",
}),
},
});