diff --git a/apps/api/src/aws/aws.service.ts b/apps/api/src/aws/aws.service.ts index e6046ef4..12f2243e 100644 --- a/apps/api/src/aws/aws.service.ts +++ b/apps/api/src/aws/aws.service.ts @@ -22,9 +22,13 @@ export class AwsService { constructor() {} async uploadFileToS3(fileName: string, file: Buffer, folderName?: string) { + const MAX_UPLOAD_SIZE = 1024 * 1024 * 10; // 10MB const currentDate = new Date(); const dateWithTimestamp = currentDate.toISOString(); const fileType = '.' + fileName.split('.').pop(); + + if (file.byteLength > MAX_UPLOAD_SIZE) throw new Error('ไฟล์ใหญ่เกิน 10MB'); + // '{2024-09-05T16:19:34.142Z}-' has 27 characters const truncatedFileName = truncateTextByBytes( fileName.slice(0, -fileType.length), diff --git a/apps/api/src/user-filing/user-filing.service.ts b/apps/api/src/user-filing/user-filing.service.ts index 380f7424..0e92ece0 100644 --- a/apps/api/src/user-filing/user-filing.service.ts +++ b/apps/api/src/user-filing/user-filing.service.ts @@ -37,7 +37,7 @@ export class UserFilingService { return userFilings; } - async userOpenFiling(userId: string, filingId: string): Promise { + async userOpenFiling(userId: string, filingId: string) { if (!isUUID(userId) || !isUUID(filingId)) { throw new BadRequestException('Id is not in UUID format'); } @@ -58,6 +58,9 @@ export class UserFilingService { lastOpen: new Date(), }; - return await this.userFilingRepository.save(preparedUserFiling); + return await this.userFilingRepository.upsert(preparedUserFiling, { + conflictPaths: ['user', 'filing'], + skipUpdateIfNoValuesChanged: true, + }); } } diff --git a/apps/web/src/app/(authenticated)/project/[projectId]/[filingId]/page.tsx b/apps/web/src/app/(authenticated)/project/[projectId]/[filingId]/page.tsx index 9f26d562..8169e958 100644 --- a/apps/web/src/app/(authenticated)/project/[projectId]/[filingId]/page.tsx +++ b/apps/web/src/app/(authenticated)/project/[projectId]/[filingId]/page.tsx @@ -19,6 +19,7 @@ import updateFilingName from '@/src/service/filing/updateFiling'; import { isUUID } from '@/src/lib/utils'; import getUsersMap from '@/src/service/user/getUsersMap'; import { getUserId } from '@/src/service/auth'; +import userOpenFiling from '@/src/service/user-filing/userOpenFiling'; export default function Page({ params, @@ -62,11 +63,13 @@ export default function Page({ if (filingData) setFiling(filingData); if (latestDocumentData) setLatestDocument(latestDocumentData); - if (documentsData.length === 0) return; - setDocuments(documentsData); - - const updatedUsernameMap = await getUsersMap(documentsData, userId); + const [updatedUsernameMap] = await Promise.all([ + getUsersMap(documentsData, userId), + userOpenFiling(userId, params.filingId), + ]); setUsernameMap(updatedUsernameMap); + + if (documentsData.length > 0) setDocuments(documentsData); } catch (err) { if (err instanceof Error) { toast({ diff --git a/apps/web/src/app/admin/project/[projectId]/[filingId]/page.tsx b/apps/web/src/app/admin/project/[projectId]/[filingId]/page.tsx index b803037a..b54397b7 100644 --- a/apps/web/src/app/admin/project/[projectId]/[filingId]/page.tsx +++ b/apps/web/src/app/admin/project/[projectId]/[filingId]/page.tsx @@ -19,6 +19,7 @@ import updateFilingName from '@/src/service/filing/updateFiling'; import { isUUID } from '@/src/lib/utils'; import { getUserId } from '@/src/service/auth'; import getUsersMap from '@/src/service/user/getUsersMap'; +import userOpenFiling from '@/src/service/user-filing/userOpenFiling'; export default function Page({ params, @@ -62,11 +63,13 @@ export default function Page({ if (filingData) setFiling(filingData); if (latestDocumentData) setLatestDocument(latestDocumentData); - if (documentsData.length === 0) return; - setDocuments(documentsData); - - const updatedUsernameMap = await getUsersMap(documentsData, userId); + const [updatedUsernameMap] = await Promise.all([ + getUsersMap(documentsData, userId), + userOpenFiling(userId, params.filingId), + ]); setUsernameMap(updatedUsernameMap); + + if (documentsData.length > 0) setDocuments(documentsData); } catch (err) { if (err instanceof Error) { toast({ diff --git a/apps/web/src/components/filling-detail/create-edit/createDocumentClient.tsx b/apps/web/src/components/filling-detail/create-edit/createDocumentClient.tsx index 49588e0a..0a55f26f 100644 --- a/apps/web/src/components/filling-detail/create-edit/createDocumentClient.tsx +++ b/apps/web/src/components/filling-detail/create-edit/createDocumentClient.tsx @@ -18,13 +18,10 @@ import ButtonPanel from './buttonPanel'; import FileInputPanel from './fileInputPanel'; import ActivityPanel from './activityPanel'; import { DocumentType } from '@/src/interface/document'; -import createDocument from '@/src/service/document/createDocument'; -import { DocumentActivity, FilingStatus } from '@/src/constant/enum'; -import { getFileType } from '@/src/lib/utils'; -import updateFilingName from '@/src/service/filing/updateFiling'; +import { FilingStatus } from '@/src/constant/enum'; import { toast } from '../../ui/use-toast'; -import uploadFileToS3 from '@/src/service/aws/uploadFileToS3'; -import { zodDocumentFiles } from '@/src/constant/schema'; +import { createdFormSchema } from '@/src/constant/schema'; +import submitCreatedFormSchema from '@/src/lib/submitCreatedFormSchema'; export default function CreateDocumentClient({ setShowCreateDocument, @@ -39,14 +36,6 @@ export default function CreateDocumentClient({ projectId: string; status: FilingStatus; }) { - const createdFormSchema = z.object({ - // Server side ไม่รู้จัก FileList *** - file: zodDocumentFiles, - activity: z.nativeEnum(DocumentActivity, { message: 'กรุณากรอกกิจกรรม' }), - detail: z.string().min(1, { message: 'กรุณากรอกรายละเอียด' }), - note: z.string().optional(), - }); - const form = useForm>({ resolver: zodResolver(createdFormSchema), defaultValues: { @@ -59,44 +48,14 @@ export default function CreateDocumentClient({ async function onSubmit(values: z.infer) { // TODO: change to actual userId try { - const swap = getFileType(values.file[0]) !== 'pdf'; - const pdfFile = values.file[swap ? 1 : 0]; - const docFile = values.file[swap ? 0 : 1]; - const folderName = `${projectId}/${filingId}`; - - const [pdfName, docName] = await Promise.all([ - uploadFileToS3({ - file: pdfFile, - folderName, - }), - docFile && - uploadFileToS3({ - file: docFile, - folderName, - }), - ]); - - if (!pdfName || (docFile && !docName)) - throw new Error('Upload file failed'); + const newDocument = await submitCreatedFormSchema( + values, + projectId, + filingId, + 'd1c0d106-1a4a-4729-9033-1b2b2d52e98a', + status, + ); - const [newDocument, _] = await Promise.all([ - createDocument({ - document: { - name: values.detail, - filingId, - pdfName: pdfName, - docName: docName ?? '', - activity: values.activity as DocumentActivity, - userId: 'd1c0d106-1a4a-4729-9033-1b2b2d52e98a', - detail: values.note, - }, - }), - status === FilingStatus.DRAFT && - updateFilingName({ - filingId, - filingStatus: FilingStatus.DOCUMENT_CREATED, - }), - ]); afterCreateDocument(newDocument); toast({ title: 'สร้างเอกสารสำเร็จ', diff --git a/apps/web/src/components/filling-detail/create-edit/updateDocumentAdmin.tsx b/apps/web/src/components/filling-detail/create-edit/updateDocumentAdmin.tsx index 0c974975..5785bf6f 100644 --- a/apps/web/src/components/filling-detail/create-edit/updateDocumentAdmin.tsx +++ b/apps/web/src/components/filling-detail/create-edit/updateDocumentAdmin.tsx @@ -17,13 +17,11 @@ import { Select } from '../../ui/select'; import ButtonPanel from './buttonPanel'; import FileInputPanel from './fileInputPanel'; import ActivityPanel from './activityPanel'; -import { getFileType } from '@/src/lib/utils'; import { DocumentType } from '@/src/interface/document'; import { DocumentActivity } from '@/src/constant/enum'; import { toast } from '../../ui/use-toast'; -import uploadFileToS3 from '@/src/service/aws/uploadFileToS3'; -import createDocument from '@/src/service/document/createDocument'; -import { zodDocumentFiles } from '@/src/constant/schema'; +import { createdFormSchema } from '@/src/constant/schema'; +import submitCreatedFormSchema from '@/src/lib/submitCreatedFormSchema'; export default function UpdateDocumentAdmin({ setShowCreateDocument, @@ -36,14 +34,6 @@ export default function UpdateDocumentAdmin({ filingId: string; projectId: string; }) { - const createdFormSchema = z.object({ - file: zodDocumentFiles, - activity: z.nativeEnum(DocumentActivity, { message: 'กรุณากรอกกิจกรรม' }), - detail: z.string().min(1, { message: 'กรุณากรอกรายละเอียด' }), - note: z.string().optional(), - comment: z.string().optional(), - }); - const form = useForm>({ resolver: zodResolver(createdFormSchema), defaultValues: { @@ -57,38 +47,13 @@ export default function UpdateDocumentAdmin({ async function onSubmit(values: z.infer) { // TODO: change to actual userId try { - const swap = getFileType(values.file[0]) !== 'pdf'; - const pdfFile = values.file[swap ? 1 : 0]; - const docFile = values.file[swap ? 0 : 1]; - const folderName = `${projectId}/${filingId}`; - - const [pdfName, docName] = await Promise.all([ - uploadFileToS3({ - file: pdfFile, - folderName, - }), - docFile && - uploadFileToS3({ - file: docFile, - folderName, - }), - ]); + const newDocument = await submitCreatedFormSchema( + values, + projectId, + filingId, + 'd1c0d106-1a4a-4729-9033-1b2b2d52e98a', + ); - if (!pdfName || (docFile && !docName)) - throw new Error('Upload file failed'); - - const newDocument = await createDocument({ - document: { - name: values.detail, - filingId, - pdfName: pdfName, - docName: docName ?? '', - activity: values.activity as DocumentActivity, - userId: 'd1c0d106-1a4a-4729-9033-1b2b2d52e98a', - detail: values.note, - comment: values.comment, - }, - }); afterCreateDocument(newDocument); toast({ title: 'แก้ไขเอกสารสำเร็จ', diff --git a/apps/web/src/components/filling-detail/display/displayWithNoteAndStatus.tsx b/apps/web/src/components/filling-detail/display/displayWithNoteAndStatus.tsx index a00c2725..d49a6619 100644 --- a/apps/web/src/components/filling-detail/display/displayWithNoteAndStatus.tsx +++ b/apps/web/src/components/filling-detail/display/displayWithNoteAndStatus.tsx @@ -36,77 +36,75 @@ export default function DisplayWithNoteAndStatus({ const [isOpen, setIsOpen] = useState(false); return ( -
- -
- - - -
-
ความคิดเห็น
- -
-
- {handleDeleteDocument ? ( - { - handleDeleteDocument(document.id); - }} - /> - ) : ( - - )} - { - setExpanded(!expanded); + +
+ + + +
+
ความคิดเห็น
+ +
+
+ {handleDeleteDocument ? ( + { + handleDeleteDocument(document.id); }} - > - {expanded ? : } - -
+ /> + ) : ( + + )} + { + setExpanded(!expanded); + }} + > + {expanded ? : } +
- -
-
- รายละเอียดเอกสาร: - {document.name} +
+ +
+
+ รายละเอียดเอกสาร: + {document.name} +
+
+
+
หมายเหตุ
+
-
-
-
หมายเหตุ
- -
-
-
ไฟล์แนบ
-
+
+
ไฟล์แนบ
+
+ + {document.docName !== '' && document.docName !== '-' && ( - {document.docName !== '' && document.docName !== '-' && ( - - )} -
+ )}
- - -
+
+ + ); } diff --git a/apps/web/src/components/filling-detail/filingTimeline.tsx b/apps/web/src/components/filling-detail/filingTimeline.tsx index 50076748..7914bec6 100644 --- a/apps/web/src/components/filling-detail/filingTimeline.tsx +++ b/apps/web/src/components/filling-detail/filingTimeline.tsx @@ -138,11 +138,17 @@ export default function FilingTimeline({ ? 'วันนี้' : currentDate}
- +
+ +
); } - return ; + return ( +
+ +
+ ); }); return ( diff --git a/apps/web/src/components/filling-detail/filingTimelineHeader.tsx b/apps/web/src/components/filling-detail/filingTimelineHeader.tsx index 8ae6a68f..0875fbfa 100644 --- a/apps/web/src/components/filling-detail/filingTimelineHeader.tsx +++ b/apps/web/src/components/filling-detail/filingTimelineHeader.tsx @@ -10,14 +10,13 @@ import { DialogTitle, DialogTrigger, } from '../ui/dialog'; -import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react'; -import { useToast } from '../ui/use-toast'; +import { Dispatch, SetStateAction, useMemo, useState } from 'react'; +import { toast } from '../ui/use-toast'; import updateFilingName from '@/src/service/filing/updateFiling'; import CreateDocumentClient from './create-edit/createDocumentClient'; import { DocumentType } from '@/src/interface/document'; import updateDocument from '@/src/service/document/updateDocument'; import FilingTimelineHeaderApproved from './filingTimelineHeaderApproved'; -import getUrlToFile from '@/src/service/aws/getUrlToFile'; import CreateDocumentAdmin from './create-edit/createDocumentAdmin'; import { Select, SelectContent, SelectItem, SelectTrigger } from '../ui/select'; import { IoIosAlert } from 'react-icons/io'; @@ -52,9 +51,7 @@ export default function FilingTimelineHeader({ const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false); const [isReviewDialogOpen, setIsReviewDialogOpen] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); - const [pdfLink, setPdfLink] = useState(); const [reviewButton, setReviewButton] = useState('อนุมัติ'); - const { toast } = useToast(); const updateDocumentStatuses = async ( documents: DocumentType[], @@ -174,17 +171,6 @@ export default function FilingTimelineHeader({ } setIsSubmitting(false); }; - const fetchPdfLink = async () => { - const signedUrl = await getUrlToFile({ - fileName: latestDocument?.pdfName ?? '', - folderName: `${projectId}/${filingId}`, - }); - - setPdfLink(signedUrl); - }; - useEffect(() => { - if (status === FilingStatus.APPROVED && latestDocument) fetchPdfLink(); - }, [status, latestDocument]); const AddDocumentButton = () => ( - + {!noBadge && (