update login, modal detail in tripInfo
This commit is contained in:
@@ -1,4 +1,12 @@
|
|||||||
import { Platform, ScrollView, StyleSheet, Text, View } from "react-native";
|
import { Link } from "expo-router";
|
||||||
|
import {
|
||||||
|
Platform,
|
||||||
|
ScrollView,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from "react-native";
|
||||||
import { SafeAreaView } from "react-native-safe-area-context";
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
|
|
||||||
export default function Warning() {
|
export default function Warning() {
|
||||||
@@ -7,6 +15,12 @@ export default function Warning() {
|
|||||||
<ScrollView contentContainerStyle={styles.scrollContent}>
|
<ScrollView contentContainerStyle={styles.scrollContent}>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Text style={styles.titleText}>Nhật Ký Chuyến Đi</Text>
|
<Text style={styles.titleText}>Nhật Ký Chuyến Đi</Text>
|
||||||
|
|
||||||
|
<Link href="/modal" asChild>
|
||||||
|
<TouchableOpacity style={styles.button}>
|
||||||
|
<Text style={styles.buttonText}>Mở Modal</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Link>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
@@ -32,4 +46,16 @@ const styles = StyleSheet.create({
|
|||||||
default: "System",
|
default: "System",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
button: {
|
||||||
|
backgroundColor: "#007AFF",
|
||||||
|
paddingVertical: 14,
|
||||||
|
paddingHorizontal: 24,
|
||||||
|
borderRadius: 8,
|
||||||
|
marginTop: 20,
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "600",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -108,14 +108,6 @@ export default function LoginScreen() {
|
|||||||
<ThemedText type="title" style={styles.title}>
|
<ThemedText type="title" style={styles.title}>
|
||||||
Hệ thống giám sát tàu cá
|
Hệ thống giám sát tàu cá
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
{/* Owner Logo */}
|
|
||||||
<View style={styles.ownerContainer}>
|
|
||||||
<Image
|
|
||||||
source={require("@/assets/images/owner.png")}
|
|
||||||
style={styles.ownerLogo}
|
|
||||||
resizeMode="contain"
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<ThemedText style={styles.subtitle}>
|
<ThemedText style={styles.subtitle}>
|
||||||
Đăng nhập để tiếp tục
|
Đăng nhập để tiếp tục
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
@@ -263,13 +255,6 @@ const styles = StyleSheet.create({
|
|||||||
color: "#007AFF",
|
color: "#007AFF",
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
},
|
},
|
||||||
ownerContainer: {
|
|
||||||
alignItems: "center",
|
|
||||||
},
|
|
||||||
ownerLogo: {
|
|
||||||
width: 150,
|
|
||||||
height: 50,
|
|
||||||
},
|
|
||||||
copyrightContainer: {
|
copyrightContainer: {
|
||||||
marginTop: 20,
|
marginTop: 20,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { IconSymbol } from "@/components/ui/icon-symbol";
|
import { IconSymbol } from "@/components/ui/icon-symbol";
|
||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { Animated, Text, TouchableOpacity, View } from "react-native";
|
import { Animated, Text, TouchableOpacity, View } from "react-native";
|
||||||
|
import CrewDetailModal from "./modal/CrewDetailModal";
|
||||||
import styles from "./style/CrewListTable.styles";
|
import styles from "./style/CrewListTable.styles";
|
||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
@@ -11,6 +12,14 @@ interface CrewMember {
|
|||||||
maDinhDanh: string;
|
maDinhDanh: string;
|
||||||
ten: string;
|
ten: string;
|
||||||
chucVu: string;
|
chucVu: string;
|
||||||
|
ngaySinh?: string;
|
||||||
|
cccd?: string;
|
||||||
|
soDienThoai?: string;
|
||||||
|
diaChi?: string;
|
||||||
|
ngayVaoLam?: string;
|
||||||
|
trinhDoChuyenMon?: string;
|
||||||
|
bangCap?: string;
|
||||||
|
tinhTrang?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
@@ -22,21 +31,65 @@ const data: CrewMember[] = [
|
|||||||
maDinhDanh: "ChuTau",
|
maDinhDanh: "ChuTau",
|
||||||
ten: "Nguyễn Nhật Minh",
|
ten: "Nguyễn Nhật Minh",
|
||||||
chucVu: "Chủ tàu",
|
chucVu: "Chủ tàu",
|
||||||
|
ngaySinh: "08/06/2006",
|
||||||
|
cccd: "079085012345",
|
||||||
|
soDienThoai: "0912345678",
|
||||||
|
diaChi: "Hà Nội",
|
||||||
|
ngayVaoLam: "",
|
||||||
|
trinhDoChuyenMon: "Thuyền trưởng hạng I",
|
||||||
|
bangCap: "Bằng thuyền trưởng xa bờ",
|
||||||
|
tinhTrang: "Đang làm việc",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "1",
|
id: "1",
|
||||||
maDinhDanh: "TV001",
|
maDinhDanh: "TV001",
|
||||||
ten: "Nguyễn Văn A",
|
ten: "Nguyễn Văn A",
|
||||||
chucVu: "Thuyền trưởng",
|
chucVu: "Thuyền trưởng",
|
||||||
|
ngaySinh: "20/05/1988",
|
||||||
|
cccd: "079088011111",
|
||||||
|
soDienThoai: "0901234567",
|
||||||
|
diaChi: "456 Đường Cảng, Phường Thanh Khê, Đà Nẵng",
|
||||||
|
ngayVaoLam: "15/06/2015",
|
||||||
|
trinhDoChuyenMon: "Thuyền trưởng hạng II",
|
||||||
|
bangCap: "Bằng thuyền trưởng ven bờ",
|
||||||
|
tinhTrang: "Đang làm việc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
maDinhDanh: "TV002",
|
||||||
|
ten: "Trần Văn B",
|
||||||
|
chucVu: "Máy trưởng",
|
||||||
|
ngaySinh: "10/08/1990",
|
||||||
|
cccd: "079090022222",
|
||||||
|
soDienThoai: "0987654321",
|
||||||
|
diaChi: "789 Đường Nguyễn Văn Linh, Quận Sơn Trà, Đà Nẵng",
|
||||||
|
ngayVaoLam: "20/03/2016",
|
||||||
|
trinhDoChuyenMon: "Máy trưởng hạng III",
|
||||||
|
bangCap: "Bằng máy trưởng ven bờ",
|
||||||
|
tinhTrang: "Đang làm việc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
maDinhDanh: "TV003",
|
||||||
|
ten: "Lê Văn C",
|
||||||
|
chucVu: "Thủy thủ",
|
||||||
|
ngaySinh: "25/12/1995",
|
||||||
|
cccd: "079095033333",
|
||||||
|
soDienThoai: "0976543210",
|
||||||
|
diaChi: "321 Đường Hoàng Sa, Quận Ngũ Hành Sơn, Đà Nẵng",
|
||||||
|
ngayVaoLam: "10/07/2018",
|
||||||
|
trinhDoChuyenMon: "Thủy thủ hạng I",
|
||||||
|
bangCap: "Chứng chỉ thủy thủ",
|
||||||
|
tinhTrang: "Đang làm việc",
|
||||||
},
|
},
|
||||||
{ id: "2", maDinhDanh: "TV002", ten: "Trần Văn B", chucVu: "Máy trưởng" },
|
|
||||||
{ id: "3", maDinhDanh: "TV003", ten: "Lê Văn C", chucVu: "Thủy thủ" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const CrewListTable: React.FC = () => {
|
const CrewListTable: React.FC = () => {
|
||||||
const [collapsed, setCollapsed] = useState(true);
|
const [collapsed, setCollapsed] = useState(true);
|
||||||
const [contentHeight, setContentHeight] = useState<number>(0);
|
const [contentHeight, setContentHeight] = useState<number>(0);
|
||||||
const animatedHeight = useRef(new Animated.Value(0)).current;
|
const animatedHeight = useRef(new Animated.Value(0)).current;
|
||||||
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
|
const [selectedCrew, setSelectedCrew] = useState<CrewMember | null>(null);
|
||||||
const tongThanhVien = data.length;
|
const tongThanhVien = data.length;
|
||||||
|
|
||||||
const handleToggle = () => {
|
const handleToggle = () => {
|
||||||
@@ -50,7 +103,16 @@ const CrewListTable: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCrewPress = (crewId: string) => {
|
const handleCrewPress = (crewId: string) => {
|
||||||
console.log("Crew ID:", crewId);
|
const crew = data.find((item) => item.id === crewId);
|
||||||
|
if (crew) {
|
||||||
|
setSelectedCrew(crew);
|
||||||
|
setModalVisible(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseModal = () => {
|
||||||
|
setModalVisible(false);
|
||||||
|
setSelectedCrew(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -157,6 +219,13 @@ const CrewListTable: React.FC = () => {
|
|||||||
<Text style={[styles.cell, styles.right]}></Text>
|
<Text style={[styles.cell, styles.right]}></Text>
|
||||||
</View>
|
</View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
||||||
|
{/* Modal chi tiết thuyền viên */}
|
||||||
|
<CrewDetailModal
|
||||||
|
visible={modalVisible}
|
||||||
|
onClose={handleCloseModal}
|
||||||
|
crewData={selectedCrew}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { IconSymbol } from "@/components/ui/icon-symbol";
|
import { IconSymbol } from "@/components/ui/icon-symbol";
|
||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { Animated, Text, TouchableOpacity, View } from "react-native";
|
import { Animated, Text, TouchableOpacity, View } from "react-native";
|
||||||
|
import TripCostDetailModal from "./modal/TripCostDetailModal";
|
||||||
import styles from "./style/TripCostTable.styles";
|
import styles from "./style/TripCostTable.styles";
|
||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
@@ -60,6 +61,7 @@ const data: CostItem[] = [
|
|||||||
const TripCostTable: React.FC = () => {
|
const TripCostTable: React.FC = () => {
|
||||||
const [collapsed, setCollapsed] = useState(true);
|
const [collapsed, setCollapsed] = useState(true);
|
||||||
const [contentHeight, setContentHeight] = useState<number>(0);
|
const [contentHeight, setContentHeight] = useState<number>(0);
|
||||||
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
const animatedHeight = useRef(new Animated.Value(0)).current;
|
const animatedHeight = useRef(new Animated.Value(0)).current;
|
||||||
const tongCong = data.reduce((sum, item) => sum + item.tongChiPhi, 0);
|
const tongCong = data.reduce((sum, item) => sum + item.tongChiPhi, 0);
|
||||||
|
|
||||||
@@ -74,7 +76,11 @@ const TripCostTable: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleViewDetail = () => {
|
const handleViewDetail = () => {
|
||||||
console.log("View trip cost details");
|
setModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseModal = () => {
|
||||||
|
setModalVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -191,6 +197,13 @@ const TripCostTable: React.FC = () => {
|
|||||||
<Text style={styles.viewDetailText}>Xem chi tiết</Text>
|
<Text style={styles.viewDetailText}>Xem chi tiết</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
||||||
|
{/* Modal */}
|
||||||
|
<TripCostDetailModal
|
||||||
|
visible={modalVisible}
|
||||||
|
onClose={handleCloseModal}
|
||||||
|
data={data}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
91
components/tripInfo/modal/CrewDetailModal.tsx
Normal file
91
components/tripInfo/modal/CrewDetailModal.tsx
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { IconSymbol } from "@/components/ui/icon-symbol";
|
||||||
|
import React from "react";
|
||||||
|
import { Modal, ScrollView, Text, TouchableOpacity, View } from "react-native";
|
||||||
|
import styles from "./style/CrewDetailModal.styles";
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// 🧩 Interface
|
||||||
|
// ---------------------------
|
||||||
|
interface CrewMember {
|
||||||
|
id: string;
|
||||||
|
maDinhDanh: string;
|
||||||
|
ten: string;
|
||||||
|
chucVu: string;
|
||||||
|
ngaySinh?: string;
|
||||||
|
cccd?: string;
|
||||||
|
soDienThoai?: string;
|
||||||
|
diaChi?: string;
|
||||||
|
ngayVaoLam?: string;
|
||||||
|
trinhDoChuyenMon?: string;
|
||||||
|
bangCap?: string;
|
||||||
|
tinhTrang?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CrewDetailModalProps {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
crewData: CrewMember | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// 👤 Component Modal
|
||||||
|
// ---------------------------
|
||||||
|
const CrewDetailModal: React.FC<CrewDetailModalProps> = ({
|
||||||
|
visible,
|
||||||
|
onClose,
|
||||||
|
crewData,
|
||||||
|
}) => {
|
||||||
|
if (!crewData) return null;
|
||||||
|
|
||||||
|
const infoItems = [
|
||||||
|
{ label: "Mã định danh", value: crewData.maDinhDanh },
|
||||||
|
{ label: "Họ và tên", value: crewData.ten },
|
||||||
|
{ label: "Chức vụ", value: crewData.chucVu },
|
||||||
|
{ label: "Ngày sinh", value: crewData.ngaySinh || "Chưa cập nhật" },
|
||||||
|
{ label: "CCCD/CMND", value: crewData.cccd || "Chưa cập nhật" },
|
||||||
|
{ label: "Số điện thoại", value: crewData.soDienThoai || "Chưa cập nhật" },
|
||||||
|
{ label: "Địa chỉ", value: crewData.diaChi || "Chưa cập nhật" },
|
||||||
|
{ label: "Ngày vào làm", value: crewData.ngayVaoLam || "Chưa cập nhật" },
|
||||||
|
{
|
||||||
|
label: "Trình độ chuyên môn",
|
||||||
|
value: crewData.trinhDoChuyenMon || "Chưa cập nhật",
|
||||||
|
},
|
||||||
|
{ label: "Bằng cấp", value: crewData.bangCap || "Chưa cập nhật" },
|
||||||
|
{ label: "Tình trạng", value: crewData.tinhTrang || "Đang làm việc" },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible={visible}
|
||||||
|
animationType="slide"
|
||||||
|
presentationStyle="pageSheet"
|
||||||
|
onRequestClose={onClose}
|
||||||
|
>
|
||||||
|
<View style={styles.container}>
|
||||||
|
{/* Header */}
|
||||||
|
<View style={styles.header}>
|
||||||
|
<Text style={styles.title}>Thông tin thuyền viên</Text>
|
||||||
|
<TouchableOpacity onPress={onClose} style={styles.closeButton}>
|
||||||
|
<View style={styles.closeIconButton}>
|
||||||
|
<IconSymbol name="xmark" size={28} color="#fff" />
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<ScrollView style={styles.content}>
|
||||||
|
<View style={styles.infoCard}>
|
||||||
|
{infoItems.map((item, index) => (
|
||||||
|
<View key={index} style={styles.infoRow}>
|
||||||
|
<Text style={styles.infoLabel}>{item.label}</Text>
|
||||||
|
<Text style={styles.infoValue}>{item.value}</Text>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CrewDetailModal;
|
||||||
222
components/tripInfo/modal/TripCostDetailModal.tsx
Normal file
222
components/tripInfo/modal/TripCostDetailModal.tsx
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
import { IconSymbol } from "@/components/ui/icon-symbol";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
KeyboardAvoidingView,
|
||||||
|
Modal,
|
||||||
|
Platform,
|
||||||
|
ScrollView,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from "react-native";
|
||||||
|
import styles from "./style/TripCostDetailModal.styles";
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// 🧩 Interface
|
||||||
|
// ---------------------------
|
||||||
|
interface CostItem {
|
||||||
|
id: string;
|
||||||
|
loai: string;
|
||||||
|
soLuong: number;
|
||||||
|
donVi: string;
|
||||||
|
chiPhi: number;
|
||||||
|
tongChiPhi: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TripCostDetailModalProps {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
data: CostItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// 💰 Component Modal
|
||||||
|
// ---------------------------
|
||||||
|
const TripCostDetailModal: React.FC<TripCostDetailModalProps> = ({
|
||||||
|
visible,
|
||||||
|
onClose,
|
||||||
|
data,
|
||||||
|
}) => {
|
||||||
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
const [editableData, setEditableData] = useState<CostItem[]>(data);
|
||||||
|
|
||||||
|
const tongCong = editableData.reduce((sum, item) => sum + item.tongChiPhi, 0);
|
||||||
|
|
||||||
|
const handleEdit = () => {
|
||||||
|
setIsEditing(!isEditing);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
setIsEditing(false);
|
||||||
|
// TODO: Save data to backend
|
||||||
|
console.log("Saved data:", editableData);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
setIsEditing(false);
|
||||||
|
setEditableData(data); // Reset to original data
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateItem = (id: string, field: keyof CostItem, value: string) => {
|
||||||
|
setEditableData((prev) =>
|
||||||
|
prev.map((item) => {
|
||||||
|
if (item.id === id) {
|
||||||
|
const numValue =
|
||||||
|
field === "loai" || field === "donVi" ? value : Number(value) || 0;
|
||||||
|
const updated = { ...item, [field]: numValue };
|
||||||
|
// Recalculate tongChiPhi
|
||||||
|
if (field === "soLuong" || field === "chiPhi") {
|
||||||
|
updated.tongChiPhi = updated.soLuong * updated.chiPhi;
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible={visible}
|
||||||
|
animationType="slide"
|
||||||
|
presentationStyle="pageSheet"
|
||||||
|
onRequestClose={onClose}
|
||||||
|
>
|
||||||
|
<KeyboardAvoidingView
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||||
|
keyboardVerticalOffset={60}
|
||||||
|
>
|
||||||
|
<View style={styles.container}>
|
||||||
|
{/* Header */}
|
||||||
|
<View style={styles.header}>
|
||||||
|
<Text style={styles.title}>Chi tiết chi phí chuyến đi</Text>
|
||||||
|
<View style={styles.headerButtons}>
|
||||||
|
{isEditing ? (
|
||||||
|
<>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={handleCancel}
|
||||||
|
style={styles.cancelButton}
|
||||||
|
>
|
||||||
|
<Text style={styles.cancelButtonText}>Hủy</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={handleSave}
|
||||||
|
style={styles.saveButton}
|
||||||
|
>
|
||||||
|
<Text style={styles.saveButtonText}>Lưu</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={handleEdit}
|
||||||
|
style={styles.editButton}
|
||||||
|
>
|
||||||
|
<View style={styles.editIconButton}>
|
||||||
|
<IconSymbol
|
||||||
|
name="pencil"
|
||||||
|
size={28}
|
||||||
|
color="#fff"
|
||||||
|
weight="heavy"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
<TouchableOpacity onPress={onClose} style={styles.closeButton}>
|
||||||
|
<View style={styles.closeIconButton}>
|
||||||
|
<IconSymbol name="xmark" size={28} color="#fff" />
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<ScrollView style={styles.content}>
|
||||||
|
{editableData.map((item) => (
|
||||||
|
<View key={item.id} style={styles.itemCard}>
|
||||||
|
{/* Loại */}
|
||||||
|
<View style={styles.fieldGroup}>
|
||||||
|
<Text style={styles.label}>Loại chi phí</Text>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.input, !isEditing && styles.inputDisabled]}
|
||||||
|
value={item.loai}
|
||||||
|
onChangeText={(value) => updateItem(item.id, "loai", value)}
|
||||||
|
editable={isEditing}
|
||||||
|
placeholder="Nhập loại chi phí"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Số lượng & Đơn vị */}
|
||||||
|
<View style={styles.rowGroup}>
|
||||||
|
<View
|
||||||
|
style={[styles.fieldGroup, { flex: 1, marginRight: 8 }]}
|
||||||
|
>
|
||||||
|
<Text style={styles.label}>Số lượng</Text>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.input, !isEditing && styles.inputDisabled]}
|
||||||
|
value={String(item.soLuong)}
|
||||||
|
onChangeText={(value) =>
|
||||||
|
updateItem(item.id, "soLuong", value)
|
||||||
|
}
|
||||||
|
editable={isEditing}
|
||||||
|
keyboardType="numeric"
|
||||||
|
placeholder="0"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={[styles.fieldGroup, { flex: 1, marginLeft: 8 }]}>
|
||||||
|
<Text style={styles.label}>Đơn vị</Text>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.input, !isEditing && styles.inputDisabled]}
|
||||||
|
value={item.donVi}
|
||||||
|
onChangeText={(value) =>
|
||||||
|
updateItem(item.id, "donVi", value)
|
||||||
|
}
|
||||||
|
editable={isEditing}
|
||||||
|
placeholder="kg, lít..."
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Chi phí/đơn vị */}
|
||||||
|
<View style={styles.fieldGroup}>
|
||||||
|
<Text style={styles.label}>Chi phí/đơn vị (VNĐ)</Text>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.input, !isEditing && styles.inputDisabled]}
|
||||||
|
value={String(item.chiPhi)}
|
||||||
|
onChangeText={(value) =>
|
||||||
|
updateItem(item.id, "chiPhi", value)
|
||||||
|
}
|
||||||
|
editable={isEditing}
|
||||||
|
keyboardType="numeric"
|
||||||
|
placeholder="0"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Tổng chi phí */}
|
||||||
|
<View style={styles.fieldGroup}>
|
||||||
|
<Text style={styles.label}>Tổng chi phí</Text>
|
||||||
|
<View style={styles.totalContainer}>
|
||||||
|
<Text style={styles.totalText}>
|
||||||
|
{item.tongChiPhi.toLocaleString()} VNĐ
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Footer Total */}
|
||||||
|
<View style={styles.footerTotal}>
|
||||||
|
<Text style={styles.footerLabel}>Tổng cộng</Text>
|
||||||
|
<Text style={styles.footerAmount}>
|
||||||
|
{tongCong.toLocaleString()} VNĐ
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
</KeyboardAvoidingView>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TripCostDetailModal;
|
||||||
69
components/tripInfo/modal/style/CrewDetailModal.styles.ts
Normal file
69
components/tripInfo/modal/style/CrewDetailModal.styles.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "#f5f5f5",
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
paddingTop: 30,
|
||||||
|
paddingBottom: 16,
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: "#eee",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: "700",
|
||||||
|
color: "#000",
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
closeButton: {
|
||||||
|
padding: 4,
|
||||||
|
},
|
||||||
|
closeIconButton: {
|
||||||
|
backgroundColor: "#FF3B30",
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: 10,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 16,
|
||||||
|
marginBottom: 15,
|
||||||
|
},
|
||||||
|
infoCard: {
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
borderRadius: 12,
|
||||||
|
padding: 16,
|
||||||
|
marginBottom: 20,
|
||||||
|
shadowColor: "#000",
|
||||||
|
shadowOpacity: 0.05,
|
||||||
|
shadowRadius: 4,
|
||||||
|
shadowOffset: { width: 0, height: 2 },
|
||||||
|
elevation: 2,
|
||||||
|
},
|
||||||
|
infoRow: {
|
||||||
|
paddingVertical: 12,
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: "#f0f0f0",
|
||||||
|
},
|
||||||
|
infoLabel: {
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: "600",
|
||||||
|
color: "#666",
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
infoValue: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: "#000",
|
||||||
|
fontWeight: "500",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default styles;
|
||||||
153
components/tripInfo/modal/style/TripCostDetailModal.styles.ts
Normal file
153
components/tripInfo/modal/style/TripCostDetailModal.styles.ts
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
closeIconButton: {
|
||||||
|
backgroundColor: "#FF3B30",
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: 10,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "#f5f5f5",
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
paddingTop: 30,
|
||||||
|
paddingBottom: 16,
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: "#eee",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: "700",
|
||||||
|
color: "#000",
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
headerButtons: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
editButton: {
|
||||||
|
padding: 4,
|
||||||
|
},
|
||||||
|
editIconButton: {
|
||||||
|
backgroundColor: "#007AFF",
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: 10,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
cancelButton: {
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 6,
|
||||||
|
},
|
||||||
|
cancelButtonText: {
|
||||||
|
color: "#007AFF",
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "600",
|
||||||
|
},
|
||||||
|
saveButton: {
|
||||||
|
backgroundColor: "#007AFF",
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 6,
|
||||||
|
borderRadius: 6,
|
||||||
|
},
|
||||||
|
saveButtonText: {
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "600",
|
||||||
|
},
|
||||||
|
closeButton: {
|
||||||
|
padding: 4,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
itemCard: {
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
borderRadius: 12,
|
||||||
|
padding: 16,
|
||||||
|
marginBottom: 12,
|
||||||
|
shadowColor: "#000",
|
||||||
|
shadowOpacity: 0.05,
|
||||||
|
shadowRadius: 4,
|
||||||
|
shadowOffset: { width: 0, height: 2 },
|
||||||
|
elevation: 2,
|
||||||
|
},
|
||||||
|
fieldGroup: {
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
rowGroup: {
|
||||||
|
flexDirection: "row",
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: "600",
|
||||||
|
color: "#666",
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "#007AFF",
|
||||||
|
borderRadius: 8,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 10,
|
||||||
|
fontSize: 15,
|
||||||
|
color: "#000",
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
},
|
||||||
|
inputDisabled: {
|
||||||
|
borderColor: "#ddd",
|
||||||
|
backgroundColor: "#f9f9f9",
|
||||||
|
color: "#666",
|
||||||
|
},
|
||||||
|
totalContainer: {
|
||||||
|
backgroundColor: "#fff5e6",
|
||||||
|
borderRadius: 8,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 10,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "#ffd699",
|
||||||
|
},
|
||||||
|
totalText: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "700",
|
||||||
|
color: "#ff6600",
|
||||||
|
},
|
||||||
|
footerTotal: {
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
borderRadius: 12,
|
||||||
|
padding: 20,
|
||||||
|
marginTop: 8,
|
||||||
|
marginBottom: 50,
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
shadowColor: "#000",
|
||||||
|
shadowOpacity: 0.1,
|
||||||
|
shadowRadius: 4,
|
||||||
|
shadowOffset: { width: 0, height: 2 },
|
||||||
|
elevation: 3,
|
||||||
|
},
|
||||||
|
footerLabel: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: "700",
|
||||||
|
color: "#007bff",
|
||||||
|
},
|
||||||
|
footerAmount: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: "700",
|
||||||
|
color: "#ff6600",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default styles;
|
||||||
@@ -28,6 +28,8 @@ const MAPPING = {
|
|||||||
"exclamationmark.triangle.fill": "warning",
|
"exclamationmark.triangle.fill": "warning",
|
||||||
"book.closed.fill": "book",
|
"book.closed.fill": "book",
|
||||||
"dot.radiowaves.left.and.right": "sensors",
|
"dot.radiowaves.left.and.right": "sensors",
|
||||||
|
xmark: "close",
|
||||||
|
pencil: "edit",
|
||||||
} as IconMapping;
|
} as IconMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
25
package-lock.json
generated
25
package-lock.json
generated
@@ -31,6 +31,7 @@
|
|||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-native": "0.81.5",
|
"react-native": "0.81.5",
|
||||||
"react-native-gesture-handler": "~2.28.0",
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
|
"react-native-keyboard-aware-scroll-view": "^0.9.5",
|
||||||
"react-native-maps": "^1.20.1",
|
"react-native-maps": "^1.20.1",
|
||||||
"react-native-reanimated": "~4.1.1",
|
"react-native-reanimated": "~4.1.1",
|
||||||
"react-native-safe-area-context": "5.4.0",
|
"react-native-safe-area-context": "5.4.0",
|
||||||
@@ -10817,7 +10818,6 @@
|
|||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
@@ -10829,7 +10829,6 @@
|
|||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/proxy-from-env": {
|
"node_modules/proxy-from-env": {
|
||||||
@@ -11345,6 +11344,15 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-iphone-x-helper": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": ">=0.42.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-is-edge-to-edge": {
|
"node_modules/react-native-is-edge-to-edge": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz",
|
||||||
@@ -11355,6 +11363,19 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-keyboard-aware-scroll-view": {
|
||||||
|
"version": "0.9.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-keyboard-aware-scroll-view/-/react-native-keyboard-aware-scroll-view-0.9.5.tgz",
|
||||||
|
"integrity": "sha512-XwfRn+T/qBH9WjTWIBiJD2hPWg0yJvtaEw6RtPCa5/PYHabzBaWxYBOl0usXN/368BL1XktnZPh8C2lmTpOREA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.6.2",
|
||||||
|
"react-native-iphone-x-helper": "^1.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": ">=0.48.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-maps": {
|
"node_modules/react-native-maps": {
|
||||||
"version": "1.20.1",
|
"version": "1.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-maps/-/react-native-maps-1.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-maps/-/react-native-maps-1.20.1.tgz",
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-native": "0.81.5",
|
"react-native": "0.81.5",
|
||||||
"react-native-gesture-handler": "~2.28.0",
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
|
"react-native-keyboard-aware-scroll-view": "^0.9.5",
|
||||||
"react-native-maps": "^1.20.1",
|
"react-native-maps": "^1.20.1",
|
||||||
"react-native-reanimated": "~4.1.1",
|
"react-native-reanimated": "~4.1.1",
|
||||||
"react-native-safe-area-context": "5.4.0",
|
"react-native-safe-area-context": "5.4.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user