thêm tab "Xem chi tiết chuyến đi", "Xem chi tiết thành viên chuyến đi", tái sử dụng lại components modal tripForm

This commit is contained in:
2025-12-23 23:10:19 +07:00
parent afc6acbfe2
commit 000a4ed856
22 changed files with 3221 additions and 379 deletions

View File

@@ -0,0 +1,135 @@
import React from "react";
import { View, Text, StyleSheet, Platform } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useI18n } from "@/hooks/use-i18n";
import { useThemeContext } from "@/hooks/use-theme-context";
interface BasicInfoSectionProps {
trip: Model.Trip;
}
/**
* Displays basic trip information like ship, dates, ports
*/
export default function BasicInfoSection({ trip }: BasicInfoSectionProps) {
const { t } = useI18n();
const { colors } = useThemeContext();
const formatDateTime = (dateStr?: string) => {
if (!dateStr) return "--";
const date = new Date(dateStr);
return date.toLocaleString("vi-VN", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
});
};
const infoItems = [
{
icon: "boat" as const,
label: t("diary.tripDetail.shipId"),
value: trip.vms_id || "--",
},
{
icon: "play-circle" as const,
label: t("diary.tripDetail.departureTime"),
value: formatDateTime(trip.departure_time),
},
{
icon: "stop-circle" as const,
label: t("diary.tripDetail.arrivalTime"),
value: formatDateTime(trip.arrival_time),
},
{
icon: "location" as const,
label: t("diary.tripDetail.departurePort"),
value: trip.departure_port_id ? `Cảng #${trip.departure_port_id}` : "--",
},
{
icon: "flag" as const,
label: t("diary.tripDetail.arrivalPort"),
value: trip.arrival_port_id ? `Cảng #${trip.arrival_port_id}` : "--",
},
{
icon: "map" as const,
label: t("diary.tripDetail.fishingGrounds"),
value: trip.fishing_ground_codes?.length > 0
? trip.fishing_ground_codes.join(", ")
: "--",
},
];
return (
<View style={[styles.container, { backgroundColor: colors.card, borderColor: colors.separator }]}>
<View style={styles.header}>
<Ionicons name="information-circle-outline" size={20} color={colors.primary} />
<Text style={[styles.title, { color: colors.text }]}>
{t("diary.tripDetail.basicInfo")}
</Text>
</View>
<View style={styles.content}>
{infoItems.map((item, index) => (
<View key={index} style={styles.infoItem}>
<View style={styles.infoLabel}>
<Ionicons name={item.icon} size={16} color={colors.textSecondary} />
<Text style={[styles.infoLabelText, { color: colors.textSecondary }]}>
{item.label}
</Text>
</View>
<Text style={[styles.infoValue, { color: colors.text }]}>
{item.value}
</Text>
</View>
))}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
borderRadius: 12,
borderWidth: 1,
marginBottom: 16,
overflow: "hidden",
},
header: {
flexDirection: "row",
alignItems: "center",
gap: 10,
paddingHorizontal: 16,
paddingVertical: 14,
},
title: {
fontSize: 16,
fontWeight: "600",
fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }),
},
content: {
paddingHorizontal: 16,
paddingBottom: 16,
gap: 12,
},
infoItem: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
infoLabel: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
infoLabelText: {
fontSize: 13,
fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }),
},
infoValue: {
fontSize: 13,
fontWeight: "500",
fontFamily: Platform.select({ ios: "System", android: "Roboto", default: "System" }),
},
});