feat: add upload document in daily checklist

This commit is contained in:
ValdiANS
2026-01-12 17:30:30 +07:00
parent 1002c6c437
commit 9245285fe2
@@ -30,7 +30,7 @@ import { KandangApi } from '@/services/api/master-data';
import { DailyChecklistApi } from '@/services/api/daily-checklist/daily-checklist';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import useSWR from 'swr';
import { BaseApiResponse } from '@/types/api/api-general';
import { BaseApiResponse, Document } from '@/types/api/api-general';
import { AxiosError } from 'axios';
import { httpClientFetcher, SWRHttpKey } from '@/services/http/client';
import { PhaseApi } from '@/services/api/daily-checklist/phase';
@@ -39,6 +39,9 @@ import { Employee } from '@/types/api/daily-checklist/employee';
import { PhaseActivityApi } from '@/services/api/daily-checklist/phase-activity';
import { PhaseActivity } from '@/types/api/daily-checklist/phase-activity';
import DebouncedTextArea from '@/components/input/DebouncedTextArea';
import DropFileInput from '@/components/input/DropFileInput';
import Link from 'next/link';
import { Icon } from '@iconify/react';
// Static categories
const CATEGORIES = [
@@ -148,6 +151,10 @@ export function DailyChecklistContent() {
const [loading, setLoading] = useState(false);
const [initialLoading, setInitialLoading] = useState(true);
const [existingDocuments, setExistingDocuments] = useState<Document[]>([]);
const [documents, setDocuments] = useState<File[]>([]);
const [deletedDocumentIds, setDeletedDocumentIds] = useState<number[]>([]);
// Format date for display
const formatDateForDisplay = (dateStr: string) => {
if (!dateStr) return 'Pilih tanggal';
@@ -340,6 +347,9 @@ export function DailyChecklistContent() {
return;
}
// set existing document
setExistingDocuments(existingDailyChecklist?.data.document_urls || []);
// Build assignments map
const assignmentMap: {
[taskId: string]: {
@@ -729,7 +739,11 @@ export function DailyChecklistContent() {
setLoading(true);
try {
const submitRes = await DailyChecklistApi.submit(dailyChecklistId);
const submitRes = await DailyChecklistApi.submit(
dailyChecklistId,
documents,
deletedDocumentIds
);
if (isResponseError(submitRes)) {
console.error('Error submitting:', submitRes.message);
@@ -750,6 +764,19 @@ export function DailyChecklistContent() {
const handleSaveDraft = async () => {
if (!dailyChecklistId) return;
const uploadImageRes = await DailyChecklistApi.uploadImage(
Number(dailyChecklistId),
'DRAFT',
documents,
deletedDocumentIds
);
if (isResponseError(uploadImageRes)) {
console.error('Error saving draft:', uploadImageRes.message);
toast.error('Gagal menyimpan draft');
return;
}
toast.success('Draft tersimpan otomatis');
};
@@ -1263,6 +1290,94 @@ export function DailyChecklistContent() {
</div>
)}
{dailyChecklistId &&
selectedPhaseIds.length > 0 &&
selectedEmployees.length > 0 && (
<>
{existingDocuments.length > 0 && (
<div className='mt-6'>
<h3 className='font-semibold text-gray-900 mb-2'>
Dokumen yang telah diupload
</h3>
{existingDocuments.map(
(existingDocument, existingDocumentIdx) => (
<div
key={existingDocumentIdx}
className='w-full flex flex-wrap justify-between'
>
<Link
href={existingDocument.url}
target='_blank'
rel='noopener noreferrer'
className='text-blue-500 underline'
>
{existingDocument.name}{' '}
<Icon
icon='cuida:open-in-new-tab-outline'
width={12}
height={12}
className='inline'
/>
</Link>
<Button
type='button'
variant='ghost'
color='error'
onClick={() => {
setDeletedDocumentIds((prevIds) => [
...prevIds,
existingDocument.id,
]);
setExistingDocuments((prevExistingDocument) => {
const newExistingDocuments = [
...prevExistingDocument,
];
newExistingDocuments.splice(
existingDocumentIdx,
1
);
return newExistingDocuments;
});
}}
className='p-1 rounded-full text-error focus-visible:text-error-content hover:text-error-content'
>
<Icon
icon='fluent:delete-12-regular'
width={20}
height={20}
/>
</Button>
</div>
)
)}
</div>
)}
<DropFileInput
name='Dokumen'
label='Dokumen'
values={documents}
onChange={(files) => {
setDocuments(files);
}}
onDelete={(deletedFileIdx: number) => {
const newRequestDocuments = [...documents];
newRequestDocuments?.splice(deletedFileIdx, 1);
setDocuments(newRequestDocuments);
}}
className={{
wrapper: 'mt-6',
inputWrapper: 'flex items-center',
label: 'font-semibold text-gray-900',
}}
/>
</>
)}
{/* Action Buttons */}
{dailyChecklistId &&
selectedPhaseIds.length > 0 &&