forked from github/plane
Compare commits
11 Commits
preview
...
feat/toast
Author | SHA1 | Date | |
---|---|---|---|
|
0658953d7a | ||
|
df4211e54f | ||
|
e4e1aa8b52 | ||
|
2836161107 | ||
|
1b06b21087 | ||
|
937d04e88c | ||
|
32aef44e52 | ||
|
c568a26164 | ||
|
2b665626b4 | ||
|
6d6478136a | ||
|
4cf121b914 |
@ -173,9 +173,19 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
|
mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
|
||||||
mutate(MODULE_DETAILS(moduleId as string));
|
mutate(MODULE_DETAILS(moduleId as string));
|
||||||
} else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
|
} else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Issue updated successfully.",
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -209,15 +219,22 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
const originURL =
|
const originURL =
|
||||||
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||||
copyTextToClipboard(
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`)
|
||||||
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`
|
.then(() => {
|
||||||
).then(() => {
|
setToastAlert({
|
||||||
setToastAlert({
|
type: "info",
|
||||||
type: "success",
|
title: "Link Copied Successfully",
|
||||||
title: "Link Copied!",
|
iconType: "copy",
|
||||||
message: "Issue link copied to clipboard.",
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -149,6 +149,19 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
|
mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
|
||||||
mutate(MODULE_DETAILS(moduleId as string));
|
mutate(MODULE_DETAILS(moduleId as string));
|
||||||
} else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
|
} else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Issue updated successfully.",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -168,15 +181,22 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
const originURL =
|
const originURL =
|
||||||
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||||
copyTextToClipboard(
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`)
|
||||||
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`
|
.then(() => {
|
||||||
).then(() => {
|
setToastAlert({
|
||||||
setToastAlert({
|
type: "info",
|
||||||
type: "success",
|
title: "Link Copied Successfully",
|
||||||
title: "Link Copied!",
|
iconType: "copy",
|
||||||
message: "Issue link copied to clipboard.",
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const isNotAllowed = userAuth.isGuest || userAuth.isViewer || isCompleted;
|
const isNotAllowed = userAuth.isGuest || userAuth.isViewer || isCompleted;
|
||||||
|
@ -117,8 +117,8 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
|||||||
handleClose();
|
handleClose();
|
||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
title: "Success",
|
|
||||||
type: "success",
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
message: "Cycle deleted successfully",
|
message: "Cycle deleted successfully",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -62,8 +62,8 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
|||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success",
|
||||||
message: "Cycle created successfully.",
|
message: "Cycle created successfully",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@ -115,8 +115,8 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
|||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success",
|
||||||
message: "Cycle updated successfully.",
|
message: "Cycle updated successfully",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@ -92,8 +92,22 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
|
|
||||||
cyclesService
|
cyclesService
|
||||||
.patchCycle(workspaceSlug as string, projectId as string, cycleId as string, data)
|
.patchCycle(workspaceSlug as string, projectId as string, cycleId as string, data)
|
||||||
.then(() => mutate(CYCLE_DETAILS(cycleId as string)))
|
.then(() => {
|
||||||
.catch((e) => console.log(e));
|
mutate(CYCLE_DETAILS(cycleId as string));
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Cycle updated successfully",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
@ -103,14 +117,16 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/cycles/${cycle?.id}`)
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/cycles/${cycle?.id}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Cycle link copied to clipboard",
|
title: "Link Copied Successfully",
|
||||||
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Some error occurred",
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -219,9 +219,9 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
`${originURL}/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`
|
`${originURL}/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`
|
||||||
).then(() => {
|
).then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Link Copied!",
|
title: "Link Copied Successfully",
|
||||||
message: "Cycle link copied to clipboard.",
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -282,7 +282,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-between mt-4">
|
<div className="mt-4 flex items-center justify-between">
|
||||||
<div className="flex items-center gap-2.5">
|
<div className="flex items-center gap-2.5">
|
||||||
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
|
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
|
||||||
<Image
|
<Image
|
||||||
@ -293,7 +293,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
alt={cycle.owned_by.first_name}
|
alt={cycle.owned_by.first_name}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-brand-base capitalize bg-brand-secondary">
|
<span className="bg-brand-secondary flex h-5 w-5 items-center justify-center rounded-full bg-brand-base capitalize">
|
||||||
{cycle.owned_by.first_name.charAt(0)}
|
{cycle.owned_by.first_name.charAt(0)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
26
apps/app/components/icons/error-icon.tsx
Normal file
26
apps/app/components/icons/error-icon.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import type { Props } from "./types";
|
||||||
|
|
||||||
|
export const ErrorIcon: React.FC<Props> = ({ width = "24", height = "24", className }) => (
|
||||||
|
<svg
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
className={className}
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g clip-path="url(#clip0_3327_77971)">
|
||||||
|
<path
|
||||||
|
d="M9 1.5C4.8525 1.5 1.5 4.8525 1.5 9C1.5 13.1475 4.8525 16.5 9 16.5C13.1475 16.5 16.5 13.1475 16.5 9C16.5 4.8525 13.1475 1.5 9 1.5ZM12.75 11.6925L11.6925 12.75L9 10.0575L6.3075 12.75L5.25 11.6925L7.9425 9L5.25 6.3075L6.3075 5.25L9 7.9425L11.6925 5.25L12.75 6.3075L10.0575 9L12.75 11.6925Z"
|
||||||
|
fill="#FF5353"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_3327_77971">
|
||||||
|
<rect width="18" height="18" fill="white" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
);
|
@ -43,7 +43,7 @@ export * from "./user-icon";
|
|||||||
export * from "./grid-view-icons";
|
export * from "./grid-view-icons";
|
||||||
export * from "./assignment-clipboard-icon";
|
export * from "./assignment-clipboard-icon";
|
||||||
export * from "./tick-mark-icon";
|
export * from "./tick-mark-icon";
|
||||||
export * from "./target-icon"
|
export * from "./target-icon";
|
||||||
export * from "./contrast-icon";
|
export * from "./contrast-icon";
|
||||||
export * from "./people-group-icon";
|
export * from "./people-group-icon";
|
||||||
export * from "./cmd-icon";
|
export * from "./cmd-icon";
|
||||||
@ -72,4 +72,6 @@ export * from "./svg-file-icon";
|
|||||||
export * from "./txt-file-icon";
|
export * from "./txt-file-icon";
|
||||||
export * from "./default-file-icon";
|
export * from "./default-file-icon";
|
||||||
export * from "./video-file-icon";
|
export * from "./video-file-icon";
|
||||||
export * from "./audio-file-icon";
|
export * from "./audio-file-icon";
|
||||||
|
export * from "./success-icon";
|
||||||
|
export * from "./error-icon";
|
||||||
|
19
apps/app/components/icons/success-icon.tsx
Normal file
19
apps/app/components/icons/success-icon.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import type { Props } from "./types";
|
||||||
|
|
||||||
|
export const SuccessIcon: React.FC<Props> = ({ width = "24", height = "24", className }) => (
|
||||||
|
<svg
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
className={className}
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="#09A953"
|
||||||
|
d="M8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM6.5 11.75L2.75 8L3.8075 6.9425L6.5 9.6275L12.1925 3.935L13.25 5L6.5 11.75Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
@ -65,9 +65,9 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
|
|||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
title: "Success",
|
title: "Issue Deleted Successfully",
|
||||||
type: "success",
|
type: "success",
|
||||||
message: "Issue deleted successfully",
|
message: `${data.project_detail.identifier}-${data.sequence_id} is deleted successfully from the project ${data.project_detail.name}`,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
@ -138,8 +138,8 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
|||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Issue Created Successfully",
|
||||||
message: "Issue created successfully.",
|
message: `${res.project_detail.identifier}-${res.sequence_id} is created successfully under the project ${res.project_detail.name}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (payload.assignees_list?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE);
|
if (payload.assignees_list?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE);
|
||||||
@ -179,7 +179,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
|||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success",
|
||||||
message: "Issue updated successfully.",
|
message: "Issue updated successfully.",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -57,9 +57,19 @@ export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId
|
|||||||
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
|
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(USER_ISSUE(workspaceSlug as string));
|
mutate(USER_ISSUE(workspaceSlug as string));
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Issue updated successfully.",
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[workspaceSlug, projectId, issue]
|
[workspaceSlug, projectId, issue]
|
||||||
@ -68,21 +78,28 @@ export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId
|
|||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
const originURL =
|
const originURL =
|
||||||
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||||
copyTextToClipboard(
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`)
|
||||||
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`
|
.then(() => {
|
||||||
).then(() => {
|
setToastAlert({
|
||||||
setToastAlert({
|
type: "info",
|
||||||
type: "success",
|
title: "Link Copied Successfully",
|
||||||
title: "Link Copied!",
|
iconType: "copy",
|
||||||
message: "Issue link copied to clipboard.",
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const isNotAllowed = false;
|
const isNotAllowed = false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-b border-brand-base last:border-b-0 mx-6">
|
<div className="mx-6 border-b border-brand-base last:border-b-0">
|
||||||
<div key={issue.id} className="flex items-center justify-between gap-2 py-3">
|
<div key={issue.id} className="flex items-center justify-between gap-2 py-3">
|
||||||
<Link href={`/${workspaceSlug}/projects/${issue?.project_detail?.id}/issues/${issue.id}`}>
|
<Link href={`/${workspaceSlug}/projects/${issue?.project_detail?.id}/issues/${issue.id}`}>
|
||||||
<a className="group relative flex items-center gap-2">
|
<a className="group relative flex items-center gap-2">
|
||||||
@ -171,7 +188,7 @@ export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{properties.link && (
|
{properties.link && (
|
||||||
<div className="flex items-center rounded-md shadow-sm px-2.5 py-1 cursor-default text-xs border border-gray-200">
|
<div className="flex cursor-default items-center rounded-md border border-gray-200 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Link" tooltipContent={`${issue.link_count}`}>
|
<Tooltip tooltipHeading="Link" tooltipContent={`${issue.link_count}`}>
|
||||||
<div className="flex items-center gap-1 text-gray-500">
|
<div className="flex items-center gap-1 text-gray-500">
|
||||||
<LinkIcon className="h-3.5 w-3.5 text-gray-500" />
|
<LinkIcon className="h-3.5 w-3.5 text-gray-500" />
|
||||||
@ -181,10 +198,10 @@ export const MyIssuesListItem: React.FC<Props> = ({ issue, properties, projectId
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.attachment_count && (
|
{properties.attachment_count && (
|
||||||
<div className="flex items-center rounded-md shadow-sm px-2.5 py-1 cursor-default text-xs border border-gray-200">
|
<div className="flex cursor-default items-center rounded-md border border-gray-200 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Attachment" tooltipContent={`${issue.attachment_count}`}>
|
<Tooltip tooltipHeading="Attachment" tooltipContent={`${issue.attachment_count}`}>
|
||||||
<div className="flex items-center gap-1 text-gray-500">
|
<div className="flex items-center gap-1 text-gray-500">
|
||||||
<PaperClipIcon className="h-3.5 w-3.5 text-gray-500 -rotate-45" />
|
<PaperClipIcon className="h-3.5 w-3.5 -rotate-45 text-gray-500" />
|
||||||
{issue.attachment_count}
|
{issue.attachment_count}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -156,7 +156,14 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
|
|
||||||
await issuesService
|
await issuesService
|
||||||
.createIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, payload)
|
.createIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, payload)
|
||||||
.then(() => mutate(ISSUE_DETAILS(issueDetail.id)))
|
.then(() => {
|
||||||
|
mutate(ISSUE_DETAILS(issueDetail.id));
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Link added successfully",
|
||||||
|
});
|
||||||
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (err.status === 400)
|
if (err.status === 400)
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -188,9 +195,19 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
.deleteIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, linkId)
|
.deleteIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, linkId)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(ISSUE_DETAILS(issueDetail.id));
|
mutate(ISSUE_DETAILS(issueDetail.id));
|
||||||
|
setToastAlert({
|
||||||
|
title: "Success",
|
||||||
|
message: "Link removed successfully",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -202,9 +219,9 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issueDetail?.id}`
|
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issueDetail?.id}`
|
||||||
).then(() => {
|
).then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Link Copied!",
|
title: "Link Copied Successfully",
|
||||||
message: "Issue link copied to clipboard.",
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -54,6 +54,11 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data })
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
if (moduleId) router.push(`/${workspaceSlug}/projects/${data.project}/modules`);
|
if (moduleId) router.push(`/${workspaceSlug}/projects/${data.project}/modules`);
|
||||||
handleClose();
|
handleClose();
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Module deleted successfully",
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
|
@ -57,8 +57,8 @@ export const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, da
|
|||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success",
|
||||||
message: "Module created successfully.",
|
message: "Module created successfully",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@ -88,8 +88,8 @@ export const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, da
|
|||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success",
|
||||||
message: "Module updated successfully.",
|
message: "Module updated successfully",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
@ -87,8 +87,22 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen,
|
|||||||
|
|
||||||
modulesService
|
modulesService
|
||||||
.patchModule(workspaceSlug as string, projectId as string, moduleId as string, data)
|
.patchModule(workspaceSlug as string, projectId as string, moduleId as string, data)
|
||||||
.then(() => mutate(MODULE_DETAILS(moduleId as string)))
|
.then(() => {
|
||||||
.catch((e) => console.log(e));
|
mutate(MODULE_DETAILS(moduleId as string));
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Module updated successfully",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateLink = async (formData: ModuleLink) => {
|
const handleCreateLink = async (formData: ModuleLink) => {
|
||||||
@ -98,7 +112,14 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen,
|
|||||||
|
|
||||||
await modulesService
|
await modulesService
|
||||||
.createModuleLink(workspaceSlug as string, projectId as string, moduleId as string, payload)
|
.createModuleLink(workspaceSlug as string, projectId as string, moduleId as string, payload)
|
||||||
.then(() => mutate(MODULE_DETAILS(moduleId as string)))
|
.then(() => {
|
||||||
|
mutate(MODULE_DETAILS(moduleId as string));
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Link added successfully",
|
||||||
|
});
|
||||||
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (err.status === 400)
|
if (err.status === 400)
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -143,14 +164,16 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ issues, module, isOpen,
|
|||||||
copyTextToClipboard(`${workspaceSlug}/projects/${projectId}/modules/${module?.id}`)
|
copyTextToClipboard(`${workspaceSlug}/projects/${projectId}/modules/${module?.id}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Module link copied to clipboard",
|
title: "Link Copied Successfully",
|
||||||
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Some error occurred",
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -104,9 +104,9 @@ export const SingleModuleCard: React.FC<Props> = ({ module, handleEditModule })
|
|||||||
`${originURL}/${workspaceSlug}/projects/${projectId}/modules/${module.id}`
|
`${originURL}/${workspaceSlug}/projects/${projectId}/modules/${module.id}`
|
||||||
).then(() => {
|
).then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Link Copied!",
|
title: "Link Copied Successfully",
|
||||||
message: "Module link copied to clipboard.",
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -265,9 +265,9 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, index
|
|||||||
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${block.issue}`
|
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${block.issue}`
|
||||||
).then(() => {
|
).then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Link Copied!",
|
title: "Link Copied Successfully",
|
||||||
message: "Issue link copied to clipboard.",
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -57,9 +57,9 @@ export const SinglePageDetailedItem: React.FC<TSingleStatProps> = ({
|
|||||||
`${originURL}/${workspaceSlug}/projects/${projectId}/pages/${page.id}`
|
`${originURL}/${workspaceSlug}/projects/${projectId}/pages/${page.id}`
|
||||||
).then(() => {
|
).then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Link Copied!",
|
title: "Link Copied Successfully",
|
||||||
message: "Page link copied to clipboard.",
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -58,9 +58,9 @@ export const SinglePageListItem: React.FC<TSingleStatProps> = ({
|
|||||||
`${originURL}/${workspaceSlug}/projects/${projectId}/pages/${page.id}`
|
`${originURL}/${workspaceSlug}/projects/${projectId}/pages/${page.id}`
|
||||||
).then(() => {
|
).then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Link Copied!",
|
title: "Link Copied Successfully",
|
||||||
message: "Page link copied to clipboard.",
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -127,9 +127,9 @@ export const ProjectSidebarList: FC = () => {
|
|||||||
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||||
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues`).then(() => {
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues`).then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Link Copied!",
|
title: "Link Copied Successfully",
|
||||||
message: "Project link copied to clipboard.",
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -128,9 +128,9 @@ export const SingleProjectCard: React.FC<ProjectCardProps> = ({
|
|||||||
|
|
||||||
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${project.id}/issues`).then(() => {
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${project.id}/issues`).then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Link Copied!",
|
title: "Link Copied Successfully",
|
||||||
message: "Project link copied to clipboard.",
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
// hooks
|
// hooks
|
||||||
import {
|
|
||||||
CheckCircleIcon,
|
|
||||||
ExclamationTriangleIcon,
|
|
||||||
InformationCircleIcon,
|
|
||||||
XCircleIcon,
|
|
||||||
XMarkIcon,
|
|
||||||
} from "@heroicons/react/24/outline";
|
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// icons
|
// icons
|
||||||
|
import { LinkIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||||
|
import { ErrorIcon, SuccessIcon } from "components/icons";
|
||||||
|
|
||||||
const ToastAlerts = () => {
|
const ToastAlerts = () => {
|
||||||
const { alerts, removeAlert } = useToast();
|
const { alerts, removeAlert } = useToast();
|
||||||
@ -16,48 +11,60 @@ const ToastAlerts = () => {
|
|||||||
if (!alerts) return null;
|
if (!alerts) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pointer-events-none fixed top-5 right-5 z-50 h-full w-80 space-y-5 overflow-hidden">
|
<div className="pointer-events-none fixed top-5 right-5 z-50 h-full w-96 space-y-5 overflow-hidden rounded-md">
|
||||||
{alerts.map((alert) => (
|
{alerts.map((alert) => (
|
||||||
<div className="relative overflow-hidden rounded-md text-white" key={alert.id}>
|
<div
|
||||||
|
className="relative flex flex-col items-center justify-center gap-2 overflow-hidden rounded-md border-[2px] border-brand-surface-2 bg-brand-base px-4 py-3 text-sm text-brand-base shadow-md"
|
||||||
|
key={alert.id}
|
||||||
|
>
|
||||||
<div className="absolute top-1 right-1">
|
<div className="absolute top-1 right-1">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="pointer-events-auto inline-flex rounded-md p-1.5 focus:outline-none focus:ring-2 focus:ring-offset-2"
|
className="pointer-events-auto inline-flex rounded-md p-1.5 text-brand-secondary"
|
||||||
onClick={() => removeAlert(alert.id)}
|
onClick={() => removeAlert(alert.id)}
|
||||||
>
|
>
|
||||||
<span className="sr-only">Dismiss</span>
|
<span className="sr-only">Dismiss</span>
|
||||||
<XMarkIcon className="h-5 w-5" aria-hidden="true" />
|
<XMarkIcon className="h-4 w-4" aria-hidden="true" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
{alert.type !== "info" ? (
|
||||||
className={`px-2 py-4 ${
|
<>
|
||||||
alert.type === "success"
|
<div className="flex w-full items-center gap-2.5">
|
||||||
? "bg-[#06d6a0]"
|
|
||||||
: alert.type === "error"
|
|
||||||
? "bg-[#ef476f]"
|
|
||||||
: alert.type === "warning"
|
|
||||||
? "bg-[#e98601]"
|
|
||||||
: "bg-[#1B9aaa]"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-x-3">
|
|
||||||
<div className="flex-shrink-0">
|
|
||||||
{alert.type === "success" ? (
|
{alert.type === "success" ? (
|
||||||
<CheckCircleIcon className="h-8 w-8" aria-hidden="true" />
|
<SuccessIcon className="h-4 w-4" />
|
||||||
) : alert.type === "error" ? (
|
) : alert.type === "error" ? (
|
||||||
<XCircleIcon className="h-8 w-8" />
|
<ErrorIcon className="h-4 w-4" />
|
||||||
) : alert.type === "warning" ? (
|
|
||||||
<ExclamationTriangleIcon className="h-8 w-8" aria-hidden="true" />
|
|
||||||
) : (
|
) : (
|
||||||
<InformationCircleIcon className="h-8 w-8" />
|
""
|
||||||
)}
|
)}
|
||||||
|
<p
|
||||||
|
className={`font-medium ${
|
||||||
|
alert.type === "success"
|
||||||
|
? "text-brand-base"
|
||||||
|
: alert.type === "error"
|
||||||
|
? "text-[#ef476f]"
|
||||||
|
: alert.type === "warning"
|
||||||
|
? "text-[#e98601]"
|
||||||
|
: "text-[#1B9aaa]"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{alert.title}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex w-full items-center justify-start text-brand-secondary">
|
||||||
<p className="font-semibold">{alert.title}</p>
|
<p className="text-left">{alert.message}</p>
|
||||||
{alert.message && <p className="mt-1 text-xs">{alert.message}</p>}
|
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="flex w-full items-center justify-center gap-2.5 py-2 text-brand-secondary">
|
||||||
|
{alert.iconType === "copy" && (
|
||||||
|
<span>
|
||||||
|
<LinkIcon className="h-4 w-4" />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<p className="font-medium italic">{alert.title}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,6 +12,7 @@ type ToastAlert = {
|
|||||||
title: string;
|
title: string;
|
||||||
message?: string;
|
message?: string;
|
||||||
type: "success" | "error" | "warning" | "info";
|
type: "success" | "error" | "warning" | "info";
|
||||||
|
iconType?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ReducerActionType = {
|
type ReducerActionType = {
|
||||||
@ -26,6 +27,7 @@ type ContextType = {
|
|||||||
title: string;
|
title: string;
|
||||||
type?: "success" | "error" | "warning" | "info" | undefined;
|
type?: "success" | "error" | "warning" | "info" | undefined;
|
||||||
message?: string | undefined;
|
message?: string | undefined;
|
||||||
|
iconType?: string | undefined;
|
||||||
}) => void;
|
}) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ export const ToastContextProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||||||
const removeAlert = useCallback((id: string) => {
|
const removeAlert = useCallback((id: string) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "REMOVE_TOAST_ALERT",
|
type: "REMOVE_TOAST_ALERT",
|
||||||
payload: { id, title: "", message: "", type: "success" },
|
payload: { id, title: "", message: "", type: "success", iconType: "" },
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -76,12 +78,13 @@ export const ToastContextProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||||||
title: string;
|
title: string;
|
||||||
type?: "success" | "error" | "warning" | "info";
|
type?: "success" | "error" | "warning" | "info";
|
||||||
message?: string;
|
message?: string;
|
||||||
|
iconType?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const id = uuid();
|
const id = uuid();
|
||||||
const { title, type, message } = data;
|
const { title, type, message, iconType } = data;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "SET_TOAST_ALERT",
|
type: "SET_TOAST_ALERT",
|
||||||
payload: { id, title, message, type: type ?? "success" },
|
payload: { id, title, message, type: type ?? "success", iconType },
|
||||||
});
|
});
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
|
@ -7,6 +7,8 @@ import useSWR, { mutate } from "swr";
|
|||||||
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
// hooks
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// services
|
// services
|
||||||
import issuesService from "services/issues.service";
|
import issuesService from "services/issues.service";
|
||||||
// layouts
|
// layouts
|
||||||
@ -50,6 +52,8 @@ const IssueDetailsPage: NextPage = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, issueId } = router.query;
|
const { workspaceSlug, projectId, issueId } = router.query;
|
||||||
|
|
||||||
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const { data: issueDetails, mutate: mutateIssueDetails } = useSWR<IIssue | undefined>(
|
const { data: issueDetails, mutate: mutateIssueDetails } = useSWR<IIssue | undefined>(
|
||||||
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
|
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
|
||||||
workspaceSlug && projectId && issueId
|
workspaceSlug && projectId && issueId
|
||||||
@ -93,9 +97,19 @@ const IssueDetailsPage: NextPage = () => {
|
|||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutateIssueDetails();
|
mutateIssueDetails();
|
||||||
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Success",
|
||||||
|
message: "Issue updated successfully.",
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[workspaceSlug, issueId, projectId, mutateIssueDetails]
|
[workspaceSlug, issueId, projectId, mutateIssueDetails]
|
||||||
|
@ -247,9 +247,9 @@ const SinglePage: NextPage = () => {
|
|||||||
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/pages/${pageId}`).then(
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/pages/${pageId}`).then(
|
||||||
() => {
|
() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "info",
|
||||||
title: "Link Copied!",
|
title: "Link Copied Successfully",
|
||||||
message: "Page link copied to clipboard.",
|
iconType: "copy",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user