[WEB-1899] fix: issue attachment delete modal and code refactor (#5085)

* chore: issue attachment modal state updated in store

* fix: issue attachment delete modal fix and code refactor
This commit is contained in:
Anmol Singh Bhatia 2024-07-09 15:14:23 +05:30 committed by GitHub
parent 6b12c78cea
commit 676ec7e396
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 59 additions and 54 deletions

View file

@ -52,7 +52,7 @@ export const IssueAttachmentsDetail: FC<TIssueAttachmentsDetail> = observer((pro
isOpen={isDeleteIssueAttachmentModalOpen}
onClose={() => setIsDeleteIssueAttachmentModalOpen(false)}
handleAttachmentOperations={handleAttachmentOperations}
data={attachment}
attachmentId={attachmentId}
/>
)}
<div className="flex h-[60px] items-center justify-between gap-1 rounded-md border-[2px] border-custom-border-200 bg-custom-background-100 px-4 py-2 text-sm">

View file

@ -9,6 +9,7 @@ import { useInstance, useIssueDetail } from "@/hooks/store";
// components
import { IssueAttachmentsListItem } from "./attachment-list-item";
// types
import { IssueAttachmentDeleteModal } from "./delete-attachment-modal";
import { TAttachmentOperations } from "./root";
type TAttachmentOperationsRemoveModal = Exclude<TAttachmentOperations, "create">;
@ -28,6 +29,8 @@ export const IssueAttachmentItemList: FC<TIssueAttachmentItemList> = observer((p
const { config } = useInstance();
const {
attachment: { getAttachmentsByIssueId },
attachmentDeleteModalId,
toggleDeleteAttachmentModal,
} = useIssueDetail();
// derived values
const issueAttachments = getAttachmentsByIssueId(issueId);
@ -65,29 +68,34 @@ export const IssueAttachmentItemList: FC<TIssueAttachmentItemList> = observer((p
if (!issueAttachments) return <></>;
return (
<div
{...getRootProps()}
className={`relative flex flex-col ${isDragActive && issueAttachments.length < 3 ? "min-h-[200px]" : ""} ${disabled ? "cursor-not-allowed" : "cursor-pointer"}`}
>
<input {...getInputProps()} />
{isDragActive && (
<div className="absolute flex items-center justify-center left-0 top-0 h-full w-full bg-custom-background-90/75 z-30 ">
<div className="flex items-center justify-center p-1 rounded-md bg-custom-background-100">
<div className="flex flex-col justify-center items-center px-5 py-6 rounded-md border border-dashed border-custom-border-300">
<UploadCloud className="size-7" />
<span className="text-sm text-custom-text-300">Drag and drop anywhere to upload</span>
<>
{attachmentDeleteModalId && (
<IssueAttachmentDeleteModal
isOpen={Boolean(attachmentDeleteModalId)}
onClose={() => toggleDeleteAttachmentModal(null)}
handleAttachmentOperations={handleAttachmentOperations}
attachmentId={attachmentDeleteModalId}
/>
)}
<div
{...getRootProps()}
className={`relative flex flex-col ${isDragActive && issueAttachments.length < 3 ? "min-h-[200px]" : ""} ${disabled ? "cursor-not-allowed" : "cursor-pointer"}`}
>
<input {...getInputProps()} />
{isDragActive && (
<div className="absolute flex items-center justify-center left-0 top-0 h-full w-full bg-custom-background-90/75 z-30 ">
<div className="flex items-center justify-center p-1 rounded-md bg-custom-background-100">
<div className="flex flex-col justify-center items-center px-5 py-6 rounded-md border border-dashed border-custom-border-300">
<UploadCloud className="size-7" />
<span className="text-sm text-custom-text-300">Drag and drop anywhere to upload</span>
</div>
</div>
</div>
</div>
)}
{issueAttachments?.map((attachmentId) => (
<IssueAttachmentsListItem
key={attachmentId}
attachmentId={attachmentId}
disabled={disabled}
handleAttachmentOperations={handleAttachmentOperations}
/>
))}
</div>
)}
{issueAttachments?.map((attachmentId) => (
<IssueAttachmentsListItem key={attachmentId} attachmentId={attachmentId} disabled={disabled} />
))}
</div>
</>
);
});

View file

@ -8,32 +8,25 @@ import { CustomMenu, Tooltip } from "@plane/ui";
// components
import { ButtonAvatars } from "@/components/dropdowns/member/avatar";
import { getFileIcon } from "@/components/icons";
import { IssueAttachmentDeleteModal } from "@/components/issues";
// helpers
import { convertBytesToSize, getFileExtension, getFileName } from "@/helpers/attachment.helper";
import { renderFormattedDate } from "@/helpers/date-time.helper";
// hooks
import { useIssueDetail, useMember } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// types
import { TAttachmentOperations } from "./root";
type TAttachmentOperationsRemoveModal = Exclude<TAttachmentOperations, "create">;
type TIssueAttachmentsListItem = {
attachmentId: string;
handleAttachmentOperations: TAttachmentOperationsRemoveModal;
disabled?: boolean;
};
export const IssueAttachmentsListItem: FC<TIssueAttachmentsListItem> = observer((props) => {
// props
const { attachmentId, handleAttachmentOperations, disabled } = props;
const { attachmentId, disabled } = props;
// store hooks
const { getUserDetails } = useMember();
const {
attachment: { getAttachmentById },
isDeleteAttachmentModalOpen,
toggleDeleteAttachmentModal,
} = useIssueDetail();
@ -46,14 +39,6 @@ export const IssueAttachmentsListItem: FC<TIssueAttachmentsListItem> = observer(
return (
<>
{isDeleteAttachmentModalOpen && (
<IssueAttachmentDeleteModal
isOpen={isDeleteAttachmentModalOpen}
onClose={() => toggleDeleteAttachmentModal(false)}
handleAttachmentOperations={handleAttachmentOperations}
data={attachment}
/>
)}
<button
onClick={(e) => {
e.preventDefault();
@ -95,7 +80,7 @@ export const IssueAttachmentsListItem: FC<TIssueAttachmentsListItem> = observer(
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
toggleDeleteAttachmentModal(true);
toggleDeleteAttachmentModal(attachmentId);
}}
>
<div className="flex items-center gap-2">

View file

@ -1,10 +1,12 @@
import { FC, useState } from "react";
import { observer } from "mobx-react";
// types
import type { TIssueAttachment } from "@plane/types";
// ui
import { AlertModalCore } from "@plane/ui";
// helper
import { getFileName } from "@/helpers/attachment.helper";
// hooks
import { useIssueDetail } from "@/hooks/store";
// types
import { TAttachmentOperations } from "./root";
@ -13,15 +15,24 @@ export type TAttachmentOperationsRemoveModal = Exclude<TAttachmentOperations, "c
type Props = {
isOpen: boolean;
onClose: () => void;
data: TIssueAttachment;
attachmentId: string;
handleAttachmentOperations: TAttachmentOperationsRemoveModal;
};
export const IssueAttachmentDeleteModal: FC<Props> = (props) => {
const { isOpen, onClose, data, handleAttachmentOperations } = props;
export const IssueAttachmentDeleteModal: FC<Props> = observer((props) => {
const { isOpen, onClose, attachmentId, handleAttachmentOperations } = props;
// states
const [loader, setLoader] = useState(false);
// store hooks
const {
attachment: { getAttachmentById },
} = useIssueDetail();
// derived values
const attachment = attachmentId ? getAttachmentById(attachmentId) : undefined;
// handlers
const handleClose = () => {
onClose();
setLoader(false);
@ -32,20 +43,21 @@ export const IssueAttachmentDeleteModal: FC<Props> = (props) => {
handleAttachmentOperations.remove(assetId).finally(() => handleClose());
};
if (!attachment) return <></>;
return (
<AlertModalCore
handleClose={handleClose}
handleSubmit={() => handleDeletion(data.id)}
handleSubmit={() => handleDeletion(attachment.id)}
isSubmitting={loader}
isOpen={isOpen}
title="Delete attachment"
content={
<>
Are you sure you want to delete attachment-{" "}
<span className="font-bold">{getFileName(data.attributes.name)}</span>? This attachment will be permanently
removed. This action cannot be undone.
<span className="font-bold">{getFileName(attachment.attributes.name)}</span>? This attachment will be
permanently removed. This action cannot be undone.
</>
}
/>
);
};
});

View file

@ -57,7 +57,7 @@ export interface IIssueDetail
isArchiveIssueModalOpen: string | null;
isRelationModalOpen: TIssueRelationModal | null;
isSubIssuesModalOpen: string | null;
isDeleteAttachmentModalOpen: boolean;
attachmentDeleteModalId: string | null;
// computed
isAnyModalOpen: boolean;
// helper actions
@ -71,7 +71,7 @@ export interface IIssueDetail
toggleArchiveIssueModal: (value: string | null) => void;
toggleRelationModal: (issueId: string | null, relationType: TIssueRelationTypes | null) => void;
toggleSubIssuesModal: (value: string | null) => void;
toggleDeleteAttachmentModal: (value:boolean) => void;
toggleDeleteAttachmentModal: (attachmentId: string | null) => void;
// store
rootIssueStore: IIssueRootStore;
issue: IIssueStore;
@ -96,7 +96,7 @@ export class IssueDetail implements IIssueDetail {
isArchiveIssueModalOpen: string | null = null;
isRelationModalOpen: TIssueRelationModal | null = null;
isSubIssuesModalOpen: string | null = null;
isDeleteAttachmentModalOpen: boolean = false;
attachmentDeleteModalId: string | null = null;
// store
rootIssueStore: IIssueRootStore;
issue: IIssueStore;
@ -121,7 +121,7 @@ export class IssueDetail implements IIssueDetail {
isArchiveIssueModalOpen: observable.ref,
isRelationModalOpen: observable.ref,
isSubIssuesModalOpen: observable.ref,
isDeleteAttachmentModalOpen: observable,
attachmentDeleteModalId: observable.ref,
// computed
isAnyModalOpen: computed,
// action
@ -160,7 +160,7 @@ export class IssueDetail implements IIssueDetail {
!!this.isArchiveIssueModalOpen ||
!!this.isRelationModalOpen?.issueId ||
!!this.isSubIssuesModalOpen ||
this.isDeleteAttachmentModalOpen
!!this.attachmentDeleteModalId
);
}
@ -177,7 +177,7 @@ export class IssueDetail implements IIssueDetail {
toggleRelationModal = (issueId: string | null, relationType: TIssueRelationTypes | null) =>
(this.isRelationModalOpen = { issueId, relationType });
toggleSubIssuesModal = (issueId: string | null) => (this.isSubIssuesModalOpen = issueId);
toggleDeleteAttachmentModal = (value: boolean) => (this.isDeleteAttachmentModalOpen = value);
toggleDeleteAttachmentModal = (attachmentId: string | null) => (this.attachmentDeleteModalId = attachmentId);
// issue
fetchIssue = async (