From 51a0bc0e36421d250f38a2dad73b23c82af190f0 Mon Sep 17 00:00:00 2001 From: gakshita Date: Tue, 11 Feb 2025 12:49:27 +0530 Subject: [PATCH 1/3] fix: code splitting for delete modal --- .../workspace/delete-workspace-modal.tsx | 27 +++ .../workspace/delete-workspace-section.tsx | 2 +- .../workspace/delete-workspace-form.tsx | 173 +++++++++++++++ .../workspace/delete-workspace-modal.tsx | 205 ------------------ web/core/components/workspace/index.ts | 1 - .../workspace/delete-workspace-modal.tsx | 1 + 6 files changed, 202 insertions(+), 207 deletions(-) create mode 100644 web/ce/components/workspace/delete-workspace-modal.tsx create mode 100644 web/core/components/workspace/delete-workspace-form.tsx delete mode 100644 web/core/components/workspace/delete-workspace-modal.tsx create mode 100644 web/ee/components/workspace/delete-workspace-modal.tsx diff --git a/web/ce/components/workspace/delete-workspace-modal.tsx b/web/ce/components/workspace/delete-workspace-modal.tsx new file mode 100644 index 00000000000..cccee781fc5 --- /dev/null +++ b/web/ce/components/workspace/delete-workspace-modal.tsx @@ -0,0 +1,27 @@ +"use client"; + +import React from "react"; +import { observer } from "mobx-react"; +import type { IWorkspace } from "@plane/types"; +// ui +import { EModalPosition, EModalWidth, ModalCore } from "@plane/ui"; +// constants +// hooks + +import { DeleteWorkspaceForm } from "@/components/workspace/delete-workspace-form"; + +type Props = { + isOpen: boolean; + data: IWorkspace | null; + onClose: () => void; +}; + +export const DeleteWorkspaceModal: React.FC = observer((props) => { + const { isOpen, data, onClose } = props; + + return ( + onClose()} position={EModalPosition.CENTER} width={EModalWidth.XL}> + + + ); +}); diff --git a/web/ce/components/workspace/delete-workspace-section.tsx b/web/ce/components/workspace/delete-workspace-section.tsx index 81fc754593f..00fb7b87891 100644 --- a/web/ce/components/workspace/delete-workspace-section.tsx +++ b/web/ce/components/workspace/delete-workspace-section.tsx @@ -6,8 +6,8 @@ import { useTranslation } from "@plane/i18n"; import { IWorkspace } from "@plane/types"; // ui import { Button, Collapsible } from "@plane/ui"; +import { DeleteWorkspaceModal } from "./delete-workspace-modal"; // components -import { DeleteWorkspaceModal } from "@/components/workspace"; type TDeleteWorkspace = { workspace: IWorkspace | null; diff --git a/web/core/components/workspace/delete-workspace-form.tsx b/web/core/components/workspace/delete-workspace-form.tsx new file mode 100644 index 00000000000..8baa953cb20 --- /dev/null +++ b/web/core/components/workspace/delete-workspace-form.tsx @@ -0,0 +1,173 @@ +"use client"; + +import React from "react"; +import { observer } from "mobx-react"; +import { Controller, useForm } from "react-hook-form"; +import { AlertTriangle } from "lucide-react"; +// types +import { WORKSPACE_DELETED } from "@plane/constants"; +import type { IWorkspace } from "@plane/types"; +// ui +import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui"; +// constants +// hooks +import { cn } from "@plane/utils"; +import { useEventTracker, useWorkspace } from "@/hooks/store"; +import { useAppRouter } from "@/hooks/use-app-router"; + +type Props = { + data: IWorkspace | null; + onClose: () => void; +}; + +const defaultValues = { + workspaceName: "", + confirmDelete: "", +}; + +export const DeleteWorkspaceForm: React.FC = observer((props) => { + const { data, onClose } = props; + // router + const router = useAppRouter(); + // store hooks + const { captureWorkspaceEvent } = useEventTracker(); + const { deleteWorkspace } = useWorkspace(); + // form info + const { + control, + formState: { errors, isSubmitting }, + handleSubmit, + reset, + watch, + } = useForm({ defaultValues }); + + const canDelete = watch("workspaceName") === data?.name && watch("confirmDelete") === "delete my workspace"; + + const handleClose = () => { + const timer = setTimeout(() => { + reset(defaultValues); + clearTimeout(timer); + }, 350); + + onClose(); + }; + + const onSubmit = async () => { + if (!data || !canDelete) return; + + await deleteWorkspace(data.slug) + .then(() => { + handleClose(); + router.push("/"); + captureWorkspaceEvent({ + eventName: WORKSPACE_DELETED, + payload: { + ...data, + state: "SUCCESS", + element: "Workspace general settings page", + }, + }); + setToast({ + type: TOAST_TYPE.SUCCESS, + title: "Workspace deleted.", + message: "You will soon go to the next workspace or your profile page.", + }); + }) + .catch(() => { + setToast({ + type: TOAST_TYPE.ERROR, + title: "That didn't work.", + message: "Try again, please.", + }); + captureWorkspaceEvent({ + eventName: WORKSPACE_DELETED, + payload: { + ...data, + state: "FAILED", + element: "Workspace general settings page", + }, + }); + }); + }; + + return ( +
+
+ + +
+
+

Are you sure you want to delete this workspace?

+

+ You are about to delete the workspace {data?.name}. If + you confirm, you will lose access to all your work data in this workspace without any way to restore it. + Tread very carefully. +

+
+ +
+

Type in this workspace's name to continue.

+ ( + + )} + /> +
+ +
+

+ For final confirmation, type{" "} + delete my workspace + below. +

+ ( + + )} + /> +
+
+
+ +
+ + +
+
+ ); +}); diff --git a/web/core/components/workspace/delete-workspace-modal.tsx b/web/core/components/workspace/delete-workspace-modal.tsx deleted file mode 100644 index 62ff1c3098a..00000000000 --- a/web/core/components/workspace/delete-workspace-modal.tsx +++ /dev/null @@ -1,205 +0,0 @@ -"use client"; - -import React from "react"; -import { observer } from "mobx-react"; -import { Controller, useForm } from "react-hook-form"; -import { AlertTriangle } from "lucide-react"; -import { Dialog, Transition } from "@headlessui/react"; -// types -import { WORKSPACE_DELETED } from "@plane/constants"; -import type { IWorkspace } from "@plane/types"; -// ui -import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui"; -// constants -// hooks -import { useEventTracker, useWorkspace } from "@/hooks/store"; -import { useAppRouter } from "@/hooks/use-app-router"; - -type Props = { - isOpen: boolean; - data: IWorkspace | null; - onClose: () => void; -}; - -const defaultValues = { - workspaceName: "", - confirmDelete: "", -}; - -export const DeleteWorkspaceModal: React.FC = observer((props) => { - const { isOpen, data, onClose } = props; - // router - const router = useAppRouter(); - // store hooks - const { captureWorkspaceEvent } = useEventTracker(); - const { deleteWorkspace } = useWorkspace(); - // form info - const { - control, - formState: { errors, isSubmitting }, - handleSubmit, - reset, - watch, - } = useForm({ defaultValues }); - - const canDelete = watch("workspaceName") === data?.name && watch("confirmDelete") === "delete my workspace"; - - const handleClose = () => { - const timer = setTimeout(() => { - reset(defaultValues); - clearTimeout(timer); - }, 350); - - onClose(); - }; - - const onSubmit = async () => { - if (!data || !canDelete) return; - - await deleteWorkspace(data.slug) - .then(() => { - handleClose(); - router.push("/"); - captureWorkspaceEvent({ - eventName: WORKSPACE_DELETED, - payload: { - ...data, - state: "SUCCESS", - element: "Workspace general settings page", - }, - }); - setToast({ - type: TOAST_TYPE.SUCCESS, - title: "Success!", - message: "Workspace deleted successfully.", - }); - }) - .catch(() => { - setToast({ - type: TOAST_TYPE.ERROR, - title: "Error!", - message: "Something went wrong. Please try again later.", - }); - captureWorkspaceEvent({ - eventName: WORKSPACE_DELETED, - payload: { - ...data, - state: "FAILED", - element: "Workspace general settings page", - }, - }); - }); - }; - - return ( - - - -
- - -
-
- - -
-
- - - -

Delete workspace

-
-
- - -

- Are you sure you want to delete workspace{" "} - {data?.name}? All of the data related to the - workspace will be permanently removed. This action cannot be undone. -

-
- -
-

- Enter the workspace name {data?.name} to - continue: -

- ( - - )} - /> -
- -
-

- To confirm, type delete my workspace{" "} - below: -

- ( - - )} - /> -
- -
- - -
-
-
-
-
-
-
-
- ); -}); diff --git a/web/core/components/workspace/index.ts b/web/core/components/workspace/index.ts index a8f404d1b96..160370d4a6d 100644 --- a/web/core/components/workspace/index.ts +++ b/web/core/components/workspace/index.ts @@ -3,6 +3,5 @@ export * from "./sidebar"; export * from "./views"; export * from "./confirm-workspace-member-remove"; export * from "./create-workspace-form"; -export * from "./delete-workspace-modal"; export * from "./logo"; export * from "./send-workspace-invitation-modal"; diff --git a/web/ee/components/workspace/delete-workspace-modal.tsx b/web/ee/components/workspace/delete-workspace-modal.tsx new file mode 100644 index 00000000000..ce6b9cccf20 --- /dev/null +++ b/web/ee/components/workspace/delete-workspace-modal.tsx @@ -0,0 +1 @@ +export * from "ce/components/workspace/delete-workspace-modal"; From 33829d07328a230be030c627385f89bddf04b3a1 Mon Sep 17 00:00:00 2001 From: gakshita Date: Tue, 11 Feb 2025 14:03:51 +0530 Subject: [PATCH 2/3] fix: redirected to profile post deletion --- web/core/components/workspace/delete-workspace-form.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/core/components/workspace/delete-workspace-form.tsx b/web/core/components/workspace/delete-workspace-form.tsx index 8baa953cb20..feceb86348b 100644 --- a/web/core/components/workspace/delete-workspace-form.tsx +++ b/web/core/components/workspace/delete-workspace-form.tsx @@ -58,7 +58,7 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => { await deleteWorkspace(data.slug) .then(() => { handleClose(); - router.push("/"); + router.push("/profile"); captureWorkspaceEvent({ eventName: WORKSPACE_DELETED, payload: { @@ -70,7 +70,7 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => { setToast({ type: TOAST_TYPE.SUCCESS, title: "Workspace deleted.", - message: "You will soon go to the next workspace or your profile page.", + message: "You will soon go to your profile page.", }); }) .catch(() => { From 342a89d3eb3a9ad316880666bc2c87238bb69eb6 Mon Sep 17 00:00:00 2001 From: gakshita Date: Wed, 12 Feb 2025 12:40:54 +0530 Subject: [PATCH 3/3] fix: translations --- .../i18n/src/locales/en/translations.json | 14 ++++++++++-- .../i18n/src/locales/es/translations.json | 16 +++++++++++--- .../i18n/src/locales/fr/translations.json | 16 +++++++++++--- .../i18n/src/locales/ja/translations.json | 16 +++++++++++--- .../i18n/src/locales/zh-CN/translations.json | 16 +++++++++++--- .../workspace/delete-workspace-form.tsx | 22 +++++++++---------- 6 files changed, 74 insertions(+), 26 deletions(-) diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 32eb6b64f7a..2f097f00891 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -1253,9 +1253,19 @@ "company_size": "Company size", "url": "Workspace URL", "update_workspace": "Update workspace", - "delete_workspace": "Delete workspace", + "delete_workspace": "Delete this workspace", "delete_workspace_description": "When deleting a workspace, all of the data and resources within that workspace will be permanently removed and cannot be recovered.", - "delete_btn": "Delete my workspace", + "delete_btn": "Delete this workspace", + "delete_modal": { + "title": "Are you sure you want to delete this workspace?", + "description": "You have an active trial to one of our paid plans. Please cancel it first to proceed.", + "dismiss": "Dismiss", + "cancel": "Cancel trial", + "success_title": "Workspace deleted.", + "success_message": "You will soon go to your profile page.", + "error_title": "That didn't work.", + "error_message": "Try again, please." + }, "errors": { "name": { "required": "Name is required", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index c7a3da312dc..046c17cee71 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -1422,9 +1422,19 @@ "company_size": "Tamaño de la empresa", "url": "URL del espacio de trabajo", "update_workspace": "Actualizar espacio de trabajo", - "delete_workspace": "Eliminar espacio de trabajo", - "delete_workspace_description": "Al eliminar un espacio de trabajo, todos los datos y recursos dentro de ese espacio de trabajo se eliminarán permanentemente y no se podrán recuperar.", - "delete_btn": "Eliminar mi espacio de trabajo", + "delete_workspace": "Eliminar este espacio de trabajo", + "delete_workspace_description": "Al eliminar un espacio de trabajo, todos los datos y recursos dentro de ese espacio se eliminarán permanentemente y no podrán recuperarse.", + "delete_btn": "Eliminar este espacio de trabajo", + "delete_modal": { + "title": "¿Está seguro de que desea eliminar este espacio de trabajo?", + "description": "Tiene una prueba activa de uno de nuestros planes de pago. Por favor, cancelela primero para continuar.", + "dismiss": "Descartar", + "cancel": "Cancelar prueba", + "success_title": "Espacio de trabajo eliminado.", + "success_message": "Pronto irá a su página de perfil.", + "error_title": "Eso no funcionó.", + "error_message": "Por favor, inténtelo de nuevo." + }, "errors": { "name": { "required": "El nombre es obligatorio", diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 83b1b31db10..670a63f0454 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -1422,9 +1422,19 @@ "company_size": "Taille de l'entreprise", "url": "URL de l'espace de travail", "update_workspace": "Mettre à jour l'espace de travail", - "delete_workspace": "Supprimer l'espace de travail", - "delete_workspace_description": "Lors de la suppression d'un espace de travail, toutes les données et ressources au sein de cet espace de travail seront définitivement supprimées et ne pourront pas être récupérées.", - "delete_btn": "Supprimer mon espace de travail", + "delete_workspace": "Supprimer cet espace de travail", + "delete_workspace_description": "Lors de la suppression d'un espace de travail, toutes les données et ressources au sein de cet espace seront définitivement supprimées et ne pourront pas être récupérées.", + "delete_btn": "Supprimer cet espace de travail", + "delete_modal": { + "title": "Êtes-vous sûr de vouloir supprimer cet espace de travail ?", + "description": "Vous avez un essai actif sur l'un de nos forfaits payants. Veuillez d'abord l'annuler pour continuer.", + "dismiss": "Fermer", + "cancel": "Annuler l'essai", + "success_title": "Espace de travail supprimé.", + "success_message": "Vous serez bientôt redirigé vers votre page de profil.", + "error_title": "Cela n'a pas fonctionné.", + "error_message": "Veuillez réessayer." + }, "errors": { "name": { "required": "Le nom est requis", diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index d34a26aaaed..16b34ff7fb9 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -1422,9 +1422,19 @@ "company_size": "会社の規模", "url": "ワークスペースURL", "update_workspace": "ワークスペースを更新", - "delete_workspace": "ワークスペースを削除", - "delete_workspace_description": "ワークスペースを削除すると、そのワークスペース内のすべてのデータとリソースが永久に削除され、復元できなくなります。", - "delete_btn": "ワークスペースを削除", + "delete_workspace": "このワークスペースを削除", + "delete_workspace_description": "ワークスペースを削除すると、そのワークスペース内のすべてのデータとリソースが完全に削除され、復元することはできません。", + "delete_btn": "このワークスペースを削除", + "delete_modal": { + "title": "このワークスペースを削除してもよろしいですか?", + "description": "有料プランの無料トライアルが有効です。続行するには、まずトライアルをキャンセルしてください。", + "dismiss": "閉じる", + "cancel": "トライアルをキャンセル", + "success_title": "ワークスペースが削除されました。", + "success_message": "まもなくプロフィールページに移動します。", + "error_title": "操作に失敗しました。", + "error_message": "もう一度お試しください。" + }, "errors": { "name": { "required": "名前は必須です", diff --git a/packages/i18n/src/locales/zh-CN/translations.json b/packages/i18n/src/locales/zh-CN/translations.json index f715a21ae51..2f52c4793b4 100644 --- a/packages/i18n/src/locales/zh-CN/translations.json +++ b/packages/i18n/src/locales/zh-CN/translations.json @@ -1422,9 +1422,19 @@ "company_size": "公司规模", "url": "工作区网址", "update_workspace": "更新工作区", - "delete_workspace": "删除工作区", - "delete_workspace_description": "删除工作区时,该工作区内的所有数据和资源将被永久删除且无法恢复。", - "delete_btn": "删除我的工作区", + "delete_workspace": "删除此工作区", + "delete_workspace_description": "删除工作区时,该工作区内的所有数据和资源将被永久删除,且无法恢复。", + "delete_btn": "删除此工作区", + "delete_modal": { + "title": "确定要删除此工作区吗?", + "description": "您目前正在试用我们的付费方案。请先取消试用后再继续。", + "dismiss": "关闭", + "cancel": "取消试用", + "success_title": "工作区已删除。", + "success_message": "即将跳转到您的个人资料页面。", + "error_title": "操作失败。", + "error_message": "请重试。" + }, "errors": { "name": { "required": "名称为必填项", diff --git a/web/core/components/workspace/delete-workspace-form.tsx b/web/core/components/workspace/delete-workspace-form.tsx index feceb86348b..3697d8f360e 100644 --- a/web/core/components/workspace/delete-workspace-form.tsx +++ b/web/core/components/workspace/delete-workspace-form.tsx @@ -6,6 +6,7 @@ import { Controller, useForm } from "react-hook-form"; import { AlertTriangle } from "lucide-react"; // types import { WORKSPACE_DELETED } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import type { IWorkspace } from "@plane/types"; // ui import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui"; @@ -32,6 +33,7 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => { // store hooks const { captureWorkspaceEvent } = useEventTracker(); const { deleteWorkspace } = useWorkspace(); + const { t } = useTranslation(); // form info const { control, @@ -44,12 +46,8 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => { const canDelete = watch("workspaceName") === data?.name && watch("confirmDelete") === "delete my workspace"; const handleClose = () => { - const timer = setTimeout(() => { - reset(defaultValues); - clearTimeout(timer); - }, 350); - onClose(); + reset(defaultValues); }; const onSubmit = async () => { @@ -69,15 +67,15 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => { }); setToast({ type: TOAST_TYPE.SUCCESS, - title: "Workspace deleted.", - message: "You will soon go to your profile page.", + title: t("workspace_settings.settings.general.delete_modal.success_title"), + message: t("workspace_settings.settings.general.delete_modal.success_message"), }); }) .catch(() => { setToast({ type: TOAST_TYPE.ERROR, - title: "That didn't work.", - message: "Try again, please.", + title: t("workspace_settings.settings.general.delete_modal.error_title"), + message: t("workspace_settings.settings.general.delete_modal.error_message"), }); captureWorkspaceEvent({ eventName: WORKSPACE_DELETED, @@ -102,7 +100,7 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => {
-

Are you sure you want to delete this workspace?

+

{t("workspace_settings.settings.general.delete_modal.title")}

You are about to delete the workspace {data?.name}. If you confirm, you will lose access to all your work data in this workspace without any way to restore it. @@ -162,10 +160,10 @@ export const DeleteWorkspaceForm: React.FC = observer((props) => {