mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-24 23:35:45 +00:00
feat: add upload document in daily checklist
This commit is contained in:
@@ -30,7 +30,7 @@ import { KandangApi } from '@/services/api/master-data';
|
|||||||
import { DailyChecklistApi } from '@/services/api/daily-checklist/daily-checklist';
|
import { DailyChecklistApi } from '@/services/api/daily-checklist/daily-checklist';
|
||||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { BaseApiResponse } from '@/types/api/api-general';
|
import { BaseApiResponse, Document } from '@/types/api/api-general';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { httpClientFetcher, SWRHttpKey } from '@/services/http/client';
|
import { httpClientFetcher, SWRHttpKey } from '@/services/http/client';
|
||||||
import { PhaseApi } from '@/services/api/daily-checklist/phase';
|
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 { PhaseActivityApi } from '@/services/api/daily-checklist/phase-activity';
|
||||||
import { PhaseActivity } from '@/types/api/daily-checklist/phase-activity';
|
import { PhaseActivity } from '@/types/api/daily-checklist/phase-activity';
|
||||||
import DebouncedTextArea from '@/components/input/DebouncedTextArea';
|
import DebouncedTextArea from '@/components/input/DebouncedTextArea';
|
||||||
|
import DropFileInput from '@/components/input/DropFileInput';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
|
||||||
// Static categories
|
// Static categories
|
||||||
const CATEGORIES = [
|
const CATEGORIES = [
|
||||||
@@ -148,6 +151,10 @@ export function DailyChecklistContent() {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [initialLoading, setInitialLoading] = useState(true);
|
const [initialLoading, setInitialLoading] = useState(true);
|
||||||
|
|
||||||
|
const [existingDocuments, setExistingDocuments] = useState<Document[]>([]);
|
||||||
|
const [documents, setDocuments] = useState<File[]>([]);
|
||||||
|
const [deletedDocumentIds, setDeletedDocumentIds] = useState<number[]>([]);
|
||||||
|
|
||||||
// Format date for display
|
// Format date for display
|
||||||
const formatDateForDisplay = (dateStr: string) => {
|
const formatDateForDisplay = (dateStr: string) => {
|
||||||
if (!dateStr) return 'Pilih tanggal';
|
if (!dateStr) return 'Pilih tanggal';
|
||||||
@@ -340,6 +347,9 @@ export function DailyChecklistContent() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set existing document
|
||||||
|
setExistingDocuments(existingDailyChecklist?.data.document_urls || []);
|
||||||
|
|
||||||
// Build assignments map
|
// Build assignments map
|
||||||
const assignmentMap: {
|
const assignmentMap: {
|
||||||
[taskId: string]: {
|
[taskId: string]: {
|
||||||
@@ -729,7 +739,11 @@ export function DailyChecklistContent() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const submitRes = await DailyChecklistApi.submit(dailyChecklistId);
|
const submitRes = await DailyChecklistApi.submit(
|
||||||
|
dailyChecklistId,
|
||||||
|
documents,
|
||||||
|
deletedDocumentIds
|
||||||
|
);
|
||||||
|
|
||||||
if (isResponseError(submitRes)) {
|
if (isResponseError(submitRes)) {
|
||||||
console.error('Error submitting:', submitRes.message);
|
console.error('Error submitting:', submitRes.message);
|
||||||
@@ -750,6 +764,19 @@ export function DailyChecklistContent() {
|
|||||||
const handleSaveDraft = async () => {
|
const handleSaveDraft = async () => {
|
||||||
if (!dailyChecklistId) return;
|
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');
|
toast.success('Draft tersimpan otomatis');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1263,6 +1290,94 @@ export function DailyChecklistContent() {
|
|||||||
</div>
|
</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 */}
|
{/* Action Buttons */}
|
||||||
{dailyChecklistId &&
|
{dailyChecklistId &&
|
||||||
selectedPhaseIds.length > 0 &&
|
selectedPhaseIds.length > 0 &&
|
||||||
|
|||||||
Reference in New Issue
Block a user