From eb97307122e961aa42b4c191fe08ca76a4bab4b4 Mon Sep 17 00:00:00 2001 From: Shivank Kacker Date: Fri, 31 May 2024 00:31:46 +0530 Subject: [PATCH 1/9] Restructured Consent Records --- src/CAREUI/misc/PaginatedList.tsx | 6 + src/Components/Facility/ConsultationForm.tsx | 4 +- src/Components/Facility/models.tsx | 15 +- .../Patient/PatientConsentRecordBlock.tsx | 193 +++++------------- .../Patient/PatientConsentRecords.tsx | 180 +++++++++------- src/Components/Patient/PatientInfoCard.tsx | 29 ++- src/Components/Patient/models.tsx | 1 + src/Redux/api.tsx | 25 +++ 8 files changed, 221 insertions(+), 232 deletions(-) diff --git a/src/CAREUI/misc/PaginatedList.tsx b/src/CAREUI/misc/PaginatedList.tsx index ec270bf8134..39c0a80df1c 100644 --- a/src/CAREUI/misc/PaginatedList.tsx +++ b/src/CAREUI/misc/PaginatedList.tsx @@ -36,6 +36,7 @@ interface Props extends QueryOptions> { queryCB?: ( query: ReturnType>>, ) => void; + refreshTrigger?: any; children: ( ctx: PaginatedListContext, query: ReturnType>>, @@ -47,6 +48,7 @@ export default function PaginatedList({ route, perPage = DEFAULT_PER_PAGE_LIMIT, queryCB, + refreshTrigger, ...queryOptions }: Props) { const [currentPage, setPage] = useState(1); @@ -67,6 +69,10 @@ export default function PaginatedList({ } }, [query]); + useEffect(() => { + query.refetch(); + }, [refreshTrigger]); + return ( void; archiveFile: ( file: FileUploadModel, file_associating_id: string, skipPrompt?: { reason: string }, ) => void; - onDelete: (consentRecord: ConsentRecord) => void; - refreshTrigger: any; + onDelete: (consentRecord: PatientConsentModel) => void; showArchive: boolean; - onFilesFound: () => void; + files?: FileUploadModel[]; }) { - const { - consentRecord, - previewFile, - archiveFile, - refreshTrigger, - showArchive, - } = props; + const { consentRecord, previewFile, archiveFile, files, showArchive } = props; const authUser = useAuthUser(); - const filesQuery = useQuery(routes.viewUpload, { - query: { - file_type: "CONSENT_RECORD", - associating_id: consentRecord.id, - is_archived: false, - limit: 100, - offset: 0, - }, - onResponse: (response) => { - /* - if (consentRecord.deleted === true && response.data?.results) { - const unarchivedFiles = response.data.results; - console.log("checking for unarchived files on this deleted consent record") - for (const file of unarchivedFiles) { - console.log("archiving file", file) - archiveFile(file, consentRecord.id, { - reason: "Consent Record Archived", - }); - } - } - */ - - if ((response.data?.results?.length || 0) > 0) { - props.onFilesFound(); - } - }, - }); - - const archivedFilesQuery = useQuery(routes.viewUpload, { - query: { - file_type: "CONSENT_RECORD", - associating_id: consentRecord.id, - is_archived: true, - limit: 100, - offset: 0, - }, - prefetch: showArchive, - onResponse: (response) => { - if ((response.data?.results?.length || 0) > 0) { - props.onFilesFound(); - } - }, - }); - const consent = CONSENT_TYPE_CHOICES.find((c) => c.id === consentRecord.type); const consentPCS = CONSENT_PATIENT_CODE_STATUS_CHOICES.find( (c) => c.id === consentRecord.patient_code_status, ); - const data = showArchive - ? [ - ...(archivedFilesQuery.data?.results || []), - ...(consentRecord.deleted ? filesQuery.data?.results || [] : []), - ] - : filesQuery.data?.results; - - const loading = archivedFilesQuery.loading || filesQuery.loading; - - useEffect(() => { - if (!showArchive) { - filesQuery.refetch(); - } else { - archivedFilesQuery.refetch(); - } - }, [showArchive, refreshTrigger]); - return (

{consent?.text} {consentPCS?.text && `(${consentPCS.text})`}

- {consentRecord.deleted && ( -
-
- - Archived -
-
- )}
- {/* - {!consentRecord.deleted && !showArchive && ( - - )} - */}
- {loading ? ( -
- ) : ( - data?.map((file: FileUploadModel, i: number) => ( -
-
-
- + {files?.map((file: FileUploadModel, i: number) => ( +
+
+
+ +
+
+
+ {file.name} + {file.extension} {file.is_archived && "(Archived)"}
-
-
- {file.name} - {file.extension} {file.is_archived && "(Archived)"} -
-
- {dayjs(file.created_date).format("DD MMM YYYY, hh:mm A")} -
+
+ {dayjs(file.created_date).format("DD MMM YYYY, hh:mm A")} by{" "} + {file.uploaded_by?.username}
-
- {!file.is_archived && ( - previewFile(file, consentRecord.id)} - className="" - > - - View - - )} - {(file.is_archived || - file?.uploaded_by?.username === authUser.username || - authUser.user_type === "DistrictAdmin" || - authUser.user_type === "StateAdmin") && ( - archiveFile(file, consentRecord.id)} - className="" - > - - {file.is_archived ? "More Info" : "Archive"} - - )} -
- )) - )} +
+ {!file.is_archived && ( + previewFile(file, consentRecord.id)} + className="" + > + + View + + )} + {(file.is_archived || + file?.uploaded_by?.username === authUser.username || + authUser.user_type === "DistrictAdmin" || + authUser.user_type === "StateAdmin") && ( + archiveFile(file, consentRecord.id)} + className="" + > + + {file.is_archived ? "More Info" : "Archive"} + + )} +
+
+ ))}
); } diff --git a/src/Components/Patient/PatientConsentRecords.tsx b/src/Components/Patient/PatientConsentRecords.tsx index ca26b270d80..5edd9bbe5f8 100644 --- a/src/Components/Patient/PatientConsentRecords.tsx +++ b/src/Components/Patient/PatientConsentRecords.tsx @@ -6,7 +6,6 @@ import { import routes from "../../Redux/api"; import useQuery from "../../Utils/request/useQuery"; import Page from "../Common/components/Page"; -import { ConsentRecord } from "../Facility/models"; import request from "../../Utils/request/request"; import ConfirmDialog from "../Common/ConfirmDialog"; import { SelectFormField } from "../Form/FormFields/SelectFormField"; @@ -18,6 +17,13 @@ import useFileUpload from "../../Utils/useFileUpload"; import PatientConsentRecordBlockGroup from "./PatientConsentRecordBlock"; import SwitchTabs from "../Common/components/SwitchTabs"; import useFileManager from "../../Utils/useFileManager"; +import PaginatedList from "../../CAREUI/misc/PaginatedList"; +import { PatientConsentModel } from "../Facility/models"; + +const useRefresh: () => [number, () => void] = () => { + const [trigger, setTrigger] = useState(0); + return [trigger, () => setTrigger((prev) => prev + 1)]; +}; export default function PatientConsentRecords(props: { facilityId: string; @@ -26,7 +32,6 @@ export default function PatientConsentRecords(props: { }) { const { facilityId, patientId, consultationId } = props; const [showArchived, setShowArchived] = useState(false); - const [filesFound, setFilesFound] = useState(false); const [showPCSChangeModal, setShowPCSChangeModal] = useState( null, ); @@ -43,35 +48,57 @@ export default function PatientConsentRecords(props: { type: "CONSENT_RECORD", onArchive: async () => { refetch(); + refetchFiles(); + refetchArchivedFiles(); }, }); + const [refreshTrigger, refetch] = useRefresh(); + const { data: patient } = useQuery(routes.getPatient, { pathParams: { id: patientId, }, }); - const { - data: consultation, - refetch, - loading, - } = useQuery(routes.getConsultation, { - pathParams: { id: consultationId! }, - onResponse: (data) => { - if (data.data && data.data.consent_records) { - setConsentRecords(data.data.consent_records); - } - }, - }); const [showDeleteConsent, setShowDeleteConsent] = useState( null, ); - const [consentRecords, setConsentRecords] = useState( - null, + const [consentRecords, setConsentRecords] = useState< + PatientConsentModel[] | null + >(null); + + const { data: unarchivedFiles, refetch: refetchFiles } = useQuery( + routes.viewUpload, + { + query: { + file_type: "CONSENT_RECORD", + associating_id: consentRecords?.map((cr) => cr.id).join(","), + limit: 1000, + offset: 0, + is_archived: false, + }, + prefetch: (consentRecords?.length || 0) > 0 && showArchived, + }, + ); + + const { data: archivedFiles, refetch: refetchArchivedFiles } = useQuery( + routes.viewUpload, + { + query: { + file_type: "CONSENT_RECORD", + associating_id: consentRecords?.map((cr) => cr.id).join(","), + limit: 1000, + offset: 0, + is_archived: true, + }, + prefetch: (consentRecords?.length || 0) > 0 && !showArchived, + }, ); + const files = showArchived ? archivedFiles : unarchivedFiles; + const handleDeleteConsent = async () => { const consent_id = showDeleteConsent; if (!consent_id || !consultationId || !consentRecords) return; @@ -91,55 +118,36 @@ export default function PatientConsentRecords(props: { }; }; - const handleUpload = async (diffPCS?: ConsentRecord) => { - if (newConsent.type === 0) return; - const consentTypeExists = consentRecords?.find( - (record) => record.type === newConsent.type && record.deleted !== true, + const handleUpload = async (diffPCS?: PatientConsentModel) => { + const consentExists = consentRecords?.find( + (record) => record.type === newConsent.type && !record.archived, ); - if (consentTypeExists && !diffPCS) { - await fileUpload.handleFileUpload(consentTypeExists.id); - } else { - const randomId = "consent-" + new Date().getTime().toString(); - const newRecords = [ - ...(consentRecords?.map((r) => - r.id === diffPCS?.id ? { ...r, deleted: true } : r, - ) || []), - { - id: randomId, - type: newConsent.type, + let consentId = consentExists?.id; + if (!consentExists || diffPCS) { + consentId = undefined; + const res = await request(routes.createConsent, { + pathParams: { consultationId: consultationId }, + body: { + ...newConsent, patient_code_status: newConsent.type === 2 ? newConsent.patient_code_status : undefined, }, - ]; - await request(routes.partialUpdateConsultation, { - pathParams: { id: consultationId }, - body: { consent_records: newRecords }, }); - await fileUpload.handleFileUpload(randomId); - setConsentRecords(newRecords); + if (res.data) { + consentId = res.data.id; + } } - + consentId && (await fileUpload.handleFileUpload(consentId)); refetch(); }; useEffect(() => { - const timeout = setTimeout(async () => { - if (consentRecords) { - await request(routes.partialUpdateConsultation, { - pathParams: { id: consultationId }, - body: { consent_records: consentRecords }, - }); - } - }, 1000); - return () => clearTimeout(timeout); + if (consentRecords && consentRecords.length > 0) { + refetchFiles(); + refetchArchivedFiles(); + } }, [consentRecords]); - const tabConsents = consentRecords?.filter((c) => showArchived || !c.deleted); - - useEffect(() => { - setFilesFound(false); - }, [showArchived]); - return ( record.type === 2 && - !record.deleted && + !record.archived && record.patient_code_status !== showPCSChangeModal, ), ); @@ -189,7 +197,7 @@ export default function PatientConsentRecords(props: { }} action="Change Patient Code Status" variant="danger" - description={`Consent records exist with the "${CONSENT_PATIENT_CODE_STATUS_CHOICES.find((c) => consentRecords?.find((c) => c.type === 2 && !c.deleted)?.patient_code_status === c.id)?.text}" patient code status. Adding a new record for a different type will archive the existing records. Are you sure you want to proceed?`} + description={`Consent records exist with the "${CONSENT_PATIENT_CODE_STATUS_CHOICES.find((c) => consentRecords?.find((c) => c.type === 2 && !c.archived)?.patient_code_status === c.id)?.text}" patient code status. Adding a new record for a different type will archive the existing records. Are you sure you want to proceed?`} title="Archive Previous Records" className="w-auto" /> @@ -246,7 +254,7 @@ export default function PatientConsentRecords(props: { newConsent.type === 2 && record.patient_code_status !== newConsent.patient_code_status && - record.deleted !== true, + record.archived !== true, ); if (diffPCS) { setShowPCSChangeModal(newConsent.patient_code_status); @@ -283,28 +291,48 @@ export default function PatientConsentRecords(props: {
-
- {loading ? ( + {consentRecords?.filter( + (r) => + files?.results.filter((f) => f.associating_id === r.id).length, + ).length === 0 ? ( +
+ No consent records found +
+ ) : ( + (!unarchivedFiles || !archivedFiles) && + !consentRecords && (
- ) : tabConsents?.length === 0 || !filesFound ? ( -
- No records found + ) + )} + { + if (query.data) { + setConsentRecords(query.data.results); + } + }} + > + {(c) => ( +
+ {c.data?.results.map((record, index) => ( + setShowDeleteConsent(record.id)} + showArchive={showArchived} + files={files?.results.filter( + (f) => f.associating_id === record.id, + )} + /> + ))}
- ) : null} - {!loading && - tabConsents?.map((record, index) => ( - setShowDeleteConsent(record.id)} - refreshTrigger={consultation} - showArchive={showArchived} - onFilesFound={() => setFilesFound(true)} - /> - ))} -
+ )} +
diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index 247d9312d6e..8d9aa6acdbc 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -140,6 +140,24 @@ export default function PatientInfoCard(props: { prefetch: !!consultation?.treating_physician_object?.username, }); + const { data: consentRecords } = useQuery(routes.listConsents, { + pathParams: { + consultationId: consultation?.id ?? "", + }, + prefetch: !!consultation?.id, + }); + + const { data: consentFiles } = useQuery(routes.viewUpload, { + query: { + file_type: "CONSENT_RECORD", + associating_id: consentRecords?.results.map((cr) => cr.id).join(","), + limit: 1000, + offset: 0, + is_archived: false, + }, + prefetch: (consentRecords?.results.length || 0) > 0, + }); + return ( <>
)} - {( - consultation?.consent_records?.filter((c) => !c.deleted) || - [] - ).length < 1 && ( + {consentRecords?.results.some((c) => + consentFiles?.results.filter( + (f) => f.associating_id === c.id, + ), + ) && (
-
+
Consent Records Missing diff --git a/src/Components/Patient/models.tsx b/src/Components/Patient/models.tsx index f64d71146c4..9664d0f462b 100644 --- a/src/Components/Patient/models.tsx +++ b/src/Components/Patient/models.tsx @@ -354,6 +354,7 @@ export interface CreateFileResponse { export interface FileUploadModel { id?: string; name?: string; + associating_id?: string; created_date?: string; upload_completed?: boolean; uploaded_by?: PerformedByModel; diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx index f4a9732a40c..5f8ed3be21d 100644 --- a/src/Redux/api.tsx +++ b/src/Redux/api.tsx @@ -65,6 +65,7 @@ import { LocalBodyModel, LocationModel, MinimumQuantityItemResponse, + PatientConsentModel, PatientNotesEditModel, PatientNotesModel, PatientStatsModel, @@ -1000,6 +1001,30 @@ const routes = { TRes: Type>(), }, + // Consents + listConsents: { + path: "/api/v1/consultation/{consultationId}/consents/", + method: "GET", + TRes: Type>(), + }, + getConsent: { + path: "/api/v1/consultation/{consultationId}/consents/{id}/", + method: "GET", + TRes: Type(), + }, + createConsent: { + path: "/api/v1/consultation/{consultationId}/consents/", + method: "POST", + TRes: Type(), + TBody: Type>(), + }, + partialUpdateConsent: { + path: "/api/v1/consultation/{consultationId}/consents/{id}/", + method: "PATCH", + TRes: Type(), + TBody: Type>(), + }, + //Profile checkUsername: { path: "/api/v1/users/{username}/check_availability/", From 4662ae278c21a425cf2144fdfd9ebc7a10f4025f Mon Sep 17 00:00:00 2001 From: Shivank Kacker Date: Fri, 31 May 2024 02:49:32 +0530 Subject: [PATCH 2/9] fixed label --- src/Components/Patient/PatientInfoCard.tsx | 60 ++++++++++++---------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index 8d9aa6acdbc..aff99e0f68e 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -140,23 +140,29 @@ export default function PatientInfoCard(props: { prefetch: !!consultation?.treating_physician_object?.username, }); - const { data: consentRecords } = useQuery(routes.listConsents, { - pathParams: { - consultationId: consultation?.id ?? "", + const { data: consentRecords, loading: consentRecordsLoading } = useQuery( + routes.listConsents, + { + pathParams: { + consultationId: consultation?.id ?? "", + }, + prefetch: !!consultation?.id, }, - prefetch: !!consultation?.id, - }); + ); - const { data: consentFiles } = useQuery(routes.viewUpload, { - query: { - file_type: "CONSENT_RECORD", - associating_id: consentRecords?.results.map((cr) => cr.id).join(","), - limit: 1000, - offset: 0, - is_archived: false, + const { data: consentFiles, loading: consentFilesLoading } = useQuery( + routes.viewUpload, + { + query: { + file_type: "CONSENT_RECORD", + associating_id: consentRecords?.results.map((cr) => cr.id).join(","), + limit: 1000, + offset: 0, + is_archived: false, + }, + prefetch: (consentRecords?.results.length || 0) > 0, }, - prefetch: (consentRecords?.results.length || 0) > 0, - }); + ); return ( <> @@ -372,19 +378,21 @@ export default function PatientInfoCard(props: {
)} - {consentRecords?.results.some((c) => - consentFiles?.results.filter( - (f) => f.associating_id === c.id, - ), - ) && ( -
-
- - Consent Records Missing - + {!consentFilesLoading && + !consentRecordsLoading && + !consentRecords?.results.some((c) => + consentFiles?.results.filter( + (f) => f.associating_id === c.id, + ), + ) && ( +
+
+ + Consent Records Missing + +
-
- )} + )} {consultation?.suggestion === "DC" && (
From bcc31fd06dbce8fbc0cd975de47a90797240b220 Mon Sep 17 00:00:00 2001 From: Shivank Kacker Date: Sat, 1 Jun 2024 20:50:08 +0530 Subject: [PATCH 3/9] made required changes --- .../Patient/PatientConsentRecordBlock.tsx | 34 +++- .../Patient/PatientConsentRecords.tsx | 8 + src/Components/Patient/PatientInfoCard.tsx | 7 +- src/Utils/useFileManager.tsx | 171 +++++++++++++++--- src/Utils/useFileUpload.tsx | 32 ++-- 5 files changed, 204 insertions(+), 48 deletions(-) diff --git a/src/Components/Patient/PatientConsentRecordBlock.tsx b/src/Components/Patient/PatientConsentRecordBlock.tsx index 80683833d96..440ed548ca5 100644 --- a/src/Components/Patient/PatientConsentRecordBlock.tsx +++ b/src/Components/Patient/PatientConsentRecordBlock.tsx @@ -17,11 +17,19 @@ export default function PatientConsentRecordBlockGroup(props: { file_associating_id: string, skipPrompt?: { reason: string }, ) => void; + editFile: (file: FileUploadModel) => void; onDelete: (consentRecord: PatientConsentModel) => void; showArchive: boolean; files?: FileUploadModel[]; }) { - const { consentRecord, previewFile, archiveFile, files, showArchive } = props; + const { + consentRecord, + previewFile, + archiveFile, + editFile, + files, + showArchive, + } = props; const authUser = useAuthUser(); @@ -56,12 +64,17 @@ export default function PatientConsentRecordBlockGroup(props: { {file.extension} {file.is_archived && "(Archived)"}
- {dayjs(file.created_date).format("DD MMM YYYY, hh:mm A")} by{" "} - {file.uploaded_by?.username} + {dayjs( + file.is_archived ? file.archived_datetime : file.created_date, + ).format("DD MMM YYYY, hh:mm A")}{" "} + by{" "} + {file.is_archived + ? file.archived_by?.username + : file.uploaded_by?.username}
-
+
{!file.is_archived && ( previewFile(file, consentRecord.id)} @@ -71,6 +84,19 @@ export default function PatientConsentRecordBlockGroup(props: { View )} + {!file.is_archived && + (file?.uploaded_by?.username === authUser.username || + authUser.user_type === "DistrictAdmin" || + authUser.user_type === "StateAdmin") && ( + editFile(file)} + className="" + > + + Rename + + )} {(file.is_archived || file?.uploaded_by?.username === authUser.username || authUser.user_type === "DistrictAdmin" || diff --git a/src/Components/Patient/PatientConsentRecords.tsx b/src/Components/Patient/PatientConsentRecords.tsx index 5edd9bbe5f8..c76fed3ed22 100644 --- a/src/Components/Patient/PatientConsentRecords.tsx +++ b/src/Components/Patient/PatientConsentRecords.tsx @@ -42,6 +42,7 @@ export default function PatientConsentRecords(props: { const fileUpload = useFileUpload({ type: "CONSENT_RECORD", + allowedExtensions: ["pdf", "jpg", "jpeg", "png"], }); const fileManager = useFileManager({ @@ -51,6 +52,11 @@ export default function PatientConsentRecords(props: { refetchFiles(); refetchArchivedFiles(); }, + onEdit: async () => { + refetch(); + refetchFiles(); + refetchArchivedFiles(); + }, }); const [refreshTrigger, refetch] = useRefresh(); @@ -289,6 +295,7 @@ export default function PatientConsentRecords(props: { )}
+
{fileUpload.error}
{consentRecords?.filter( @@ -323,6 +330,7 @@ export default function PatientConsentRecords(props: { consentRecord={record} previewFile={fileManager.viewFile} archiveFile={fileManager.archiveFile} + editFile={fileManager.editFile} onDelete={(record) => setShowDeleteConsent(record.id)} showArchive={showArchived} files={files?.results.filter( diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index aff99e0f68e..f4dffd30807 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -380,11 +380,8 @@ export default function PatientInfoCard(props: { )} {!consentFilesLoading && !consentRecordsLoading && - !consentRecords?.results.some((c) => - consentFiles?.results.filter( - (f) => f.associating_id === c.id, - ), - ) && ( + !consentFiles?.results.filter((c) => !c.is_archived) + .length && (
diff --git a/src/Utils/useFileManager.tsx b/src/Utils/useFileManager.tsx index 133b4d2533d..789cc169334 100644 --- a/src/Utils/useFileManager.tsx +++ b/src/Utils/useFileManager.tsx @@ -10,10 +10,12 @@ import TextAreaFormField from "../Components/Form/FormFields/TextAreaFormField"; import { Cancel, Submit } from "../Components/Common/components/ButtonV2"; import { formatDateTime } from "./utils"; import * as Notification from "./Notifications.js"; +import TextFormField from "../Components/Form/FormFields/TextFormField"; export interface FileManagerOptions { type: string; onArchive?: () => void; + onEdit?: () => void; } export interface FileManagerResult { @@ -23,13 +25,14 @@ export interface FileManagerResult { associating_id: string, skipPrompt?: { reason: string }, ) => void; + editFile: (file: FileUploadModel) => void; Dialogues: React.ReactNode; } export default function useFileManager( options: FileManagerOptions, ): FileManagerResult { - const { type: fileType, onArchive } = options; + const { type: fileType, onArchive, onEdit } = options; const [file_state, setFileState] = useState({ open: false, @@ -49,6 +52,10 @@ export default function useFileManager( const [archiveReason, setArchiveReason] = useState(""); const [archiveReasonError, setArchiveReasonError] = useState(""); const [archiving, setArchiving] = useState(false); + const [editing, setEditing] = useState(false); + const [editDialogueOpen, setEditDialogueOpen] = + useState(null); + const [editError, setEditError] = useState(""); const getExtension = (url: string) => { const div1 = url.split("?")[0].split("."); @@ -155,6 +162,43 @@ export default function useFileManager( }); }; + const validateEditFileName = (name: string) => { + if (name.trim() === "") { + setEditError("Please enter a name!"); + return false; + } else { + setEditError(""); + return true; + } + }; + + const partialupdateFileName = async (file: FileUploadModel) => { + if (!validateEditFileName(file.name || "")) { + setEditing(false); + return; + } + + const { res } = await request(routes.editUpload, { + body: { name: file.name }, + pathParams: { + id: file.id || "", + fileType, + associatingId: file.associating_id || "", + }, + }); + + if (res?.ok) { + Notification.Success({ msg: "File name changed successfully" }); + setEditDialogueOpen(null); + onEdit && onEdit(); + } + setEditing(false); + }; + + const editFile = (file: FileUploadModel) => { + setEditDialogueOpen(file); + }; + const Dialogues = ( <> + {archiveDialogueOpen?.name} (Archived) + + } + fixedWidth={false} + className="md:w-2/4" + onClose={() => setArchiveDialogueOpen(null)} + > +
+ + This file has been archived and cannot be unarchived. +
+
+ {[ + { + label: "File Name", + content: archiveDialogueOpen?.name, + icon: "l-file", + }, + { + label: "Uploaded By", + content: archiveDialogueOpen?.uploaded_by?.username, + icon: "l-user", + }, + { + label: "Uploaded On", + content: formatDateTime(archiveDialogueOpen?.created_date), + icon: "l-clock", + }, + { + label: "Archive Reason", + content: archiveDialogueOpen?.archive_reason, + icon: "l-archive", + }, + { + label: "Archived By", + content: archiveDialogueOpen?.archived_by?.username, + icon: "l-user", + }, + { + label: "Archived On", + content: formatDateTime(archiveDialogueOpen?.archived_datetime), + icon: "l-clock", + }, + ].map((item, index) => ( +
+
+ +
+
+
+ {item.label} +
+
{item.content}
+
+
+ ))} +
+
+ setArchiveDialogueOpen(null)} /> +
+ + -
+
-
-

File Details

- This file is archived. Once a file is archived it cannot be - unarchived. +
+

Rename File

} - onClose={() => setArchiveDialogueOpen(null)} + onClose={() => setEditDialogueOpen(null)} > -
+
{ + event.preventDefault(); + setEditing(true); + if (editDialogueOpen) partialupdateFileName(editDialogueOpen); + }} + className="flex w-full flex-col" + >
-
- {archiveDialogueOpen?.name} file is - archived. -
-
- Reason: {archiveDialogueOpen?.archive_reason} -
-
- Archived by: {archiveDialogueOpen?.archived_by?.username} -
-
- Time of Archive: - {formatDateTime(archiveDialogueOpen?.archived_datetime)} -
+ { + setEditDialogueOpen({ ...editDialogueOpen, name: e.value }); + }} + error={editError} + />
- setArchiveDialogueOpen(null)} /> + setEditDialogueOpen(null)} /> +
-
+ ); @@ -269,6 +389,7 @@ export default function useFileManager( return { viewFile, archiveFile, + editFile, Dialogues, }; } diff --git a/src/Utils/useFileUpload.tsx b/src/Utils/useFileUpload.tsx index e28e8c9b1b5..55d44ffe55e 100644 --- a/src/Utils/useFileUpload.tsx +++ b/src/Utils/useFileUpload.tsx @@ -21,14 +21,8 @@ export type FileUploadOptions = { type: string; category?: FileCategory; onUpload?: (file: FileUploadModel) => void; -} & ( - | { - allowAllExtensions?: boolean; - } - | { - allowedExtensions?: string[]; - } -); + allowedExtensions?: string[]; +}; export type FileUploadButtonProps = { icon?: IconName; @@ -71,7 +65,12 @@ const ExtImage: string[] = [ export default function useFileUpload( options: FileUploadOptions, ): FileUploadReturn { - const { type, onUpload, category = "UNSPECIFIED" } = options; + const { + type, + onUpload, + category = "UNSPECIFIED", + allowedExtensions, + } = options; const [uploadFileName, setUploadFileName] = useState(""); const [error, setError] = useState(null); @@ -146,6 +145,13 @@ export default function useFileUpload( setError("Maximum size of files is 100 MB"); return false; } + const extension = f.name.split(".").pop(); + if (allowedExtensions && !allowedExtensions.includes(extension || "")) { + setError( + `Invalid file type ".${extension}" Allowed types: ${allowedExtensions.join(", ")}`, + ); + return false; + } return true; }; const markUploadComplete = ( @@ -414,11 +420,9 @@ export default function useFileUpload( onChange={onFileChange} type="file" accept={ - "allowAllExtensions" in options - ? "image/*,video/*,audio/*,text/plain,text/csv,application/rtf,application/msword,application/vnd.oasis.opendocument.text,application/pdf,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet,application/pdf" - : "allowedExtensions" in options - ? options.allowedExtensions?.join(",") - : "" + "allowExtensions" in options + ? allowedExtensions?.join(",") + : "image/*,video/*,audio/*,text/plain,text/csv,application/rtf,application/msword,application/vnd.oasis.opendocument.text,application/pdf,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet,application/pdf" } hidden /> From 2e45ca9d24062af41ab890812f2f2f2e1ba78e19 Mon Sep 17 00:00:00 2001 From: Shivank Kacker Date: Sat, 1 Jun 2024 23:35:08 +0530 Subject: [PATCH 4/9] QOL updates --- src/Components/Common/FilePreviewDialog.tsx | 23 ++++++++++++++++++++- src/Utils/useFileManager.tsx | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Components/Common/FilePreviewDialog.tsx b/src/Components/Common/FilePreviewDialog.tsx index 9bf9780c7a3..b4443d330ea 100644 --- a/src/Components/Common/FilePreviewDialog.tsx +++ b/src/Components/Common/FilePreviewDialog.tsx @@ -32,6 +32,19 @@ type FilePreviewProps = { fixedWidth?: boolean; }; +const previewExtensions = [ + ".html", + ".htm", + ".pdf", + ".mp4", + ".webm", + ".jpg", + ".jpeg", + ".png", + ".gif", + ".webp", +]; + const FilePreviewDialog = (props: FilePreviewProps) => { const { show, onClose, file_state, setFileState, downloadURL, fileUrl } = props; @@ -130,13 +143,21 @@ const FilePreviewDialog = (props: FilePreviewProps) => { }} pageNumber={page} /> - ) : ( + ) : previewExtensions.includes(file_state.extension) ? (