[WEB-570] chore: toast refactor (#3836)

* new toast setup

* chore: new toast implementation.

* chore: move toast component to ui package.

* chore: replace `setToast` with `setPromiseToast` in required places for better UX.
* chore: code cleanup.

* chore: update theme.

* fix: theme switching issue.

* chore: remove toast from issue update operations.

* chore: add promise toast for add/ remove issue to cycle/ module and remove local spinners.

---------

Co-authored-by: rahulramesha <rahulramesham@gmail.com>
This commit is contained in:
Prateek Shourya 2024-03-06 14:18:41 +05:30 committed by GitHub
parent c06ef4d1d7
commit 53367a6bc4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
167 changed files with 1827 additions and 1896 deletions

View file

@ -4,9 +4,8 @@ import { Dialog, Transition } from "@headlessui/react";
import { observer } from "mobx-react-lite";
// hooks
import { useEventTracker, useModule } from "hooks/store";
import useToast from "hooks/use-toast";
// ui
import { Button } from "@plane/ui";
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
// icons
import { AlertTriangle } from "lucide-react";
// types
@ -30,8 +29,6 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
// store hooks
const { captureModuleEvent } = useEventTracker();
const { deleteModule } = useModule();
// toast alert
const { setToastAlert } = useToast();
const handleClose = () => {
onClose();
@ -47,8 +44,8 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
.then(() => {
if (moduleId || peekModule) router.push(`/${workspaceSlug}/projects/${data.project_id}/modules`);
handleClose();
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
message: "Module deleted successfully.",
});
@ -58,8 +55,8 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
});
})
.catch(() => {
setToastAlert({
type: "error",
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Module could not be deleted. Please try again.",
});

View file

@ -4,7 +4,8 @@ import { useForm } from "react-hook-form";
import { Dialog, Transition } from "@headlessui/react";
// hooks
import { useEventTracker, useModule, useProject } from "hooks/store";
import useToast from "hooks/use-toast";
// ui
import { TOAST_TYPE, setToast } from "@plane/ui";
// components
import { ModuleForm } from "components/modules";
// types
@ -36,8 +37,6 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
const { captureModuleEvent } = useEventTracker();
const { workspaceProjectIds } = useProject();
const { createModule, updateModuleDetails } = useModule();
// toast alert
const { setToastAlert } = useToast();
const handleClose = () => {
reset(defaultValues);
@ -55,8 +54,8 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
await createModule(workspaceSlug.toString(), selectedProjectId, payload)
.then((res) => {
handleClose();
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
message: "Module created successfully.",
});
@ -66,8 +65,8 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
});
})
.catch((err) => {
setToastAlert({
type: "error",
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: err.detail ?? "Module could not be created. Please try again.",
});
@ -86,8 +85,8 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
.then((res) => {
handleClose();
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
message: "Module updated successfully.",
});
@ -97,8 +96,8 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
});
})
.catch((err) => {
setToastAlert({
type: "error",
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: err.detail ?? "Module could not be updated. Please try again.",
});

View file

@ -5,11 +5,10 @@ import { observer } from "mobx-react-lite";
import { Info, LinkIcon, Pencil, Star, Trash2 } from "lucide-react";
// hooks
import { useEventTracker, useMember, useModule, useUser } from "hooks/store";
import useToast from "hooks/use-toast";
// components
import { CreateUpdateModuleModal, DeleteModuleModal } from "components/modules";
// ui
import { Avatar, AvatarGroup, CustomMenu, LayersIcon, Tooltip } from "@plane/ui";
import { Avatar, AvatarGroup, CustomMenu, LayersIcon, Tooltip, TOAST_TYPE, setToast, setPromiseToast } from "@plane/ui";
// helpers
import { copyUrlToClipboard } from "helpers/string.helper";
import { renderFormattedDate } from "helpers/date-time.helper";
@ -30,8 +29,6 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
// router
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
// toast alert
const { setToastAlert } = useToast();
// store hooks
const {
membership: { currentProjectRole },
@ -48,21 +45,27 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
e.preventDefault();
if (!workspaceSlug || !projectId) return;
addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId)
.then(() => {
const addToFavoritePromise = addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId).then(
() => {
captureEvent(MODULE_FAVORITED, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
});
})
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "Couldn't add the module to favorites. Please try again.",
});
});
}
);
setPromiseToast(addToFavoritePromise, {
loading: "Adding module to favorites...",
success: {
title: "Success!",
message: () => "Module added to favorites.",
},
error: {
title: "Error!",
message: () => "Couldn't add the module to favorites. Please try again.",
},
});
};
const handleRemoveFromFavorites = (e: React.MouseEvent<HTMLButtonElement>) => {
@ -70,29 +73,37 @@ export const ModuleCardItem: React.FC<Props> = observer((props) => {
e.preventDefault();
if (!workspaceSlug || !projectId) return;
removeModuleFromFavorites(workspaceSlug.toString(), projectId.toString(), moduleId)
.then(() => {
captureEvent(MODULE_UNFAVORITED, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
});
})
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "Couldn't remove the module from favorites. Please try again.",
});
const removeFromFavoritePromise = removeModuleFromFavorites(
workspaceSlug.toString(),
projectId.toString(),
moduleId
).then(() => {
captureEvent(MODULE_UNFAVORITED, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
});
});
setPromiseToast(removeFromFavoritePromise, {
loading: "Removing module from favorites...",
success: {
title: "Success!",
message: () => "Module removed from favorites.",
},
error: {
title: "Error!",
message: () => "Couldn't remove the module from favorites. Please try again.",
},
});
};
const handleCopyText = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
e.preventDefault();
copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/modules/${moduleId}`).then(() => {
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Link Copied!",
message: "Module link copied to clipboard.",
});

View file

@ -5,11 +5,19 @@ import { observer } from "mobx-react-lite";
import { Check, Info, LinkIcon, Pencil, Star, Trash2, User2 } from "lucide-react";
// hooks
import { useModule, useUser, useEventTracker, useMember } from "hooks/store";
import useToast from "hooks/use-toast";
// components
import { CreateUpdateModuleModal, DeleteModuleModal } from "components/modules";
// ui
import { Avatar, AvatarGroup, CircularProgressIndicator, CustomMenu, Tooltip } from "@plane/ui";
import {
Avatar,
AvatarGroup,
CircularProgressIndicator,
CustomMenu,
Tooltip,
TOAST_TYPE,
setToast,
setPromiseToast,
} from "@plane/ui";
// helpers
import { copyUrlToClipboard } from "helpers/string.helper";
import { renderFormattedDate } from "helpers/date-time.helper";
@ -30,8 +38,6 @@ export const ModuleListItem: React.FC<Props> = observer((props) => {
// router
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
// toast alert
const { setToastAlert } = useToast();
// store hooks
const {
membership: { currentProjectRole },
@ -48,21 +54,27 @@ export const ModuleListItem: React.FC<Props> = observer((props) => {
e.preventDefault();
if (!workspaceSlug || !projectId) return;
addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId)
.then(() => {
const addToFavoritePromise = addModuleToFavorites(workspaceSlug.toString(), projectId.toString(), moduleId).then(
() => {
captureEvent(MODULE_FAVORITED, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
});
})
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "Couldn't add the module to favorites. Please try again.",
});
});
}
);
setPromiseToast(addToFavoritePromise, {
loading: "Adding module to favorites...",
success: {
title: "Success!",
message: () => "Module added to favorites.",
},
error: {
title: "Error!",
message: () => "Couldn't add the module to favorites. Please try again.",
},
});
};
const handleRemoveFromFavorites = (e: React.MouseEvent<HTMLButtonElement>) => {
@ -70,29 +82,37 @@ export const ModuleListItem: React.FC<Props> = observer((props) => {
e.preventDefault();
if (!workspaceSlug || !projectId) return;
removeModuleFromFavorites(workspaceSlug.toString(), projectId.toString(), moduleId)
.then(() => {
captureEvent(MODULE_UNFAVORITED, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
});
})
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "Couldn't remove the module from favorites. Please try again.",
});
const removeFromFavoritePromise = removeModuleFromFavorites(
workspaceSlug.toString(),
projectId.toString(),
moduleId
).then(() => {
captureEvent(MODULE_UNFAVORITED, {
module_id: moduleId,
element: "Grid layout",
state: "SUCCESS",
});
});
setPromiseToast(removeFromFavoritePromise, {
loading: "Removing module from favorites...",
success: {
title: "Success!",
message: () => "Module removed from favorites.",
},
error: {
title: "Error!",
message: () => "Couldn't remove the module from favorites. Please try again.",
},
});
};
const handleCopyText = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
e.preventDefault();
copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/modules/${moduleId}`).then(() => {
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Link Copied!",
message: "Module link copied to clipboard.",
});

View file

@ -16,14 +16,22 @@ import {
} from "lucide-react";
// hooks
import { useModule, useUser, useEventTracker } from "hooks/store";
import useToast from "hooks/use-toast";
// components
import { LinkModal, LinksList, SidebarProgressStats } from "components/core";
import { DeleteModuleModal } from "components/modules";
import ProgressChart from "components/core/sidebar/progress-chart";
import { DateRangeDropdown, MemberDropdown } from "components/dropdowns";
// ui
import { CustomMenu, Loader, LayersIcon, CustomSelect, ModuleStatusIcon, UserGroupIcon } from "@plane/ui";
import {
CustomMenu,
Loader,
LayersIcon,
CustomSelect,
ModuleStatusIcon,
UserGroupIcon,
TOAST_TYPE,
setToast,
} from "@plane/ui";
// helpers
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
import { copyUrlToClipboard } from "helpers/string.helper";
@ -65,8 +73,6 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
const { setTrackElement, captureModuleEvent, captureEvent } = useEventTracker();
const moduleDetails = getModuleById(moduleId);
const { setToastAlert } = useToast();
const { reset, control } = useForm({
defaultValues,
});
@ -99,15 +105,15 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
module_id: moduleId,
state: "SUCCESS",
});
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Module link created",
message: "Module link created successfully.",
});
})
.catch(() => {
setToastAlert({
type: "error",
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Some error occurred",
});
@ -125,15 +131,15 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
module_id: moduleId,
state: "SUCCESS",
});
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Module link updated",
message: "Module link updated successfully.",
});
})
.catch(() => {
setToastAlert({
type: "error",
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Some error occurred",
});
@ -149,15 +155,15 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
module_id: moduleId,
state: "SUCCESS",
});
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Module link deleted",
message: "Module link deleted successfully.",
});
})
.catch(() => {
setToastAlert({
type: "error",
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Some error occurred",
});
@ -167,15 +173,15 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
const handleCopyText = () => {
copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/modules/${moduleId}`)
.then(() => {
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Link copied",
message: "Module link copied to clipboard",
});
})
.catch(() => {
setToastAlert({
type: "error",
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Some error occurred",
});
@ -187,8 +193,8 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
start_date: startDate ? renderFormattedPayloadDate(startDate) : null,
target_date: targetDate ? renderFormattedPayloadDate(targetDate) : null,
});
setToastAlert({
type: "success",
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
message: "Module updated successfully.",
});