Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: issue attachments feature #717

Merged
merged 21 commits into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4653006
chore: issue attachment services added
anmolsinghbhatia Apr 4, 2023
0c86705
feat: attachment icons added
anmolsinghbhatia Apr 4, 2023
f4fbe0f
chore: fetch-key and icons export
anmolsinghbhatia Apr 4, 2023
ce6fa86
feat: issue attachment upload section added
anmolsinghbhatia Apr 4, 2023
921820d
feat: issue attachment list section added
anmolsinghbhatia Apr 4, 2023
312bcb6
feat: date helper function added
anmolsinghbhatia Apr 4, 2023
aa1d921
style: responsiveness added
anmolsinghbhatia Apr 4, 2023
0e38bcf
feat: attachment info added
anmolsinghbhatia Apr 4, 2023
3f8f1b9
Merge branch 'develop' of github.com:makeplane/plane into feat/issue_…
anmolsinghbhatia Apr 4, 2023
66b5056
style: attachment overflow fix
anmolsinghbhatia Apr 4, 2023
a3e0019
style: cursor pointer added
anmolsinghbhatia Apr 4, 2023
62d266b
chore: issue attachment interface
anmolsinghbhatia Apr 4, 2023
258ab5f
style: uploading state added
anmolsinghbhatia Apr 4, 2023
eeceeff
feat: delete issue attachment modal
anmolsinghbhatia Apr 4, 2023
c3d5bd9
style: style improvement and refactor
anmolsinghbhatia Apr 4, 2023
4d18cd8
Merge branch 'develop' of github.com:makeplane/plane into feat/attach…
anmolsinghbhatia Apr 5, 2023
db46ea2
Merge branch 'develop' of github.com:makeplane/plane into feat/attach…
anmolsinghbhatia Apr 5, 2023
813b1cf
style: consistent icon added , chore: refactor the code
anmolsinghbhatia Apr 5, 2023
575e9f6
fix: js icon import fix
anmolsinghbhatia Apr 5, 2023
57e0fa6
fix: build fix
anmolsinghbhatia Apr 5, 2023
b705d86
chore: refactor code
anmolsinghbhatia Apr 6, 2023
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
61 changes: 44 additions & 17 deletions apps/app/components/icons/attachment-icon.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,46 @@
import React from "react";
import {
CssIcon,
CsvIcon,
DocIcon,
FigmaIcon,
HtmlIcon,
JavaScriptIcon,
JpgIcon,
PdfIcon,
PngIcon,
SheetIcon,
SvgIcon,
TxtIcon,
} from "components/icons";

import type { Props } from "./types";
export const getFileIcon = (fileType: string) => {
switch (fileType) {
case "pdf":
return <PdfIcon height={28} width={28} />;
case "csv":
return <CsvIcon height={28} width={28} />;
case "xlsx":
return <SheetIcon height={28} width={28} />;
case "css":
return <CssIcon height={28} width={28} />;
case "doc":
return <DocIcon height={28} width={28} />;
case "fig":
return <FigmaIcon height={28} width={28} />;
case "html":
return <HtmlIcon height={28} width={28} />;
case "png":
return <PngIcon height={28} width={28} />;
case "jpg":
return <JpgIcon height={28} width={28} />;
case "js":
return <JavaScriptIcon height={28} width={28} />;
case "txt":
return <TxtIcon height={28} width={28} />;
case "svg":
return <SvgIcon height={28} width={28} />;

export const AttachmentIcon: React.FC<Props> = ({ width, height, className }) => (
<svg
width={width}
height={height}
className={className}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M18.75 20C18.4 20 18.1042 19.8792 17.8625 19.6375C17.6208 19.3958 17.5 19.1 17.5 18.75V5.25C17.5 4.9 17.6208 4.60417 17.8625 4.3625C18.1042 4.12083 18.4 4 18.75 4C19.1 4 19.3958 4.12083 19.6375 4.3625C19.8792 4.60417 20 4.9 20 5.25V18.75C20 19.1 19.8792 19.3958 19.6375 19.6375C19.3958 19.8792 19.1 20 18.75 20ZM6.275 20C6.09167 20 5.92083 19.9667 5.7625 19.9C5.60417 19.8333 5.47083 19.7458 5.3625 19.6375C5.25417 19.5292 5.16667 19.3958 5.1 19.2375C5.03333 19.0792 5 18.9167 5 18.75V15.25C5 14.9 5.12083 14.6042 5.3625 14.3625C5.60417 14.1208 5.9 14 6.25 14C6.6 14 6.89583 14.1208 7.1375 14.3625C7.37917 14.6042 7.5 14.9 7.5 15.25V18.75C7.5 18.9167 7.46667 19.0792 7.4 19.2375C7.33333 19.3958 7.24583 19.5292 7.1375 19.6375C7.02917 19.7458 6.9 19.8333 6.75 19.9C6.6 19.9667 6.44167 20 6.275 20ZM12.5 20C12.15 20 11.8542 19.8792 11.6125 19.6375C11.3708 19.3958 11.25 19.1 11.25 18.75V10.25C11.25 9.9 11.3708 9.60417 11.6125 9.3625C11.8542 9.12083 12.15 9 12.5 9C12.85 9 13.1458 9.12083 13.3875 9.3625C13.6292 9.60417 13.75 9.9 13.75 10.25V18.75C13.75 19.1 13.6292 19.3958 13.3875 19.6375C13.1458 19.8792 12.85 20 12.5 20Z"
fill="#212529"
/>
</svg>
);
default:
return <DocIcon height={28} width={28}/>;
}
};
9 changes: 9 additions & 0 deletions apps/app/components/icons/css-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import CssFileIcon from "public/attachment/css-icon.png";

export const CssIcon: React.FC<Props> = ({ width, height }) => (
<Image src={CssFileIcon} height={height} width={width} alt="CssFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/csv-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import CSVFileIcon from "public/attachment/csv-icon.png";

export const CsvIcon: React.FC<Props> = ({ width , height }) => (
<Image src={CSVFileIcon} height={height} width={width} alt="CSVFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/doc-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import DocFileIcon from "public/attachment/doc-icon.png";

export const DocIcon: React.FC<Props> = ({ width , height }) => (
<Image src={DocFileIcon} height={height} width={width} alt="DocFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/figma-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import FigmaFileIcon from "public/attachment/figma-icon.png";

export const FigmaIcon: React.FC<Props> = ({ width , height }) => (
<Image src={FigmaFileIcon} height={height} width={width} alt="FigmaFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/html-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import HtmlFileIcon from "public/attachment/html-icon.png";

export const HtmlIcon: React.FC<Props> = ({ width, height }) => (
<Image src={HtmlFileIcon} height={height} width={width} alt="HtmlFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/img-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import ImgFileIcon from "public/attachment/img-icon.png";

export const ImgIcon: React.FC<Props> = ({ width , height }) => (
<Image src={ImgFileIcon} height={height} width={width} alt="ImgFileIcon" />
);
15 changes: 14 additions & 1 deletion apps/app/components/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,17 @@ export * from "./users";
export * from "./import-layers";
export * from "./check";
export * from "./water-drop-icon";
export * from "./transfer-icon";
export * from "./transfer-icon";
export * from "./pdf-file-icon";
export * from "./csv-file-icon";
export * from "./sheet-file-icon";
export * from "./doc-file-icon";
export * from "./html-file-icon";
export * from "./css-file-icon";
export * from "./js-file-icon";
export * from "./figma-file-icon";
export * from "./img-file-icon";
export * from "./png-file-icon";
export * from "./jpg-file-icon";
export * from "./svg-file-icon";
export * from "./txt-file-icon";
9 changes: 9 additions & 0 deletions apps/app/components/icons/jpg-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import JpgFileIcon from "public/attachment/jpg-icon.png";

export const JpgIcon: React.FC<Props> = ({ width, height }) => (
<Image src={JpgFileIcon} height={height} width={width} alt="JpgFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/js-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import JsFileIcon from "public/attachment/js-icon.png";

export const JavaScriptIcon: React.FC<Props> = ({ width, height }) => (
<Image src={JsFileIcon} height={height} width={width} alt="JsFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/pdf-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import PDFFileIcon from "public/attachment/pdf-icon.png";

export const PdfIcon: React.FC<Props> = ({ width , height }) => (
<Image src={PDFFileIcon} height={height} width={width} alt="PDFFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/png-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import PngFileIcon from "public/attachment/png-icon.png";

export const PngIcon: React.FC<Props> = ({ width, height }) => (
<Image src={PngFileIcon} height={height} width={width} alt="PngFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/sheet-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import SheetFileIcon from "public/attachment/excel-icon.png";

export const SheetIcon: React.FC<Props> = ({ width, height }) => (
<Image src={SheetFileIcon} height={height} width={width} alt="SheetFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/svg-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import SvgFileIcon from "public/attachment/svg-icon.png";

export const SvgIcon: React.FC<Props> = ({ width, height }) => (
<Image src={SvgFileIcon} height={height} width={width} alt="SvgFileIcon" />
);
9 changes: 9 additions & 0 deletions apps/app/components/icons/txt-file-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import Image from "next/image";

import type { Props } from "./types";
import TxtFileIcon from "public/attachment/txt-icon.png";

export const TxtIcon: React.FC<Props> = ({ width, height }) => (
<Image src={TxtFileIcon} height={height} width={width} alt="TxtFileIcon" />
);
99 changes: 99 additions & 0 deletions apps/app/components/issues/attachment-upload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React, { useCallback, useState } from "react";

import { useRouter } from "next/router";

import { mutate } from "swr";

// react-dropzone
import { useDropzone } from "react-dropzone";
// toast
import useToast from "hooks/use-toast";
// fetch key
import { ISSUE_ATTACHMENTS } from "constants/fetch-keys";
// services
import fileServices from "services/file.service";
import { IIssueAttachment } from "types";

const maxFileSize = 5 * 1024 * 1024; // 5 MB

export const IssueAttachmentUpload = () => {
const [isLoading, setIsLoading] = useState(false);

const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query;

const { setToastAlert } = useToast();

const onDrop = useCallback((acceptedFiles: File[]) => {
setIsLoading(true);
if (!acceptedFiles[0] || !workspaceSlug) return;

const formData = new FormData();
formData.append("asset", acceptedFiles[0]);
formData.append(
"attributes",
JSON.stringify({
name: acceptedFiles[0].name,
size: acceptedFiles[0].size,
})
);

fileServices
.uploadIssueAttachment(
workspaceSlug as string,
projectId as string,
issueId as string,
formData
)
.then((res) => {
mutate<IIssueAttachment[]>(ISSUE_ATTACHMENTS(issueId as string));
setToastAlert({
type: "success",
title: "Success!",
message: "File added successfully.",
});
setIsLoading(false);
})
.catch((err) => {
setIsLoading(false);
setToastAlert({
type: "error",
title: "error!",
message: "Something went wrong. please check file type & size (max 5 MB)",
});
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const { getRootProps, getInputProps, isDragActive, isDragReject, fileRejections } = useDropzone({
onDrop,
maxSize: maxFileSize,
multiple: false,
});

const fileError =
fileRejections.length > 0
? `Invalid file type or size (max ${maxFileSize / 1024 / 1024} MB)`
: null;

return (
<div
{...getRootProps()}
className={`flex items-center justify-center h-[60px] cursor-pointer border-2 border-dashed border-theme text-blue-500 bg-blue-500/5 text-sm rounded-md px-4 ${
isDragActive ? "bg-theme/10" : ""
} ${isDragReject ? "bg-red-100" : ""}`}
>
<input {...getInputProps()} />
<span className="flex items-center gap-2">
{isDragActive ? (
<p>Drop here...</p>
) : isLoading ? (
<p className="text-center">Uploading....</p>
) : (
<p className="text-center">Drag & Drop or Click to add new file</p>
)}
{fileError && <p className="text-red-500 mt-2">{fileError}</p>}
</span>
</div>
);
};
Loading