@lifesg/web-frontend-engine 2.0.0-alpha.18 → 2.0.0-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/chunks/{file-upload-manager.6f91498f.js → file-upload-manager.6091aa9e.js} +2 -2
  2. package/chunks/file-upload-manager.6091aa9e.js.map +1 -0
  3. package/chunks/{index.01911ac9.js → index.cb4c93a5.js} +6 -6
  4. package/{cjs/chunks/index.33c9bcbb.js.map → chunks/index.cb4c93a5.js.map} +1 -1
  5. package/chunks/{index.c8228568.js → index.dcdbe23e.js} +2 -2
  6. package/chunks/{index.c8228568.js.map → index.dcdbe23e.js.map} +1 -1
  7. package/chunks/{index.94a6f552.js → index.df1ee6f5.js} +2 -2
  8. package/chunks/{index.94a6f552.js.map → index.df1ee6f5.js.map} +1 -1
  9. package/chunks/{location-modal.96339252.js → location-modal.b47d92b7.js} +2 -2
  10. package/chunks/{location-modal.96339252.js.map → location-modal.b47d92b7.js.map} +1 -1
  11. package/cjs/chunks/{file-upload-manager.2465d276.js → file-upload-manager.858f342f.js} +2 -2
  12. package/cjs/chunks/file-upload-manager.858f342f.js.map +1 -0
  13. package/cjs/chunks/{index.c8a96a82.js → index.3cfca5cf.js} +2 -2
  14. package/cjs/chunks/{index.c8a96a82.js.map → index.3cfca5cf.js.map} +1 -1
  15. package/cjs/chunks/{index.33c9bcbb.js → index.7db1a25b.js} +6 -6
  16. package/cjs/chunks/index.7db1a25b.js.map +1 -0
  17. package/cjs/chunks/{index.dbac2c71.js → index.ade37699.js} +2 -2
  18. package/cjs/chunks/{index.dbac2c71.js.map → index.ade37699.js.map} +1 -1
  19. package/cjs/chunks/{location-modal.07158be4.js → location-modal.ff0cd21c.js} +2 -2
  20. package/cjs/chunks/{location-modal.07158be4.js.map → location-modal.ff0cd21c.js.map} +1 -1
  21. package/cjs/index.js +1 -1
  22. package/components/shared/error-messages.d.ts +1 -0
  23. package/context-providers/yup/types.d.ts +8 -1
  24. package/index.js +1 -1
  25. package/package.json +1 -1
  26. package/chunks/file-upload-manager.6f91498f.js.map +0 -1
  27. package/chunks/index.01911ac9.js.map +0 -1
  28. package/cjs/chunks/file-upload-manager.2465d276.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-upload-manager.2465d276.js","sources":["../../../src/components/fields/file-upload/file-upload-manager.ts"],"sourcesContent":["import { AxiosError } from \"axios\";\nimport { useContext, useEffect, useRef } from \"react\";\nimport { useFormContext } from \"react-hook-form\";\nimport { AxiosApiClient, FileHelper, ImageHelper, generateRandomId } from \"../../../utils\";\nimport { useFieldEvent, usePrevious } from \"../../../utils/hooks\";\nimport { ERROR_MESSAGES } from \"../../shared\";\nimport { FileUploadContext } from \"./file-upload-context\";\nimport {\n\tEFileStatus,\n\tIFile,\n\tIFileUploadSchema,\n\tIFileUploadValidationRule,\n\tIFileUploadValue,\n\tTUploadErrorDetail,\n} from \"./types\";\n\ninterface IProps {\n\tcompressImages: boolean;\n\tfileTypeRule: IFileUploadValidationRule;\n\thideThumbnail?: boolean | undefined;\n\tid: string;\n\tmaxFileSizeRule: IFileUploadValidationRule;\n\tupload: IFileUploadSchema[\"uploadOnAddingFile\"];\n\tuploadRule: IFileUploadValidationRule;\n\tvalue: IFileUploadValue[];\n}\n\nconst RESIZEABLE_IMAGE_TYPES = [\"image/jpeg\", \"image/gif\", \"image/png\"];\n\nconst FileUploadManager = (props: IProps) => {\n\t// =============================================================================\n\t// CONST, STATE, REFS\n\t// =============================================================================\n\tconst { compressImages, fileTypeRule, hideThumbnail, id, maxFileSizeRule, upload, uploadRule, value } = props;\n\tconst { files, setFiles, setCurrentFileIds } = useContext(FileUploadContext);\n\tconst previousValue = usePrevious(value);\n\tconst { setValue } = useFormContext();\n\tconst { dispatchFieldEvent } = useFieldEvent();\n\tconst sessionId = useRef<string>();\n\n\t// =============================================================================\n\t// EFFECTS\n\t// =============================================================================\n\tuseEffect(() => {\n\t\tsessionId.current = generateRandomId();\n\t}, []);\n\n\tuseEffect(\n\t\t() => {\n\t\t\t// handle file status\n\t\t\tfiles.forEach(async (file, index) => {\n\t\t\t\ttry {\n\t\t\t\t\tswitch (file.status) {\n\t\t\t\t\t\tcase EFileStatus.INJECTED:\n\t\t\t\t\t\t\tawait injectFile(file, index);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase EFileStatus.NONE:\n\t\t\t\t\t\t\tawait parseFile(file, index);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase EFileStatus.UPLOAD_READY:\n\t\t\t\t\t\t\tawait uploadFile(file, index);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase EFileStatus.TO_DELETE:\n\t\t\t\t\t\t\tdeleteFile(index);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\thandleGenericError(index);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// track / update values\n\t\t\tconst uploadedFiles = files.filter(({ status }) => status === EFileStatus.UPLOADED);\n\t\t\tconst notPrefilledFiles = uploadedFiles.filter(({ addedFrom }) => addedFrom !== \"schema\");\n\t\t\tconst hasNotPrefilledFiles = notPrefilledFiles.length > 0;\n\t\t\tconst gotDeleteFiles = files.filter(({ status }) => status === EFileStatus.TO_DELETE).length > 0;\n\n\t\t\t/**\n\t\t\t * should dirty if\n\t\t\t * - it is dirty in the first place\n\t\t\t * - there are non-prefilled files\n\t\t\t * - user deleted file (differentiated from reset)\n\t\t\t */\n\t\t\tconst shouldDirty = hasNotPrefilledFiles || gotDeleteFiles;\n\n\t\t\tsetCurrentFileIds(uploadedFiles.map(({ fileItem }) => fileItem.id));\n\n\t\t\tsetValue(\n\t\t\t\tid,\n\t\t\t\tuploadedFiles.map(({ dataURL, fileItem, fileUrl, uploadResponse }) => ({\n\t\t\t\t\t...(upload.type === \"base64\" ? { dataURL } : {}),\n\t\t\t\t\tfileId: fileItem.id,\n\t\t\t\t\tfileName: fileItem.name,\n\t\t\t\t\tfileUrl,\n\t\t\t\t\tuploadResponse,\n\t\t\t\t})),\n\t\t\t\t{ shouldDirty, shouldTouch: hasNotPrefilledFiles }\n\t\t\t);\n\t\t}, // eslint-disable-next-line react-hooks/exhaustive-deps\n\t\t[files.map(({ fileItem, status }) => `${fileItem?.id}-${status}`).join(\",\")]\n\t);\n\n\t// for reset\n\tuseEffect(() => {\n\t\tif (previousValue !== undefined && value === undefined && files.length) {\n\t\t\tsetFiles([]);\n\t\t}\n\t}, [files, previousValue, setFiles, value]);\n\n\t// =============================================================================\n\t// HELPER FUNCTIONS\n\t// =============================================================================\n\n\tconst handleGenericError = (index: number) => {\n\t\tsetFiles((prev) => {\n\t\t\tconst updatedFiles = [...prev];\n\t\t\tconst file = prev[index];\n\t\t\tupdatedFiles[index] = {\n\t\t\t\t...file,\n\t\t\t\tfileItem: {\n\t\t\t\t\t...file.fileItem,\n\t\t\t\t\tid: file.fileItem?.id || generateRandomId(),\n\t\t\t\t\tname: file.rawFile.name,\n\t\t\t\t\terrorMessage: uploadRule?.errorMessage || ERROR_MESSAGES.UPLOAD().GENERIC,\n\t\t\t\t},\n\t\t\t\tstatus: EFileStatus.ERROR_GENERIC,\n\t\t\t};\n\t\t\treturn updatedFiles;\n\t\t});\n\t};\n\n\tconst generateThumbnail = async (file: IFile, fileType?: string | undefined) => {\n\t\tif (hideThumbnail !== true && RESIZEABLE_IMAGE_TYPES.includes(fileType || file.fileItem?.type)) {\n\t\t\tconst image = await ImageHelper.dataUrlToImage(file.dataURL);\n\t\t\tconst thumbnail = await ImageHelper.resampleImage(image, { width: 94, height: 94, crop: true });\n\t\t\treturn await FileHelper.fileToDataUrl(thumbnail);\n\t\t}\n\t\treturn \"\";\n\t};\n\n\tconst readFile = async (fileToRead: IFile) => {\n\t\tconst { addedFrom, dataURL, rawFile } = fileToRead;\n\t\tconst fileType = await FileHelper.getType(rawFile);\n\t\tconst fileTypeResult = validateFileType(fileType);\n\n\t\tif (fileTypeResult?.status < 0) {\n\t\t\treturn fileTypeResult;\n\t\t}\n\n\t\tconst fileSize = upload.type === \"base64\" ? FileHelper.getFilesizeFromBase64(dataURL) : rawFile.size;\n\t\tconst { errorMessage, status } = validateFileSize(fileSize);\n\t\tif (status < 0) {\n\t\t\treturn { errorMessage, fileType, status };\n\t\t}\n\n\t\tif (addedFrom === \"schema\") {\n\t\t\treturn {\n\t\t\t\tfileType,\n\t\t\t\tstatus: EFileStatus.UPLOADED,\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tfileType,\n\t\t\tstatus: EFileStatus.UPLOAD_READY,\n\t\t};\n\t};\n\n\tconst validateFileType = (fileType: { mime: string; ext: string }) => {\n\t\tconst validFileType = fileTypeRule.fileType?.length ? fileTypeRule.fileType?.includes(fileType.ext) : true;\n\n\t\tif (!validFileType) {\n\t\t\treturn {\n\t\t\t\terrorMessage:\n\t\t\t\t\tfileTypeRule.errorMessage || ERROR_MESSAGES.UPLOAD().FILE_TYPE(fileTypeRule.fileType || []),\n\t\t\t\tfileType,\n\t\t\t\tstatus: EFileStatus.ERROR_FORMAT,\n\t\t\t};\n\t\t}\n\n\t\treturn {};\n\t};\n\n\tconst validateFileSize = (fileSizeInKb: number) => {\n\t\tif (maxFileSizeRule.maxSizeInKb > 0) {\n\t\t\tconst maxSizeInB = maxFileSizeRule.maxSizeInKb * 1024;\n\t\t\tif (fileSizeInKb > maxSizeInB) {\n\t\t\t\treturn {\n\t\t\t\t\terrorMessage:\n\t\t\t\t\t\tmaxFileSizeRule.errorMessage ||\n\t\t\t\t\t\tERROR_MESSAGES.UPLOAD().MAX_FILE_SIZE(maxFileSizeRule.maxSizeInKb),\n\t\t\t\t\tstatus: EFileStatus.ERROR_SIZE,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn {};\n\t};\n\n\t// =============================================================================\n\t// FILE STATUS HANDLERS\n\t// =============================================================================\n\tconst injectFile = async (fileToInject: IFile, index: number) => {\n\t\tsetFiles((prev) => {\n\t\t\tconst updatedFiles = [...prev];\n\t\t\tupdatedFiles[index] = {\n\t\t\t\t...prev[index],\n\t\t\t\tstatus: EFileStatus.INJECTING,\n\t\t\t};\n\t\t\treturn updatedFiles;\n\t\t});\n\n\t\tlet rawFile: File;\n\t\tif (fileToInject.dataURL) {\n\t\t\tconst blob = await FileHelper.dataUrlToBlob(fileToInject.dataURL);\n\t\t\trawFile = new File([blob], fileToInject.rawFile.name);\n\t\t} else if (fileToInject.fileUrl) {\n\t\t\tconst response: Blob = await new AxiosApiClient(\"\", undefined, undefined, false, {\n\t\t\t\tresponseType: \"blob\",\n\t\t\t}).get(fileToInject.fileUrl);\n\t\t\tconst fileType = await FileHelper.getType(new File([response], fileToInject.rawFile.name));\n\t\t\trawFile = new File([response], fileToInject.rawFile.name, { type: fileType.mime });\n\t\t\tfileToInject.dataURL = await FileHelper.fileToDataUrl(rawFile);\n\t\t}\n\n\t\t// rawFile may not be available because some use cases is not able to return dataURL / fileUrl due to security concerns\n\t\t// in such cases, we will rely on the uploadResponse for file info\n\t\tconst { errorMessage, fileType } = rawFile\n\t\t\t? await readFile({ ...fileToInject, rawFile })\n\t\t\t: validateFileType({\n\t\t\t\t\tmime: fileToInject.uploadResponse?.[\"mimeType\"],\n\t\t\t\t\text: fileToInject.uploadResponse?.[\"ext\"],\n\t\t\t });\n\n\t\tlet size = rawFile?.size || fileToInject.uploadResponse?.[\"fileSize\"] || 0;\n\t\tif (isNaN(size)) {\n\t\t\tsize = 0;\n\t\t}\n\t\tconst { errorMessage: filesizeErrorMessage } = validateFileSize(size);\n\n\t\tconst thumbnailImageDataUrl = rawFile ? await generateThumbnail(fileToInject, fileType?.mime) : undefined;\n\n\t\tsetFiles((prev) => {\n\t\t\tconst updatedFiles = [...prev];\n\t\t\tupdatedFiles[index] = {\n\t\t\t\t...fileToInject,\n\t\t\t\tfileItem: {\n\t\t\t\t\terrorMessage: errorMessage || filesizeErrorMessage,\n\t\t\t\t\tid: fileToInject.fileItem?.id || generateRandomId(),\n\t\t\t\t\tname: FileHelper.deduplicateFileName(\n\t\t\t\t\t\tfiles.map(({ fileItem }) => fileItem.name),\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\trawFile?.name || fileToInject.rawFile.name\n\t\t\t\t\t),\n\t\t\t\t\tprogress: 1,\n\t\t\t\t\tsize,\n\t\t\t\t\ttype: fileType?.mime || fileToInject.uploadResponse?.[\"mimeType\"],\n\t\t\t\t\tthumbnailImageDataUrl,\n\t\t\t\t},\n\t\t\t\trawFile,\n\t\t\t\tstatus: EFileStatus.UPLOADED,\n\t\t\t};\n\t\t\treturn updatedFiles;\n\t\t});\n\t};\n\n\tconst parseFile = async (fileToParse: IFile, index: number) => {\n\t\tconst compressedFile = await compressImageFile(fileToParse);\n\t\tconst dataURL = await FileHelper.fileToDataUrl(compressedFile.rawFile);\n\t\tconst { errorMessage, fileType, status } = await readFile({ dataURL, ...compressedFile });\n\n\t\tsetFiles((prev) => {\n\t\t\tconst updatedFiles = [...prev];\n\t\t\tupdatedFiles[index] = {\n\t\t\t\t...compressedFile,\n\t\t\t\tdataURL,\n\t\t\t\tfileItem: {\n\t\t\t\t\terrorMessage,\n\t\t\t\t\tid: generateRandomId(),\n\t\t\t\t\tname: FileHelper.deduplicateFileName(\n\t\t\t\t\t\tfiles.map(({ fileItem }) => fileItem?.name),\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tFileHelper.sanitizeFileName(compressedFile.rawFile.name)\n\t\t\t\t\t),\n\t\t\t\t\tsize: compressedFile.rawFile.size,\n\t\t\t\t\ttype: fileType.mime,\n\t\t\t\t\tprogress: 0,\n\t\t\t\t},\n\t\t\t\tstatus,\n\t\t\t};\n\t\t\treturn updatedFiles;\n\t\t});\n\t};\n\n\tconst uploadFile = async (fileToUpload: IFile, index: number) => {\n\t\tsetFiles((prev) => {\n\t\t\tconst updatedFiles = [...prev];\n\t\t\tupdatedFiles[index] = {\n\t\t\t\t...prev[index],\n\t\t\t\tstatus: EFileStatus.UPLOADING,\n\t\t\t};\n\t\t\treturn updatedFiles;\n\t\t});\n\n\t\tconst formData = new FormData();\n\t\tformData.append(\"sessionId\", upload?.sessionId || sessionId.current || \"\");\n\t\tformData.append(\"fileId\", fileToUpload.fileItem.id);\n\t\tformData.append(\"slot\", fileToUpload.slot.toString());\n\t\tif (upload.type === \"base64\") {\n\t\t\tformData.append(\"dataURL\", fileToUpload.dataURL);\n\t\t} else if (upload.type === \"multipart\") {\n\t\t\tformData.append(\"file\", fileToUpload.rawFile, fileToUpload.fileItem?.name);\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await new AxiosApiClient(\"\", undefined, undefined, true).post(upload.url, formData, {\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": upload.type === \"base64\" ? \"application/json\" : \"multipart/form-data\",\n\t\t\t\t\t...upload.headers,\n\t\t\t\t},\n\t\t\t\tonUploadProgress: (progressEvent) => {\n\t\t\t\t\tconst { loaded, total } = progressEvent;\n\t\t\t\t\tsetFiles((prev) => {\n\t\t\t\t\t\tif (!prev[index]) return prev;\n\t\t\t\t\t\tconst updatedFiles = [...prev];\n\t\t\t\t\t\tupdatedFiles[index] = {\n\t\t\t\t\t\t\t...prev[index],\n\t\t\t\t\t\t\tfileItem: {\n\t\t\t\t\t\t\t\t...prev[index].fileItem,\n\t\t\t\t\t\t\t\tprogress: loaded / total,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\treturn updatedFiles;\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst thumbnailImageDataUrl = await generateThumbnail(fileToUpload);\n\t\t\tsetFiles((prev) => {\n\t\t\t\tif (!prev[index]) return prev;\n\t\t\t\tconst updatedFiles = [...prev];\n\t\t\t\tupdatedFiles[index] = {\n\t\t\t\t\t...prev[index],\n\t\t\t\t\tfileItem: {\n\t\t\t\t\t\t...prev[index].fileItem,\n\t\t\t\t\t\tprogress: 1,\n\t\t\t\t\t\tthumbnailImageDataUrl,\n\t\t\t\t\t},\n\t\t\t\t\tfileUrl: response?.[\"data\"]?.[\"fileUrl\"],\n\t\t\t\t\tstatus: EFileStatus.UPLOADED,\n\t\t\t\t\tuploadResponse: response,\n\t\t\t\t};\n\t\t\t\treturn updatedFiles;\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tdispatchFieldEvent<TUploadErrorDetail>(\"upload-error\", id, {\n\t\t\t\tfileId: fileToUpload.fileItem.id,\n\t\t\t\terrorData: (err as AxiosError)?.response?.data,\n\t\t\t});\n\n\t\t\tthrow err;\n\t\t}\n\t};\n\n\tconst deleteFile = (index: number) => {\n\t\tsetFiles((prev) => prev.filter((_file, i) => i !== index));\n\t};\n\n\tconst compressImageFile = async (fileToCompress: IFile) => {\n\t\tif (maxFileSizeRule.maxSizeInKb > 0 && compressImages) {\n\t\t\tconst maxSizeInB = maxFileSizeRule.maxSizeInKb * 1024;\n\t\t\tif (fileToCompress.rawFile.size > maxSizeInB) {\n\t\t\t\tconst fileType = await FileHelper.getType(fileToCompress.rawFile);\n\t\t\t\tif (RESIZEABLE_IMAGE_TYPES.includes(fileType.mime)) {\n\t\t\t\t\tlet fileOrBlob = await ImageHelper.compressImage(fileToCompress.rawFile, {\n\t\t\t\t\t\tfileSize: maxFileSizeRule.maxSizeInKb,\n\t\t\t\t\t});\n\t\t\t\t\tif (fileOrBlob instanceof Blob) {\n\t\t\t\t\t\tfileOrBlob = FileHelper.blobToFile(fileOrBlob, {\n\t\t\t\t\t\t\tname: fileToCompress.rawFile.name,\n\t\t\t\t\t\t\tlastModified: fileToCompress.rawFile.lastModified,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...fileToCompress,\n\t\t\t\t\t\trawFile: fileOrBlob,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn fileToCompress;\n\t};\n\n\t// =============================================================================\n\t// RENDER FUNCTIONS\n\t// =============================================================================\n\treturn null;\n};\n\nexport default FileUploadManager;\n"],"names":["RESIZEABLE_IMAGE_TYPES","props","compressImages","fileTypeRule","hideThumbnail","id","maxFileSizeRule","upload","uploadRule","value","files","setFiles","setCurrentFileIds","useContext","FileUploadContext","previousValue","usePrevious","setValue","useFormContext","dispatchFieldEvent","useFieldEvent","sessionId","useRef","useEffect","current","generateRandomId","forEach","async","file","index","status","EFileStatus","INJECTED","injectFile","NONE","parseFile","UPLOAD_READY","uploadFile","TO_DELETE","deleteFile","err","handleGenericError","uploadedFiles","filter","UPLOADED","hasNotPrefilledFiles","addedFrom","length","gotDeleteFiles","shouldDirty","map","fileItem","dataURL","fileUrl","uploadResponse","type","fileId","fileName","name","shouldTouch","join","undefined","prev","updatedFiles","rawFile","errorMessage","ERROR_MESSAGES","UPLOAD","GENERIC","ERROR_GENERIC","generateThumbnail","fileType","includes","image","ImageHelper","dataUrlToImage","thumbnail","resampleImage","width","height","crop","FileHelper","fileToDataUrl","readFile","fileToRead","getType","fileTypeResult","validateFileType","fileSize","getFilesizeFromBase64","size","validateFileSize","ext","FILE_TYPE","ERROR_FORMAT","fileSizeInKb","maxSizeInKb","MAX_FILE_SIZE","ERROR_SIZE","fileToInject","INJECTING","blob","dataUrlToBlob","File","response","AxiosApiClient","responseType","get","mime","isNaN","filesizeErrorMessage","thumbnailImageDataUrl","deduplicateFileName","progress","fileToParse","compressedFile","compressImageFile","sanitizeFileName","fileToUpload","UPLOADING","formData","FormData","append","slot","toString","post","url","headers","onUploadProgress","progressEvent","loaded","total","errorData","data","_file","i","fileToCompress","maxSizeInB","fileOrBlob","compressImage","Blob","blobToFile","lastModified"],"mappings":"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"}