import { getGPS } from '@/services/controller/DeviceController'; import { getFishSpecies, updateFishingLogs, } from '@/services/controller/TripController'; import { getColorByRarityLevel, getRarityById } from '@/utils/fishRarity'; import { DeleteOutlined } from '@ant-design/icons'; import { EditableProTable, ProColumns } from '@ant-design/pro-components'; import { Button, Flex, message, Modal, Tag, Tooltip, Typography } from 'antd'; import React, { useEffect, useState } from 'react'; interface CreateOrUpdateFishingLogProps { trip: API.Trip; fishingLogs?: API.FishingLog; isFinished: boolean; isOpen: boolean; onOpenChange: (open: boolean) => void; onFinished?: (success: boolean) => void; } interface FishingLogInfoWithKey extends API.FishingLogInfo { key: React.Key; } const CreateOrUpdateFishingLog: React.FC = ({ trip, fishingLogs, isFinished, isOpen, onOpenChange, onFinished, }) => { const [dataSource, setDataSource] = useState< readonly FishingLogInfoWithKey[] >([]); const [editableKeys, setEditableRowKeys] = useState([]); const [fishDatas, setFishDatas] = useState([]); useEffect(() => { getAllFish(); if (isOpen) { console.log('Modal opened with fishingLogs:', fishingLogs); if (fishingLogs?.info && fishingLogs.info.length > 0) { const dataWithKeys: FishingLogInfoWithKey[] = fishingLogs.info.map( (item, index) => ({ ...item, key: index, }), ); setDataSource(dataWithKeys); setEditableRowKeys(dataWithKeys.map((item) => item.key)); } else { // Nếu không có info thì reset table setDataSource([]); setEditableRowKeys([]); } } }, [isOpen, fishingLogs]); const getAllFish = async () => { try { const resp = await getFishSpecies(); setFishDatas(resp); console.log('Fetched fish species:', resp); } catch (error) { console.error('Error fetching fish species:', error); } }; const columns: ProColumns[] = [ { title: 'Tên cá', dataIndex: 'fish_species_id', valueType: 'select', fieldProps: { showSearch: true, options: fishDatas.map((f) => ({ label: f.name, value: f.id, data: JSON.stringify(f), })), optionRender: (option: any) => { const fish: API.FishSpeciesResponse = JSON.parse(option.data.data); const fishRarity = getRarityById(fish.rarity_level || 1); return ( {fish.name} {fishRarity?.rarityLabel} ); }, }, formItemProps: { rules: [{ required: true, message: 'Vui lòng chọn tên cá' }], }, }, { title: 'Kích thước (cm)', dataIndex: 'fish_size', valueType: 'digit', width: '15%', formItemProps: { rules: [ { required: true, message: 'Vui lòng nhập kích thước', }, ], }, }, { title: 'Số lượng', dataIndex: 'catch_number', valueType: 'digit', width: '15%', formItemProps: { rules: [ { required: true, message: 'Vui lòng nhập số lượng', }, ], }, }, { title: 'Đơn vị', dataIndex: 'catch_unit', valueType: 'select', width: '15%', valueEnum: { kg: 'kg', con: 'con', tấn: 'tấn', }, formItemProps: { rules: [ { required: true, message: 'Vui lòng chọn đơn vị', }, ], }, }, { title: 'Thao tác', valueType: 'option', width: 120, render: () => { return null; }, }, ]; async function createOrCreateOrUpdateFishingLog( fishingLog: FishingLogInfoWithKey[], ) { console.log('Is finished:', isFinished); console.log('Trip:', trip); try { const gpsData = await getGPS(); if (gpsData) { if (isFinished == false) { // Tạo mẻ mới const logStatus0 = trip.fishing_logs?.find((log) => log.status === 0); console.log('ok', logStatus0); console.log('ok', fishingLog); const body: API.FishingLog = { fishing_log_id: logStatus0?.fishing_log_id || '', trip_id: trip.id, start_at: logStatus0?.start_at!, start_lat: logStatus0?.start_lat!, start_lon: logStatus0?.start_lon!, haul_lat: gpsData.lat, haul_lon: gpsData.lon, end_at: new Date(), status: 1, weather_description: logStatus0?.weather_description || '', info: fishingLog.map((item) => ({ fish_species_id: item.fish_species_id, fish_name: item.fish_name, catch_number: item.catch_number, catch_unit: item.catch_unit, fish_size: item.fish_size, fish_rarity: item.fish_rarity, fish_condition: '', gear_usage: '', })), sync: true, }; const resp = await updateFishingLogs(body); console.log('Resp', resp); onFinished?.(true); onOpenChange(false); } else { const body: API.FishingLog = { fishing_log_id: fishingLogs?.fishing_log_id || '', trip_id: fishingLogs?.trip_id!, start_at: fishingLogs?.start_at!, start_lat: fishingLogs?.start_lat!, start_lon: fishingLogs?.start_lon!, haul_lat: fishingLogs?.haul_lat!, haul_lon: fishingLogs?.haul_lon!, end_at: fishingLogs?.end_at!, status: fishingLogs?.status!, weather_description: fishingLogs?.weather_description || '', info: fishingLog.map((item) => ({ fish_species_id: item.fish_species_id, fish_name: item.fish_name, catch_number: item.catch_number, catch_unit: item.catch_unit, fish_size: item.fish_size, fish_rarity: item.fish_rarity, fish_condition: '', gear_usage: '', })), sync: true, }; // console.log('Update body:', body); const resp = await updateFishingLogs(body); console.log('Resp', resp); onFinished?.(true); onOpenChange(false); } setDataSource([]); setEditableRowKeys([]); } else { message.error('Không thể lấy dữ liệu GPS. Vui lòng thử lại.'); } } catch (error) { onFinished?.(false); console.error('Error creating/updating haul:', error); } } return ( onOpenChange(false)} onOk={async () => { // Validate data trước khi submit const validData = dataSource.filter( (item) => item.fish_name && item.fish_size && item.catch_number && item.catch_unit, ); if (validData.length === 0) { message.error( 'Vui lòng nhập ít nhất một loài cá với đầy đủ thông tin', ); return; } await createOrCreateOrUpdateFishingLog(validData); }} > key={fishingLogs?.fishing_log_id} headerTitle="Danh sách cá đánh bắt" columns={columns} rowKey="key" scroll={{ x: 960, }} value={dataSource} onChange={setDataSource} recordCreatorProps={{ newRecordType: 'dataSource', creatorButtonText: 'Thêm loài', record: () => ({ key: Date.now(), }), }} editable={{ type: 'multiple', editableKeys, actionRender: (row, config, defaultDoms) => { return [defaultDoms.delete]; }, deletePopconfirmMessage: 'Bạn chắc chắn muốn xoá?', onValuesChange: ( record: Partial | undefined, recordList: FishingLogInfoWithKey[], ) => { // Nếu không có record (sự kiện không liên quan tới 1 dòng cụ thể) thì chỉ cập nhật dataSource if (!record) { setDataSource([...recordList]); return; } // Lấy giá trị species id (cẩn trọng string/number) const speciesId = (record as any).fish_species_id; if (speciesId === undefined || speciesId === null) { // Nếu không phải là thay đổi chọn loài cá, chỉ cập nhật dataSource setDataSource([...recordList]); return; } // Tìm loài cá tương ứng, so sánh bằng String để tránh khác kiểu number/string const fish = fishDatas.find( (f) => String(f.id) === String(speciesId), ); if (!fish) { setDataSource([...recordList]); return; } // Tạo record mới (merge thông tin loài cá vào dòng hiện tại) const mergedRecord: FishingLogInfoWithKey = { ...(record as FishingLogInfoWithKey), fish_species_id: fish.id, fish_name: fish.name, catch_unit: fish.default_unit, fish_rarity: fish.rarity_level, }; // Áp lại vào recordList dựa theo key (so khớp key bằng String để an toàn) const newList = recordList.map((r) => String(r.key) === String(mergedRecord.key) ? mergedRecord : r, ); // Cập nhật state (sao chép mảng để tránh vấn đề readonly/type) setDataSource([...newList]); // Đảm bảo dòng này đang ở trạng thái editable (nếu cần) setEditableRowKeys((prev) => prev.includes(mergedRecord.key) ? prev : [...prev, mergedRecord.key], ); }, onChange: setEditableRowKeys, deleteText: (