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

@@ -12,7 +12,7 @@ import { Ionicons } from "@expo/vector-icons";
import { useThemeContext } from "@/hooks/use-theme-context";
import { useI18n } from "@/hooks/use-i18n";
import dayjs from "dayjs";
import { queryCrewImage } from "@/controller/TripCrewController";
import { queryCrewImage } from "@/controller/CrewController";
import { Buffer } from "buffer";
interface CrewCardProps {
@@ -26,8 +26,12 @@ export default function CrewCard({ crew, onEdit, onDelete }: CrewCardProps) {
const { t } = useI18n();
const person = crew.Person;
const joinedDate = crew.joined_at ? dayjs(crew.joined_at).format("DD/MM/YYYY") : "-";
const leftDate = crew.left_at ? dayjs(crew.left_at).format("DD/MM/YYYY") : null;
const joinedDate = crew.joined_at
? dayjs(crew.joined_at).format("DD/MM/YYYY")
: "-";
const leftDate = crew.left_at
? dayjs(crew.left_at).format("DD/MM/YYYY")
: null;
// State for image
const [imageUri, setImageUri] = useState<string | null>(null);
@@ -47,7 +51,9 @@ export default function CrewCard({ crew, onEdit, onDelete }: CrewCardProps) {
const response = await queryCrewImage(person.personal_id);
if (response.data) {
// Convert arraybuffer to base64
const base64 = Buffer.from(response.data as ArrayBuffer).toString("base64");
const base64 = Buffer.from(response.data as ArrayBuffer).toString(
"base64"
);
setImageUri(`data:image/jpeg;base64,${base64}`);
} else {
setImageError(true);
@@ -112,7 +118,12 @@ export default function CrewCard({ crew, onEdit, onDelete }: CrewCardProps) {
<Text style={[styles.name, themedStyles.name]} numberOfLines={1}>
{person?.name || "-"}
</Text>
<View style={[styles.roleBadge, { backgroundColor: themedStyles.role.backgroundColor }]}>
<View
style={[
styles.roleBadge,
{ backgroundColor: themedStyles.role.backgroundColor },
]}
>
<Text style={[styles.roleText, { color: themedStyles.role.color }]}>
{crew.role || t("diary.crew.member")}
</Text>
@@ -123,7 +134,11 @@ export default function CrewCard({ crew, onEdit, onDelete }: CrewCardProps) {
<View style={styles.infoGrid}>
{/* Phone */}
<View style={styles.infoRow}>
<Ionicons name="call-outline" size={14} color={themedStyles.iconColor} />
<Ionicons
name="call-outline"
size={14}
color={themedStyles.iconColor}
/>
<Text style={[styles.value, themedStyles.value]} numberOfLines={1}>
{person?.phone || "-"}
</Text>
@@ -131,7 +146,11 @@ export default function CrewCard({ crew, onEdit, onDelete }: CrewCardProps) {
{/* Personal ID */}
<View style={styles.infoRow}>
<Ionicons name="card-outline" size={14} color={themedStyles.iconColor} />
<Ionicons
name="card-outline"
size={14}
color={themedStyles.iconColor}
/>
<Text style={[styles.value, themedStyles.value]} numberOfLines={1}>
{person?.personal_id || "-"}
</Text>
@@ -139,14 +158,22 @@ export default function CrewCard({ crew, onEdit, onDelete }: CrewCardProps) {
{/* Joined Date */}
<View style={styles.infoRow}>
<Ionicons name="calendar-outline" size={14} color={themedStyles.iconColor} />
<Ionicons
name="calendar-outline"
size={14}
color={themedStyles.iconColor}
/>
<Text style={[styles.value, themedStyles.value]}>{joinedDate}</Text>
</View>
{/* Left Date (only show if exists) */}
{leftDate && (
<View style={styles.infoRow}>
<Ionicons name="exit-outline" size={14} color={themedStyles.iconColor} />
<Ionicons
name="exit-outline"
size={14}
color={themedStyles.iconColor}
/>
<Text style={[styles.value, themedStyles.value]}>{leftDate}</Text>
</View>
)}
@@ -157,10 +184,17 @@ export default function CrewCard({ crew, onEdit, onDelete }: CrewCardProps) {
<View style={styles.actionRow}>
{onEdit && (
<TouchableOpacity
style={[styles.actionButton, { backgroundColor: colors.primary + "15" }]}
style={[
styles.actionButton,
{ backgroundColor: colors.primary + "15" },
]}
onPress={() => onEdit(crew)}
>
<Ionicons name="pencil-outline" size={14} color={colors.primary} />
<Ionicons
name="pencil-outline"
size={14}
color={colors.primary}
/>
<Text style={[styles.actionText, { color: colors.primary }]}>
{t("common.edit")}
</Text>
@@ -168,11 +202,23 @@ export default function CrewCard({ crew, onEdit, onDelete }: CrewCardProps) {
)}
{onDelete && (
<TouchableOpacity
style={[styles.actionButton, { backgroundColor: (colors.error || "#FF3B30") + "15" }]}
style={[
styles.actionButton,
{ backgroundColor: (colors.error || "#FF3B30") + "15" },
]}
onPress={() => onDelete(crew)}
>
<Ionicons name="trash-outline" size={14} color={colors.error || "#FF3B30"} />
<Text style={[styles.actionText, { color: colors.error || "#FF3B30" }]}>
<Ionicons
name="trash-outline"
size={14}
color={colors.error || "#FF3B30"}
/>
<Text
style={[
styles.actionText,
{ color: colors.error || "#FF3B30" },
]}
>
{t("common.delete")}
</Text>
</TouchableOpacity>
@@ -191,7 +237,7 @@ const styles = StyleSheet.create({
borderWidth: 1,
marginBottom: 12,
overflow: "hidden",
maxHeight: 150,
maxHeight: 160,
},
imageSection: {
width: 130,