Files
sgw-owner-app/components/diary/TripDetailSections/BasicInfoSection.tsx

222 lines
5.4 KiB
TypeScript

import React, { useEffect, useMemo } 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";
import { useShip } from "@/state/use-ship";
import { usePort } from "@/state/use-ports";
import { useGroup } from "@/state/use-group";
import { filterPortsByProvinceCode } from "@/utils/tripDataConverters";
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();
// Get data from zustand stores
const { ships, getShip } = useShip();
const { ports, getPorts } = usePort();
const { groups, getUserGroups } = useGroup();
// Fetch data if not available
useEffect(() => {
if (!ships) {
getShip();
}
}, [ships, getShip]);
useEffect(() => {
if (!ports) {
getPorts();
}
}, [ports, getPorts]);
useEffect(() => {
if (!groups) {
getUserGroups();
}
}, [groups, getUserGroups]);
// Filter ports by province codes from groups
const filteredPorts = useMemo(() => {
return filterPortsByProvinceCode(ports, groups);
}, [ports, groups]);
// Get ship name by ship_id
const shipName = useMemo(() => {
if (!trip?.ship_id || !ships) return "--";
const ship = ships.find((s) => s.id === trip.ship_id);
return ship?.name || "--";
}, [trip?.ship_id, ships]);
// Get ship code (reg_number) by ship_id
const shipCode = useMemo(() => {
if (!trip?.ship_id || !ships) return "--";
const ship = ships.find((s) => s.id === trip.ship_id);
return ship?.reg_number || "--";
}, [trip?.ship_id, ships]);
// Get port name by ID
const getPortName = (portId: number): string => {
const port = filteredPorts.find((p) => p.id === portId);
return port?.name || "--";
};
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.shipName"),
value: shipName,
},
{
icon: "barcode" as const,
label: t("diary.tripDetail.shipCode"),
value: shipCode,
},
{
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: getPortName(trip.departure_port_id),
},
{
icon: "flag" as const,
label: t("diary.tripDetail.arrivalPort"),
value: getPortName(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",
}),
},
});