Skip to content

Commit

Permalink
Implement delete internal staff document
Browse files Browse the repository at this point in the history
  • Loading branch information
jadmsaadaot committed Jan 25, 2025
1 parent f4b498f commit 276d5f7
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 9 deletions.
38 changes: 36 additions & 2 deletions submit-api/src/submit_api/resources/staff/internal_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
)


@cors_preflight("OPTIONS, POST")
@API.route("/submission-items/<int:submission_item_id>", methods=["POST", "OPTIONS"])
@cors_preflight("OPTIONS, POST, DELETE")
@API.route("/submission-items/<int:submission_item_id>", methods=["POST", "OPTIONS", "DELETE"])
class InternalStaffDocuments(Resource):
"""Resource for managing projects."""

Expand All @@ -57,3 +57,37 @@ def post(submission_item_id):
created_document = (InternalStaffDocumentService
.create_internal_staff_document(submission_item_id, create_document_data))
return InternalStaffDocument().dump(created_document), HTTPStatus.CREATED

@staticmethod
@ApiHelper.swagger_decorators(API, endpoint_description="Delete an internal staff document")
@API.response(
code=HTTPStatus.OK, model=internal_document, description="Deleted Internal Staff Document"
)
@API.response(HTTPStatus.NOT_FOUND, "Not found")
@auth.has_one_of_roles([EpicSubmitRole.EAO_CREATE.value])
@cors.crossdomain(origin="*")
def delete(internal_staff_document_id):
"""Delete an internal staff document."""
deleted_document = (InternalStaffDocumentService
.delete_internal_staff_document(internal_staff_document_id))
return InternalStaffDocument().dump(deleted_document), HTTPStatus.OK


@cors_preflight("OPTIONS, DELETE")
@API.route("/<int:internal_staff_document_id>", methods=["OPTIONS", "DELETE"])
class InternalStaffDocuments(Resource):
"""Resource for managing projects."""

@staticmethod
@ApiHelper.swagger_decorators(API, endpoint_description="Delete an internal staff document")
@API.response(
code=HTTPStatus.OK, model=internal_document, description="Deleted Internal Staff Document"
)
@API.response(HTTPStatus.NOT_FOUND, "Not found")
@auth.has_one_of_roles([EpicSubmitRole.EAO_CREATE.value])
@cors.crossdomain(origin="*")
def delete(internal_staff_document_id):
"""Delete an internal staff document."""
deleted_document = (InternalStaffDocumentService
.delete_internal_staff_document(internal_staff_document_id))
return InternalStaffDocument().dump(deleted_document), HTTPStatus.OK
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,12 @@ def create_internal_staff_document(cls, submission_item_id, data):
)
internal_staff_document.save()
return internal_staff_document

@classmethod
def delete_internal_staff_document(cls, internal_staff_document_id):
"""Delete internal staff document."""
internal_staff_document = InternalStaffDocumentModel.find_by_id(internal_staff_document_id)
if not internal_staff_document:
raise ResourceNotFoundError("Internal staff document not found")
internal_staff_document.delete()
return internal_staff_document
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { deleteDocument, downloadObject } from "@/hooks/api/useObjectStorage";
import { notify } from "../Shared/Snackbar/snackbarStore";
import { Submission } from "@/models/Submission";
import { LoadingButton } from "../Shared/LoadingButton";
import { deleteSubmission } from "@/hooks/api/useSubmissions";
import { useDeleteSubmission } from "@/hooks/api/useSubmissions";

export const StyledHeadTableCell = styled(TableCell)<{ error?: boolean }>(
({ error }) => ({
Expand Down Expand Up @@ -99,6 +99,10 @@ export default function DocumentTableRow({
const [pendingGetObject, setPendingGetObject] = useState(false);
const [isRemovingDocument, setIsRemovingDocument] = useState(false);

const { mutateAsync: deleteSubmission } = useDeleteSubmission({
submissionItemId: documentItem.item_id,
});

const getObjectFromS3 = async () => {
try {
if (pendingGetObject) return;
Expand Down
1 change: 1 addition & 0 deletions submit-web/src/components/Submission/ItemsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export default function ItemsTable({ submissionPackage }: ItemsTableProps) {
<InternalDocumentsRows
internalStaffDocuments={internalStaffDocuments}
numColumns={5}
hideAction
/>
</When>
</TableBody>
Expand Down
65 changes: 63 additions & 2 deletions submit-web/src/components/SubmissionItem/InternalDocuments/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,38 @@ import { InternalStaffDocument } from "@/models/SubmissionItem";
import { getObjectFromS3 } from "@/components/Shared/Table/utils";
import { notify } from "@/components/Shared/Snackbar/snackbarStore";
import { SubmitTableCell } from "@/components/Shared/Table/common";
import { LoadingButton } from "@/components/Shared/LoadingButton";
import { BCDesignTokens } from "epic.theme";
import { useDeleteInternalStaffDocument } from "@/hooks/api/useInternalStaffDocuments";
import { useParams } from "@tanstack/react-router";
import { deleteDocument } from "@/hooks/api/useObjectStorage";
import { Unless } from "react-if";

type RowProps = {
internalStaffDocument: InternalStaffDocument;
numColumns: number;
setDocuments: React.Dispatch<React.SetStateAction<InternalStaffDocument[]>>;
hideAction?: boolean;
};

export default function Row({ internalStaffDocument, numColumns }: RowProps) {
export default function Row({
internalStaffDocument,
numColumns,
setDocuments,
hideAction = false,
}: RowProps) {
const { submissionPackageId, submissionId: submissionItemId } = useParams({
strict: false,
});
const [pendingGetObject, setPendingGetObject] = useState(false);
const [isRemovingDocument, setIsRemovingDocument] = useState(false);

const { mutateAsync: deleteInternalStaffSubmission } =
useDeleteInternalStaffDocument({
packageId: Number(submissionPackageId),
itemId: Number(submissionItemId),
});

const { name, url } = internalStaffDocument;

const downloadDocument = async () => {
Expand All @@ -25,6 +49,23 @@ export default function Row({ internalStaffDocument, numColumns }: RowProps) {
setPendingGetObject(false);
}
};

const onRemoveClick = async () => {
try {
setIsRemovingDocument(true);
await deleteDocument({ filepath: internalStaffDocument.url });
await deleteInternalStaffSubmission({
documentId: internalStaffDocument.id,
});
setDocuments((prev) =>
prev.filter((sub) => sub.id !== internalStaffDocument.id),
);
} catch (e) {
notify.error("Failed to remove document");
} finally {
setIsRemovingDocument(false);
}
};
return (
<TableRow>
<SubmitTableCell>
Expand All @@ -41,7 +82,27 @@ export default function Row({ internalStaffDocument, numColumns }: RowProps) {
<MuiLink onClick={downloadDocument}>{name}</MuiLink>
</Typography>
</SubmitTableCell>
<SubmitTableCell align="right" colSpan={numColumns - 1}></SubmitTableCell>
<SubmitTableCell align="right" colSpan={numColumns - 2}></SubmitTableCell>
<SubmitTableCell align="right">
<Unless condition={hideAction}>
<LoadingButton
onClick={onRemoveClick}
loading={isRemovingDocument}
variant="text"
sx={{
color: BCDesignTokens.typographyColorLink,
"&:hover": {
backgroundColor: "transparent",
},
"&:focus": {
outline: "none",
},
}}
>
Remove
</LoadingButton>
</Unless>
</SubmitTableCell>
</TableRow>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ import {
SubmitPrimaryRowTableCell,
SubmitTablePrimaryRow,
} from "@/components/Shared/Table/common";
import { useState } from "react";

type InternalDocumentsProps = Readonly<{
internalStaffDocuments: Array<InternalStaffDocument>;
numColumns?: number;
hideAction?: boolean;
}>;
export default function Rows({
internalStaffDocuments,
numColumns = 4,
hideAction = false,
}: InternalDocumentsProps) {
const [documents, setDocuments] = useState<Array<InternalStaffDocument>>(
internalStaffDocuments,
);
const { uploadObjects: pendingDocuments } = useObjectUploadStore();

const internalStaffDocumentsIds = new Set(
internalStaffDocuments.map((doc) => doc.id),
);
const internalStaffDocumentsIds = new Set(documents.map((doc) => doc.id));

const filteredPendingDocuments = pendingDocuments.filter(
(doc) => !internalStaffDocumentsIds.has(doc.submissionId ?? 0),
Expand Down Expand Up @@ -56,6 +60,8 @@ export default function Rows({
key={`doc-row-${document.id}`}
internalStaffDocument={document}
numColumns={5}
setDocuments={setDocuments}
hideAction={hideAction}
/>
))}
{filteredPendingDocuments.map((pendingDocument) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default function Table({
<TableBody>
<Rows
internalStaffDocuments={internalStaffDocuments}
numColumns={4}
numColumns={5}
/>
</TableBody>
</MuiTable>
Expand Down
40 changes: 40 additions & 0 deletions submit-web/src/hooks/api/useInternalStaffDocuments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,43 @@ export const useCreateInternalStaffDocument = ({
},
});
};

type DeleteInternalStaffDocumentProps = {
documentId: number;
};
export const deleteInternalStaffDocument = ({
documentId,
}: DeleteInternalStaffDocumentProps) => {
return submitRequest<void>({
url: `/staff/internal-staff-documents/${documentId}`,
method: "delete",
});
};

type UseDeleteInternalStaffDocumentProps = {
itemId: number;
packageId: number;
options?: Options;
};
export const useDeleteInternalStaffDocument = ({
itemId,
packageId,
options,
}: UseDeleteInternalStaffDocumentProps) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: deleteInternalStaffDocument,
...options,
onSuccess: () => {
if (options?.onSuccess) {
options.onSuccess();
}
queryClient.invalidateQueries({
queryKey: [QUERY_KEY.SUBMISSION_ITEM, itemId],
});
queryClient.invalidateQueries({
queryKey: [QUERY_KEY.SUBMISSION_PACKAGE, packageId],
});
},
});
};
23 changes: 23 additions & 0 deletions submit-web/src/hooks/api/useSubmissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,26 @@ export const deleteSubmission = (submissionId: number) => {
method: "delete",
});
};

type UseDeleteSubmissionParams = {
submissionItemId: number;
} & Options;
export const useDeleteSubmission = ({
submissionItemId,
...options
}: UseDeleteSubmissionParams) => {
const { onSuccess: _onSuccess, ...restOptions } = options;
const queryClient = useQueryClient();
return useMutation({
mutationFn: deleteSubmission,
onSuccess: (data) => {
if (_onSuccess) {
_onSuccess(data);
}
queryClient.invalidateQueries({
queryKey: [QUERY_KEY.SUBMISSION_ITEM, submissionItemId],
});
},
...restOptions,
});
};

0 comments on commit 276d5f7

Please sign in to comment.