Skip to content

Commit

Permalink
Merge branch 'develop' into feat/platform-environments
Browse files Browse the repository at this point in the history
  • Loading branch information
rajdip-b authored Jan 28, 2025
2 parents ddf211c + d243c89 commit 191feaa
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 36 deletions.
67 changes: 37 additions & 30 deletions apps/platform/src/app/(main)/page.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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<boolean>(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: (
<p className="text-xs text-red-300">
Something went wrong while fetching projects. Check console for
more info.
</p>
)
})
// 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: (
<p className="text-xs text-red-300">
Something went wrong while fetching projects. Check console for
more info.
</p>
)
})
// 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 (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between">
Expand Down Expand Up @@ -94,6 +97,10 @@ export default function Index(): JSX.Element {
</div>
)}

{isDeleteProjectOpen && selectedProject ? (
<ConfirmDeleteProject reCallGetAllProjects={getAllProjects} />
) : null}

<EditProjectSheet />
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -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: (
<p className="text-xs text-red-300">
No project selected. Please select a project.
</p>
)
})
return
}

const projectSlug = selectedProject.slug

const { success, error } =
await ControllerInstance.getInstance().projectController.deleteProject(
{ projectSlug },
{}
)

if (success) {
toast.success('Project deleted successfully', {
description: (
<p className="text-xs text-emerald-300">
The project has been deleted.
</p>
)
})
reCallGetAllProjects()
}

if (error) {
toast.error('Something went wrong!', {
description: (
<p className="text-xs text-red-300">
Something went wrong while deleting the project. Check console for
more info.
</p>
)
})
// 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 (
<AlertDialog
aria-hidden={!isDeleteProjectOpen}
onOpenChange={handleClose}
open={isDeleteProjectOpen}
>
<AlertDialogContent className="rounded-lg border border-white/25 bg-[#18181B] ">
<AlertDialogHeader>
<div className="flex items-center gap-x-3">
<TrashSVG />
<AlertDialogTitle className="text-lg font-semibold">
Do you really want to delete project {selectedProject?.name} ?
</AlertDialogTitle>
</div>
<AlertDialogDescription className="text-sm font-normal leading-5 text-[#71717A]">
This action cannot be undone. This will permanently delete your
project and remove your project data from our servers.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel
className="rounded-md bg-[#F4F4F5] text-black hover:bg-[#F4F4F5]/80 hover:text-black"
onClick={handleClose}
>
Cancel
</AlertDialogCancel>
<AlertDialogAction
className="rounded-md bg-[#DC2626] text-white hover:bg-[#DC2626]/80"
onClick={deleteProject}
>
Yes, delete the project
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}

export default ConfirmDeleteProject
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.')
})
Expand All @@ -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 {
Expand All @@ -65,6 +71,11 @@ export default function ProjectCard({
}
}

const handleDeleteProject = () => {
setSelectedVariable(project)
setIsDeleteProjectOpen(true)
}

return (
<ContextMenu>
<ContextMenuTrigger className="flex h-[7rem]">
Expand Down Expand Up @@ -102,10 +113,10 @@ export default function ProjectCard({
</Link>
</ContextMenuTrigger>
<ContextMenuContent className="w-64">
<Link href={`/project/${name}`}>
<Link href={`/project/${slug}`}>
<ContextMenuItem inset>Open</ContextMenuItem>
</Link>
<a href={`/project/${name}`} rel="noopener noreferrer" target="_blank">
<a href={`/project/${slug}`} rel="noopener noreferrer" target="_blank">
<ContextMenuItem inset>Open in new tab</ContextMenuItem>
</a>
<ContextMenuSeparator className="bg-white/15" />
Expand All @@ -126,7 +137,9 @@ export default function ProjectCard({
>
Edit
</ContextMenuItem>
<ContextMenuItem inset>Delete</ContextMenuItem>
<ContextMenuItem inset onClick={handleDeleteProject}>
Delete
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
)
Expand Down

0 comments on commit 191feaa

Please sign in to comment.