Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions web/core/components/issues/attachment/attachment-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ import { truncateText } from "@/helpers/string.helper";
import { useIssueDetail, useMember } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// types
import { TAttachmentOperations } from "./root";
import { TAttachmentHelpers } from "../issue-detail-widgets/attachments/helper";

type TAttachmentOperationsRemoveModal = Exclude<TAttachmentOperations, "create">;
type TAttachmentOperationsRemoveModal = Exclude<TAttachmentHelpers, "create">;

type TIssueAttachmentsDetail = {
attachmentId: string;
handleAttachmentOperations: TAttachmentOperationsRemoveModal;
attachmentHelpers: TAttachmentOperationsRemoveModal;
disabled?: boolean;
};

export const IssueAttachmentsDetail: FC<TIssueAttachmentsDetail> = observer((props) => {
// props
const { attachmentId, handleAttachmentOperations, disabled } = props;
const { attachmentId, attachmentHelpers, disabled } = props;
// store hooks
const { getUserDetails } = useMember();
const {
Expand All @@ -56,7 +56,7 @@ export const IssueAttachmentsDetail: FC<TIssueAttachmentsDetail> = observer((pro
<IssueAttachmentDeleteModal
isOpen={isDeleteIssueAttachmentModalOpen}
onClose={() => setIsDeleteIssueAttachmentModalOpen(false)}
handleAttachmentOperations={handleAttachmentOperations}
attachmentOperations={attachmentHelpers.operations}
attachmentId={attachmentId}
/>
)}
Expand Down
85 changes: 46 additions & 39 deletions web/core/components/issues/attachment/attachment-item-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,36 @@ import { TOAST_TYPE, setToast } from "@plane/ui";
import { useIssueDetail } from "@/hooks/store";
// plane web hooks
import { useFileSize } from "@/plane-web/hooks/use-file-size";
// types
import { TAttachmentHelpers } from "../issue-detail-widgets/attachments/helper";
// components
import { IssueAttachmentsListItem } from "./attachment-list-item";
import { IssueAttachmentsUploadItem } from "./attachment-list-upload-item";
// types
import { IssueAttachmentDeleteModal } from "./delete-attachment-modal";
import { TAttachmentOperations } from "./root";

type TAttachmentOperationsRemoveModal = Exclude<TAttachmentOperations, "create">;

type TIssueAttachmentItemList = {
workspaceSlug: string;
projectId: string;
issueId: string;
handleAttachmentOperations: TAttachmentOperationsRemoveModal;
attachmentHelpers: TAttachmentHelpers;
disabled?: boolean;
};

export const IssueAttachmentItemList: FC<TIssueAttachmentItemList> = observer((props) => {
const { workspaceSlug, projectId, issueId, handleAttachmentOperations, disabled } = props;
const { workspaceSlug, projectId, issueId, attachmentHelpers, disabled } = props;
// states
const [isLoading, setIsLoading] = useState(false);
const [isUploading, setIsUploading] = useState(false);
// store hooks
const {
attachment: { getAttachmentsByIssueId },
attachmentDeleteModalId,
toggleDeleteAttachmentModal,
fetchActivities,
} = useIssueDetail();
const { operations: attachmentOperations, snapshot: attachmentSnapshot } = attachmentHelpers;
const { create: createAttachment } = attachmentOperations;
const { uploadStatus } = attachmentSnapshot;
// file size
const { maxFileSize } = useFileSize();
// derived values
Expand All @@ -52,9 +55,8 @@ export const IssueAttachmentItemList: FC<TIssueAttachmentItemList> = observer((p
const currentFile: File = acceptedFiles[0];
if (!currentFile || !workspaceSlug) return;

setIsLoading(true);
handleAttachmentOperations
.create(currentFile)
setIsUploading(true);
createAttachment(currentFile)
.catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
Expand All @@ -64,7 +66,7 @@ export const IssueAttachmentItemList: FC<TIssueAttachmentItemList> = observer((p
})
.finally(() => {
handleFetchPropertyActivities();
setIsLoading(false);
setIsUploading(false);
});
return;
}
Expand All @@ -79,47 +81,52 @@ export const IssueAttachmentItemList: FC<TIssueAttachmentItemList> = observer((p
});
return;
},
[handleAttachmentOperations, maxFileSize, workspaceSlug, handleFetchPropertyActivities]
[createAttachment, maxFileSize, workspaceSlug, handleFetchPropertyActivities]
);

const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
maxSize: maxFileSize,
multiple: false,
disabled: isLoading || disabled,
disabled: isUploading || disabled,
});

if (!issueAttachments) return <></>;

return (
<>
{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>
{uploadStatus?.map((uploadStatus) => (
<IssueAttachmentsUploadItem key={uploadStatus.id} uploadStatus={uploadStatus} />
))}
{issueAttachments && (
<>
{attachmentDeleteModalId && (
<IssueAttachmentDeleteModal
isOpen={Boolean(attachmentDeleteModalId)}
onClose={() => toggleDeleteAttachmentModal(null)}
attachmentOperations={attachmentOperations}
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} />
))}
</div>
)}
{issueAttachments?.map((attachmentId) => (
<IssueAttachmentsListItem key={attachmentId} attachmentId={attachmentId} disabled={disabled} />
))}
</div>
</>
)}
</>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"use client";

import { observer } from "mobx-react";
// ui
import { CircularProgressIndicator, Tooltip } from "@plane/ui";
// components
import { getFileIcon } from "@/components/icons";
// helpers
import { getFileExtension } from "@/helpers/attachment.helper";
// hooks
import { usePlatformOS } from "@/hooks/use-platform-os";
// types
import { TAttachmentUploadStatus } from "@/store/issue/issue-details/attachment.store";

type Props = {
uploadStatus: TAttachmentUploadStatus;
};

export const IssueAttachmentsUploadItem: React.FC<Props> = observer((props) => {
// props
const { uploadStatus } = props;
// derived values
const fileName = uploadStatus.name;
const fileExtension = getFileExtension(uploadStatus.name ?? "");
const fileIcon = getFileIcon(fileExtension, 18);
Comment on lines +23 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add null checks and memoize derived values.

The file name and extension calculations should be memoized and protected against undefined values.

-  const fileName = uploadStatus.name;
-  const fileExtension = getFileExtension(uploadStatus.name ?? "");
-  const fileIcon = getFileIcon(fileExtension, 18);
+  const fileName = useMemo(() => uploadStatus.name ?? "", [uploadStatus.name]);
+  const fileExtension = useMemo(
+    () => getFileExtension(fileName),
+    [fileName]
+  );
+  const fileIcon = useMemo(
+    () => getFileIcon(fileExtension, 18),
+    [fileExtension]
+  );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fileName = uploadStatus.name;
const fileExtension = getFileExtension(uploadStatus.name ?? "");
const fileIcon = getFileIcon(fileExtension, 18);
const fileName = useMemo(() => uploadStatus.name ?? "", [uploadStatus.name]);
const fileExtension = useMemo(
() => getFileExtension(fileName),
[fileName]
);
const fileIcon = useMemo(
() => getFileIcon(fileExtension, 18),
[fileExtension]
);

// hooks
const { isMobile } = usePlatformOS();

return (
<div className="flex items-center justify-between gap-3 h-11 bg-custom-background-90 pl-9 pr-2 pointer-events-none">
<div className="flex items-center gap-3 text-sm truncate">
<div className="flex-shrink-0">{fileIcon}</div>
<Tooltip tooltipContent={fileName} isMobile={isMobile}>
<p className="text-custom-text-200 font-medium truncate">{fileName}</p>
</Tooltip>
</div>
<div className="flex-shrink-0 flex items-center gap-2">
<span className="flex-shrink-0">
<CircularProgressIndicator size={20} strokeWidth={3} percentage={uploadStatus.progress} />
</span>
<div className="flex-shrink-0 text-sm font-medium">{uploadStatus.progress}% done</div>
</div>
</div>
Comment on lines +29 to +43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Enhance accessibility attributes.

The upload item should have proper ARIA attributes for better screen reader support.

-    <div className="flex items-center justify-between gap-3 h-11 bg-custom-background-90 pl-9 pr-2 pointer-events-none">
+    <div 
+      role="status"
+      aria-label={`Uploading ${fileName}, ${uploadStatus.progress}% complete`}
+      className="flex items-center justify-between gap-3 h-11 bg-custom-background-90 pl-9 pr-2 pointer-events-none"
+    >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
<div className="flex items-center justify-between gap-3 h-11 bg-custom-background-90 pl-9 pr-2 pointer-events-none">
<div className="flex items-center gap-3 text-sm truncate">
<div className="flex-shrink-0">{fileIcon}</div>
<Tooltip tooltipContent={fileName} isMobile={isMobile}>
<p className="text-custom-text-200 font-medium truncate">{fileName}</p>
</Tooltip>
</div>
<div className="flex-shrink-0 flex items-center gap-2">
<span className="flex-shrink-0">
<CircularProgressIndicator size={20} strokeWidth={3} percentage={uploadStatus.progress} />
</span>
<div className="flex-shrink-0 text-sm font-medium">{uploadStatus.progress}% done</div>
</div>
</div>
return (
<div
role="status"
aria-label={`Uploading ${fileName}, ${uploadStatus.progress}% complete`}
className="flex items-center justify-between gap-3 h-11 bg-custom-background-90 pl-9 pr-2 pointer-events-none"
>
<div className="flex items-center gap-3 text-sm truncate">
<div className="flex-shrink-0">{fileIcon}</div>
<Tooltip tooltipContent={fileName} isMobile={isMobile}>
<p className="text-custom-text-200 font-medium truncate">{fileName}</p>
</Tooltip>
</div>
<div className="flex-shrink-0 flex items-center gap-2">
<span className="flex-shrink-0">
<CircularProgressIndicator size={20} strokeWidth={3} percentage={uploadStatus.progress} />
</span>
<div className="flex-shrink-0 text-sm font-medium">{uploadStatus.progress}% done</div>
</div>
</div>

);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use client";

import { observer } from "mobx-react";
// ui
import { CircularProgressIndicator, Tooltip } from "@plane/ui";
// icons
import { getFileIcon } from "@/components/icons";
// helpers
import { getFileExtension } from "@/helpers/attachment.helper";
import { truncateText } from "@/helpers/string.helper";
// hooks
import { usePlatformOS } from "@/hooks/use-platform-os";
// types
import { TAttachmentUploadStatus } from "@/store/issue/issue-details/attachment.store";

type Props = {
uploadStatus: TAttachmentUploadStatus;
};

export const IssueAttachmentsUploadDetails: React.FC<Props> = observer((props) => {
// props
const { uploadStatus } = props;
// derived values
const fileName = uploadStatus.name;
const fileExtension = getFileExtension(uploadStatus.name ?? "");
const fileIcon = getFileIcon(fileExtension, 28);
// hooks
const { isMobile } = usePlatformOS();

Comment on lines +20 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider adding error handling for edge cases.

The component should handle cases where uploadStatus.name is undefined or empty, as the current implementation might throw errors.

Apply this diff to add error handling:

-  const fileName = uploadStatus.name;
-  const fileExtension = getFileExtension(uploadStatus.name ?? "");
+  const fileName = uploadStatus.name || "Unknown file";
+  const fileExtension = getFileExtension(fileName);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const IssueAttachmentsUploadDetails: React.FC<Props> = observer((props) => {
// props
const { uploadStatus } = props;
// derived values
const fileName = uploadStatus.name;
const fileExtension = getFileExtension(uploadStatus.name ?? "");
const fileIcon = getFileIcon(fileExtension, 28);
// hooks
const { isMobile } = usePlatformOS();
export const IssueAttachmentsUploadDetails: React.FC<Props> = observer((props) => {
// props
const { uploadStatus } = props;
// derived values
const fileName = uploadStatus.name || "Unknown file";
const fileExtension = getFileExtension(fileName);
const fileIcon = getFileIcon(fileExtension, 28);
// hooks
const { isMobile } = usePlatformOS();

return (
<div className="flex h-[60px] items-center justify-between gap-1 rounded-md border-[2px] border-custom-border-200 bg-custom-background-90 px-4 py-2 text-sm pointer-events-none">
<div className="flex-shrink-0 flex items-center gap-3">
<div className="h-7 w-7">{fileIcon}</div>
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<Tooltip tooltipContent={fileName} isMobile={isMobile}>
<span className="text-sm">{truncateText(`${fileName}`, 10)}</span>
</Tooltip>
</div>

<div className="flex items-center gap-3 text-xs text-custom-text-200">
<span>{fileExtension.toUpperCase()}</span>
</div>
</div>
</div>
Comment on lines +31 to +45
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve accessibility and user interaction.

  1. The pointer-events-none class prevents all pointer interactions, which might affect accessibility. Consider allowing pointer events for the tooltip.
  2. The truncation length of 10 characters seems too short for most file names.

Apply these improvements:

-    <div className="flex h-[60px] items-center justify-between gap-1 rounded-md border-[2px] border-custom-border-200 bg-custom-background-90 px-4 py-2 text-sm pointer-events-none">
+    <div className="flex h-[60px] items-center justify-between gap-1 rounded-md border-[2px] border-custom-border-200 bg-custom-background-90 px-4 py-2 text-sm">
       <div className="flex-shrink-0 flex items-center gap-3">
         <div className="h-7 w-7">{fileIcon}</div>
         <div className="flex flex-col gap-1">
           <div className="flex items-center gap-2">
             <Tooltip tooltipContent={fileName} isMobile={isMobile}>
-              <span className="text-sm">{truncateText(`${fileName}`, 10)}</span>
+              <span className="text-sm">{truncateText(`${fileName}`, 20)}</span>
             </Tooltip>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="flex h-[60px] items-center justify-between gap-1 rounded-md border-[2px] border-custom-border-200 bg-custom-background-90 px-4 py-2 text-sm pointer-events-none">
<div className="flex-shrink-0 flex items-center gap-3">
<div className="h-7 w-7">{fileIcon}</div>
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<Tooltip tooltipContent={fileName} isMobile={isMobile}>
<span className="text-sm">{truncateText(`${fileName}`, 10)}</span>
</Tooltip>
</div>
<div className="flex items-center gap-3 text-xs text-custom-text-200">
<span>{fileExtension.toUpperCase()}</span>
</div>
</div>
</div>
<div className="flex h-[60px] items-center justify-between gap-1 rounded-md border-[2px] border-custom-border-200 bg-custom-background-90 px-4 py-2 text-sm">
<div className="flex-shrink-0 flex items-center gap-3">
<div className="h-7 w-7">{fileIcon}</div>
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<Tooltip tooltipContent={fileName} isMobile={isMobile}>
<span className="text-sm">{truncateText(`${fileName}`, 20)}</span>
</Tooltip>
</div>
<div className="flex items-center gap-3 text-xs text-custom-text-200">
<span>{fileExtension.toUpperCase()}</span>
</div>
</div>
</div>

<div className="flex-shrink-0 flex items-center gap-2">
<span className="flex-shrink-0">
<CircularProgressIndicator size={20} strokeWidth={3} percentage={uploadStatus.progress} />
</span>
<div className="flex-shrink-0 text-sm font-medium">{uploadStatus.progress}% done</div>
</div>
</div>
Comment on lines +46 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance progress indicator accessibility.

The circular progress indicator should include ARIA attributes for better screen reader support.

Apply this improvement:

       <div className="flex-shrink-0 flex items-center gap-2">
         <span className="flex-shrink-0">
-          <CircularProgressIndicator size={20} strokeWidth={3} percentage={uploadStatus.progress} />
+          <CircularProgressIndicator 
+            size={20} 
+            strokeWidth={3} 
+            percentage={uploadStatus.progress}
+            aria-label={`Upload progress: ${uploadStatus.progress}%`}
+            role="progressbar"
+            aria-valuenow={uploadStatus.progress}
+            aria-valuemin={0}
+            aria-valuemax={100}
+          />
         </span>
-        <div className="flex-shrink-0 text-sm font-medium">{uploadStatus.progress}% done</div>
+        <div className="flex-shrink-0 text-sm font-medium" aria-hidden="true">{uploadStatus.progress}% done</div>
       </div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="flex-shrink-0 flex items-center gap-2">
<span className="flex-shrink-0">
<CircularProgressIndicator size={20} strokeWidth={3} percentage={uploadStatus.progress} />
</span>
<div className="flex-shrink-0 text-sm font-medium">{uploadStatus.progress}% done</div>
</div>
</div>
<div className="flex-shrink-0 flex items-center gap-2">
<span className="flex-shrink-0">
<CircularProgressIndicator
size={20}
strokeWidth={3}
percentage={uploadStatus.progress}
aria-label={`Upload progress: ${uploadStatus.progress}%`}
role="progressbar"
aria-valuenow={uploadStatus.progress}
aria-valuemin={0}
aria-valuemax={100}
/>
</span>
<div className="flex-shrink-0 text-sm font-medium" aria-hidden="true">{uploadStatus.progress}% done</div>
</div>
</div>

);
});
Comment on lines +20 to +54
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider performance optimizations.

The component could benefit from performance optimizations to prevent unnecessary re-renders.

  1. Memoize derived values:
+  const derivedValues = useMemo(() => ({
+    fileName: uploadStatus.name || "Unknown file",
+    fileExtension: getFileExtension(uploadStatus.name ?? ""),
+    fileIcon: getFileIcon(fileExtension, 28)
+  }), [uploadStatus.name]);
  1. Extract the progress indicator into a separate memoized component to prevent re-renders of the entire component when only the progress changes.

Committable suggestion was skipped due to low confidence.

12 changes: 6 additions & 6 deletions web/core/components/issues/attachment/attachment-upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ import { useDropzone } from "react-dropzone";
// plane web hooks
import { useFileSize } from "@/plane-web/hooks/use-file-size";
// types
import { TAttachmentOperations } from "./root";
import { TAttachmentOperations } from "../issue-detail-widgets/attachments/helper";

type TAttachmentOperationsModal = Exclude<TAttachmentOperations, "remove">;
type TAttachmentOperationsModal = Pick<TAttachmentOperations, "create">;

type Props = {
workspaceSlug: string;
disabled?: boolean;
handleAttachmentOperations: TAttachmentOperationsModal;
attachmentOperations: TAttachmentOperationsModal;
};

export const IssueAttachmentUpload: React.FC<Props> = observer((props) => {
const { workspaceSlug, disabled = false, handleAttachmentOperations } = props;
const { workspaceSlug, disabled = false, attachmentOperations } = props;
// states
const [isLoading, setIsLoading] = useState(false);
// file size
Expand All @@ -27,9 +27,9 @@ export const IssueAttachmentUpload: React.FC<Props> = observer((props) => {
if (!currentFile || !workspaceSlug) return;

setIsLoading(true);
handleAttachmentOperations.create(currentFile).finally(() => setIsLoading(false));
attachmentOperations.create(currentFile).finally(() => setIsLoading(false));
},
[handleAttachmentOperations, workspaceSlug]
[attachmentOperations, workspaceSlug]
);

const { getRootProps, getInputProps, isDragActive, isDragReject, fileRejections } = useDropzone({
Expand Down
20 changes: 11 additions & 9 deletions web/core/components/issues/attachment/attachments-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,40 @@ import { FC } from "react";
import { observer } from "mobx-react";
// hooks
import { useIssueDetail } from "@/hooks/store";
// types
import { TAttachmentHelpers } from "../issue-detail-widgets/attachments/helper";
// components
import { IssueAttachmentsDetail } from "./attachment-detail";
// types
import { TAttachmentOperations } from "./root";

type TAttachmentOperationsRemoveModal = Exclude<TAttachmentOperations, "create">;
import { IssueAttachmentsUploadDetails } from "./attachment-upload-details";

type TIssueAttachmentsList = {
issueId: string;
handleAttachmentOperations: TAttachmentOperationsRemoveModal;
attachmentHelpers: TAttachmentHelpers;
disabled?: boolean;
};

export const IssueAttachmentsList: FC<TIssueAttachmentsList> = observer((props) => {
const { issueId, handleAttachmentOperations, disabled } = props;
const { issueId, attachmentHelpers, disabled } = props;
// store hooks
const {
attachment: { getAttachmentsByIssueId },
} = useIssueDetail();
// derived values
const { snapshot: attachmentSnapshot } = attachmentHelpers;
const { uploadStatus } = attachmentSnapshot;
const issueAttachments = getAttachmentsByIssueId(issueId);

if (!issueAttachments) return <></>;

return (
<>
{uploadStatus?.map((uploadStatus) => (
<IssueAttachmentsUploadDetails key={uploadStatus.id} uploadStatus={uploadStatus} />
))}
{issueAttachments?.map((attachmentId) => (
<IssueAttachmentsDetail
key={attachmentId}
attachmentId={attachmentId}
disabled={disabled}
handleAttachmentOperations={handleAttachmentOperations}
attachmentHelpers={attachmentHelpers}
/>
))}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ import { getFileName } from "@/helpers/attachment.helper";
// hooks
import { useIssueDetail } from "@/hooks/store";
// types
import { TAttachmentOperations } from "./root";
import { TAttachmentOperations } from "../issue-detail-widgets/attachments/helper";

export type TAttachmentOperationsRemoveModal = Exclude<TAttachmentOperations, "create">;
export type TAttachmentOperationsRemoveModal = Pick<TAttachmentOperations, "remove">;

type Props = {
isOpen: boolean;
onClose: () => void;
attachmentId: string;
handleAttachmentOperations: TAttachmentOperationsRemoveModal;
attachmentOperations: TAttachmentOperationsRemoveModal;
};

export const IssueAttachmentDeleteModal: FC<Props> = observer((props) => {
const { isOpen, onClose, attachmentId, handleAttachmentOperations } = props;
const { isOpen, onClose, attachmentId, attachmentOperations } = props;
// states
const [loader, setLoader] = useState(false);

Expand All @@ -40,7 +40,7 @@ export const IssueAttachmentDeleteModal: FC<Props> = observer((props) => {

const handleDeletion = async (assetId: string) => {
setLoader(true);
handleAttachmentOperations.remove(assetId).finally(() => handleClose());
attachmentOperations.remove(assetId).finally(() => handleClose());
};

if (!attachment) return <></>;
Expand Down
Loading