From f3b0e7b7eb9b588327fc63f139416473eaacc205 Mon Sep 17 00:00:00 2001 From: Tran Anh Tuan Date: Mon, 10 Nov 2025 10:45:31 +0700 Subject: [PATCH] =?UTF-8?q?c=E1=BA=ADp=20nh=E1=BA=ADt=20api=20th=C3=AAm/s?= =?UTF-8?q?=E1=BB=ADa=20m=E1=BA=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(tabs)/_layout.tsx | 4 +- app/(tabs)/index.tsx | 2 +- .../modal/CreateOrUpdateHaulModal.tsx | 106 ++++++++++++++---- controller/TripController.ts | 5 + controller/typings.d.ts | 4 +- 5 files changed, 97 insertions(+), 24 deletions(-) diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index bce1985..3fb295b 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -18,11 +18,11 @@ export default function TabLayout() { // TODO: xử lý khi chuyển tab ở đây if (prev.current === "(tabs)" && currentSegment !== "(tabs)") { stopEvents(); - // console.log("Stop events"); + console.log("Stop events"); } else if (prev.current !== "(tabs)" && currentSegment === "(tabs)") { // we came back into the tabs group — restart polling startEvents(); - // console.log("start events"); + console.log("start events"); } prev.current = currentSegment; } diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index d95172a..8d13633 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -145,7 +145,7 @@ export default function HomeScreen() { } for (const zone of zones) { - console.log("Zone Data: ", zone); + // console.log("Zone Data: ", zone); const geom = banzoneData.find((b) => b.id === zone.zone_id); if (!geom) { continue; diff --git a/components/tripInfo/modal/CreateOrUpdateHaulModal.tsx b/components/tripInfo/modal/CreateOrUpdateHaulModal.tsx index 55249fd..60d41ed 100644 --- a/components/tripInfo/modal/CreateOrUpdateHaulModal.tsx +++ b/components/tripInfo/modal/CreateOrUpdateHaulModal.tsx @@ -1,6 +1,10 @@ import Select from "@/components/Select"; import { IconSymbol } from "@/components/ui/icon-symbol"; +import { queryGpsData } from "@/controller/DeviceController"; +import { queryUpdateFishingLogs } from "@/controller/TripController"; +import { showErrorToast, showSuccessToast } from "@/services/toast_service"; import { useFishes } from "@/state/use-fish"; +import { useTrip } from "@/state/use-trip"; import { zodResolver } from "@hookform/resolvers/zod"; import React from "react"; import { Controller, useFieldArray, useForm } from "react-hook-form"; @@ -24,7 +28,6 @@ interface CreateOrUpdateHaulModalProps { fishingLog?: Model.FishingLog | null; fishingLogIndex?: number; } - const UNITS = ["con", "kg", "tấn"] as const; type Unit = (typeof UNITS)[number]; @@ -70,6 +73,7 @@ const CreateOrUpdateHaulModal: React.FC = ({ const [expandedFishIndices, setExpandedFishIndices] = React.useState< number[] >([]); + const { trip, getTrip } = useTrip(); const { control, handleSubmit, formState, watch, reset } = useForm({ resolver: zodResolver(formSchema), @@ -95,26 +99,90 @@ const CreateOrUpdateHaulModal: React.FC = ({ ); }; - const onSubmit = (values: FormValues) => { - // Map form values to the FishingLogInfo-like shape the user requested - const mapped = values.fish.map((f) => { - const meta = fishSpecies!.find((x) => x.id === f.id); - return { - fish_species_id: f.id, - fish_name: meta?.name, - catch_number: f.quantity, - catch_unit: f.unit, - fish_size: f.size, - fish_rarity: meta?.rarity_level, - fish_condition: "", - gear_usage: "", - } as unknown; // inferred shape — keep as unknown to avoid relying on global types here - }); + const onSubmit = async (values: FormValues) => { + // Ensure species list is available so we can populate name/rarity + if (!fishSpecies || fishSpecies.length === 0) { + showErrorToast("Danh sách loài cá chưa sẵn sàng"); + return; + } + // Helper to map form rows -> API info entries (single place) + const buildInfo = (rows: FormValues["fish"]) => + rows.map((item) => { + const meta = fishSpecies.find((f) => f.id === item.id); + return { + fish_species_id: item.id, + fish_name: meta?.name ?? "", + catch_number: item.quantity, + catch_unit: item.unit, + fish_size: item.size, + fish_rarity: meta?.rarity_level ?? null, + fish_condition: "", + gear_usage: "", + } as unknown; + }); - console.log("SUBMIT (FishingLogInfo[]): ", JSON.stringify(mapped, null, 2)); + try { + const gpsResp = await queryGpsData(); + if (!gpsResp.data) { + showErrorToast("Không thể lấy dữ liệu GPS hiện tại"); + return; + } + const gpsData = gpsResp.data; - // close modal after submit (you can change this to pass the payload to a parent via prop) - onClose(); + const info = buildInfo(values.fish) as any; + + // Base payload fields shared between create and update + const base: Partial = { + fishing_log_id: fishingLog?.fishing_log_id || "", + trip_id: trip?.id || "", + start_at: fishingLog?.start_at!, + start_lat: fishingLog?.start_lat!, + start_lon: fishingLog?.start_lon!, + weather_description: + fishingLog?.weather_description || "Nắng đẹp, Trời nhiều mây", + info, + sync: true, + }; + + // Build final payload depending on create vs update + const body: Model.FishingLog = + fishingLog?.status == 0 + ? ({ + ...base, + haul_lat: gpsData.lat, + haul_lon: gpsData.lon, + end_at: new Date(), + status: 1, + } as Model.FishingLog) + : ({ + ...base, + haul_lat: fishingLog?.haul_lat, + haul_lon: fishingLog?.haul_lon, + end_at: fishingLog?.end_at, + status: fishingLog?.status, + } as Model.FishingLog); + // console.log("Body: ", body); + + const resp = await queryUpdateFishingLogs(body); + if (resp?.status === 200) { + showSuccessToast( + fishingLog?.fishing_log_id == null + ? "Thêm mẻ cá thành công" + : "Cập nhật mẻ cá thành công" + ); + getTrip(); + onClose(); + } else { + showErrorToast( + fishingLog?.fishing_log_id == null + ? "Thêm mẻ cá thất bại" + : "Cập nhật mẻ cá thất bại" + ); + } + } catch (err) { + console.error("onSubmit error:", err); + showErrorToast("Có lỗi xảy ra khi lưu mẻ cá"); + } }; // Initialize / reset form when modal visibility or haulData changes diff --git a/controller/TripController.ts b/controller/TripController.ts index a27397c..b1d87be 100644 --- a/controller/TripController.ts +++ b/controller/TripController.ts @@ -2,6 +2,7 @@ import { api } from "@/config"; import { API_GET_TRIP, API_HAUL_HANDLE, + API_UPDATE_FISHING_LOGS, API_UPDATE_TRIP_STATUS, } from "@/constants"; @@ -16,3 +17,7 @@ export async function queryUpdateTripState(body: Model.TripUpdateStateRequest) { export async function queryStartNewHaul(body: Model.NewFishingLogRequest) { return api.put(API_HAUL_HANDLE, body); } + +export async function queryUpdateFishingLogs(body: Model.FishingLog) { + return api.put(API_UPDATE_FISHING_LOGS, body); +} \ No newline at end of file diff --git a/controller/typings.d.ts b/controller/typings.d.ts index f30f04e..1500520 100644 --- a/controller/typings.d.ts +++ b/controller/typings.d.ts @@ -152,8 +152,8 @@ declare namespace Model { interface FishingLog { fishing_log_id: string; trip_id: string; - start_at: string; // ISO datetime - end_at: string; // ISO datetime + start_at: Date; // ISO datetime + end_at: Date; // ISO datetime start_lat: number; start_lon: number; haul_lat: number;