diff --git a/apps/platform/src/app/(main)/page.tsx b/apps/platform/src/app/(main)/page.tsx index d2500762..307aff6d 100644 --- a/apps/platform/src/app/(main)/page.tsx +++ b/apps/platform/src/app/(main)/page.tsx @@ -1,5 +1,5 @@ 'use client' -import { useEffect, useMemo, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import type { GetAllProjectsResponse } from '@keyshade/schema' import { FolderSVG } from '@public/svg/dashboard' import { toast } from 'sonner' @@ -11,56 +11,59 @@ import CreateProjectDialogue from '@/components/dashboard/project/createProjectD import { createProjectOpenAtom, selectedWorkspaceAtom, - projectsOfWorkspaceAtom + projectsOfWorkspaceAtom, + deleteProjectOpenAtom, + selectedProjectAtom } from '@/store' import EditProjectSheet from '@/components/dashboard/project/editProjectSheet' import { Button } from '@/components/ui/button' +import ConfirmDeleteProject from '@/components/dashboard/project/confirmDeleteProject' export default function Index(): JSX.Element { const [loading, setLoading] = useState(false) const setIsCreateProjectDialogOpen = useSetAtom(createProjectOpenAtom) const selectedWorkspace = useAtomValue(selectedWorkspaceAtom) + const isDeleteProjectOpen = useAtomValue(deleteProjectOpenAtom) + const selectedProject = useAtomValue(selectedProjectAtom) // Projects to be displayed in the dashboard const [projects, setProjects] = useAtom(projectsOfWorkspaceAtom) const isProjectsEmpty = useMemo(() => projects.length === 0, [projects]) - // If a workspace is selected, we want to fetch all the projects - // under that workspace and display it in the dashboard. - useEffect(() => { - async function getAllProjects() { - setLoading(true) + const getAllProjects = useCallback(async () => { + setLoading(true) - if (selectedWorkspace) { - const { success, error, data } = - await ControllerInstance.getInstance().projectController.getAllProjects( - { workspaceSlug: selectedWorkspace.slug }, - {} - ) + if (selectedWorkspace) { + const { success, error, data } = + await ControllerInstance.getInstance().projectController.getAllProjects( + { workspaceSlug: selectedWorkspace.slug }, + {} + ) - if (success && data) { - setProjects(data.items) - } else { - toast.error('Something went wrong!', { - description: ( -

- Something went wrong while fetching projects. Check console for - more info. -

- ) - }) - // eslint-disable-next-line no-console -- we need to log the error - console.error(error) - } + if (success && data) { + setProjects(data.items) + } else { + toast.error('Something went wrong!', { + description: ( +

+ Something went wrong while fetching projects. Check console for + more info. +

+ ) + }) + // eslint-disable-next-line no-console -- we need to log the error + console.error(error) } - - setLoading(false) } - getAllProjects() + setLoading(false) }, [selectedWorkspace, setProjects]) + useEffect(() => { + getAllProjects() + }, [getAllProjects, selectedWorkspace, setProjects]) + return (
@@ -94,6 +97,10 @@ export default function Index(): JSX.Element {
)} + {isDeleteProjectOpen && selectedProject ? ( + + ) : null} +
) diff --git a/apps/platform/src/components/dashboard/project/confirmDeleteProject/index.tsx b/apps/platform/src/components/dashboard/project/confirmDeleteProject/index.tsx new file mode 100644 index 00000000..860511d4 --- /dev/null +++ b/apps/platform/src/components/dashboard/project/confirmDeleteProject/index.tsx @@ -0,0 +1,133 @@ +import { TrashSVG } from '@public/svg/shared' +import { useAtom, useAtomValue } from 'jotai' +import React, { useCallback, useEffect } from 'react' +import { toast } from 'sonner' +import { deleteProjectOpenAtom, selectedProjectAtom } from '@/store' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle +} from '@/components/ui/alert-dialog' +import ControllerInstance from '@/lib/controller-instance' + +interface ConfirmDeleteProjectProps { + reCallGetAllProjects: () => void +} + +function ConfirmDeleteProject({ + reCallGetAllProjects +}: ConfirmDeleteProjectProps): React.JSX.Element { + const [isDeleteProjectOpen, setIsDeleteProjectOpen] = useAtom( + deleteProjectOpenAtom + ) + const selectedProject = useAtomValue(selectedProjectAtom) + + const handleClose = () => { + setIsDeleteProjectOpen(false) + } + + const deleteProject = async () => { + if (selectedProject === null) { + toast.error('No project selected', { + description: ( +

+ No project selected. Please select a project. +

+ ) + }) + return + } + + const projectSlug = selectedProject.slug + + const { success, error } = + await ControllerInstance.getInstance().projectController.deleteProject( + { projectSlug }, + {} + ) + + if (success) { + toast.success('Project deleted successfully', { + description: ( +

+ The project has been deleted. +

+ ) + }) + reCallGetAllProjects() + } + + if (error) { + toast.error('Something went wrong!', { + description: ( +

+ Something went wrong while deleting the project. Check console for + more info. +

+ ) + }) + // eslint-disable-next-line no-console -- we need to log the error + console.error(error) + } + + handleClose() + } + + //Cleaning the pointer events for the context menu after closing the alert dialog + // if we don't do this the pointer events will be disabled for the whole page + const cleanup = useCallback(() => { + document.body.style.pointerEvents = '' + document.documentElement.style.pointerEvents = '' + }, []) + + useEffect(() => { + if (!isDeleteProjectOpen) { + cleanup() + } + return () => cleanup() + }, [isDeleteProjectOpen, cleanup]) + + return ( + + + +
+ + + Do you really want to delete project {selectedProject?.name} ? + +
+ + This action cannot be undone. This will permanently delete your + project and remove your project data from our servers. + +
+ + + Cancel + + + Yes, delete the project + + +
+
+ ) +} + +export default ConfirmDeleteProject diff --git a/apps/platform/src/components/dashboard/project/projectCard/index.tsx b/apps/platform/src/components/dashboard/project/projectCard/index.tsx index b7830dce..39047dc8 100644 --- a/apps/platform/src/components/dashboard/project/projectCard/index.tsx +++ b/apps/platform/src/components/dashboard/project/projectCard/index.tsx @@ -12,7 +12,11 @@ import { ContextMenuSeparator, ContextMenuTrigger } from '@/components/ui/context-menu' -import { editProjectOpenAtom } from '@/store' +import { + deleteProjectOpenAtom, + editProjectOpenAtom, + selectedProjectAtom +} from '@/store' interface ProjectCardProps { project: ProjectWithCount @@ -32,12 +36,14 @@ export default function ProjectCard({ } = project const setIsEditProjectSheetOpen = useSetAtom(editProjectOpenAtom) + const setIsDeleteProjectOpen = useSetAtom(deleteProjectOpenAtom) + const setSelectedVariable = useSetAtom(selectedProjectAtom) const copyToClipboard = (): void => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- navigator.clipboard is checked if (navigator.clipboard) { navigator.clipboard - .writeText(`${window.location.origin}/project/${name}`) + .writeText(`${window.location.origin}/project/${slug}`) .then(() => { toast.success('Link has been copied to clipboard.') }) @@ -51,7 +57,7 @@ export default function ProjectCard({ console.log('Clipboard API not supported') const textarea = document.createElement('textarea') - textarea.value = `${window.location.origin}/project/${name}` + textarea.value = `${window.location.origin}/project/${slug}` document.body.appendChild(textarea) textarea.select() try { @@ -65,6 +71,11 @@ export default function ProjectCard({ } } + const handleDeleteProject = () => { + setSelectedVariable(project) + setIsDeleteProjectOpen(true) + } + return ( @@ -102,10 +113,10 @@ export default function ProjectCard({ - + Open - + Open in new tab @@ -126,7 +137,9 @@ export default function ProjectCard({ > Edit - Delete + + Delete + )