Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(platform): added workspace settings page #808

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6a6e853
feat(variableCard): Add copy slug functionality to variable card cont…
Allan2000-Git Feb 19, 2025
96e8b56
Merge branch 'develop' of https://github.com/Allan2000-Git/keyshade i…
Allan2000-Git Feb 21, 2025
64fcc54
Merge branch 'develop' of https://github.com/Allan2000-Git/keyshade i…
Allan2000-Git Feb 22, 2025
5a817d7
Merge branch 'develop' of https://github.com/Allan2000-Git/keyshade i…
Allan2000-Git Feb 22, 2025
12782db
Merge branch 'develop' of https://github.com/Allan2000-Git/keyshade i…
Allan2000-Git Feb 22, 2025
59e9940
Merge branch 'keyshade-xyz:develop' into develop
Allan2000-Git Feb 22, 2025
7136869
Merge branch 'keyshade-xyz:develop' into develop
Allan2000-Git Feb 23, 2025
84128e0
Merge branch 'keyshade-xyz:develop' into develop
Allan2000-Git Feb 23, 2025
4353700
Merge branch 'develop' of https://github.com/Allan2000-Git/keyshade i…
Allan2000-Git Feb 23, 2025
086708c
Merge branch 'develop' of https://github.com/Allan2000-Git/keyshade i…
Allan2000-Git Feb 24, 2025
ccf7f0b
Merge branches 'develop' and 'develop' of https://github.com/Allan200…
Allan2000-Git Feb 27, 2025
a588c9d
Merge branch 'keyshade-xyz:develop' into develop
Allan2000-Git Feb 27, 2025
9a71e1d
Merge branch 'keyshade-xyz:develop' into develop
Allan2000-Git Mar 1, 2025
dcf1cc3
feat(platform): add ConfirmDeleteWorkspace component and update state…
Allan2000-Git Mar 1, 2025
e1b14e1
Merge branch 'develop' into feat/workspace-settings-page
Allan2000-Git Mar 8, 2025
e667813
chore: updated pnpm lock file
Allan2000-Git Mar 8, 2025
cd59889
feat(workspace): enhance workspace deletion flow and UI interactions
Allan2000-Git Mar 8, 2025
ffe6a82
fix: update success message for workspace deletion
Allan2000-Git Mar 8, 2025
f5f7a93
Merge branch 'develop' into feat/workspace-settings-page
Allan2000-Git Mar 8, 2025
545de2f
Merge branch 'develop' of https://github.com/Allan2000-Git/keyshade i…
Allan2000-Git Mar 8, 2025
96eec37
fix: corrected workspace deletion messaging
Allan2000-Git Mar 8, 2025
025947f
Merge branch 'feat/workspace-settings-page' of https://github.com/All…
Allan2000-Git Mar 8, 2025
236e716
fix: update workspace deletion logic to prevent deletion of default w…
Allan2000-Git Mar 9, 2025
59a0e80
Merge branch 'develop' into feat/workspace-settings-page
rajdip-b Mar 9, 2025
ad394ec
Merge branch 'develop' into feat/workspace-settings-page
rajdip-b Mar 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(platform): add ConfirmDeleteWorkspace component and update state…
… management for workspace deletion
  • Loading branch information
Allan2000-Git committed Mar 1, 2025
commit dcf1cc3a283d7a24e791fad1edf9bed23786da64
1 change: 1 addition & 0 deletions apps/platform/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"clsx": "^2.1.0",
"cmdk": "^1.0.0",
"dayjs": "^1.11.11",
"emoji-picker-react": "^4.12.0",
"env-cmd": "^10.1.0",
"framer-motion": "^11.1.7",
"geist": "^1.2.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,184 @@
import React from 'react'
"use client"

import React, { useState } from 'react'
import dynamic from 'next/dynamic';
import type { EmojiClickData} from 'emoji-picker-react';
import { useAtom } from 'jotai';
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue
} from '@/components/ui/select'
import { deleteWorkspaceOpenAtom, selectedWorkspaceAtom } from '@/store';
import ConfirmDeleteWorkspace from '@/components/dashboard/workspace/confirmDeleteWorkspace';

const EmojiPicker = dynamic(
() => {
return import('emoji-picker-react');
},
{ ssr: false }
);

interface WorkspaceSettingsPageProps {
params: { workspace: string }
}

const billingMethods = [
{ id: 'credit', cardType: 'Visa', cardNumber: '9876 4567 3210 1234' },
{ id: 'paypal', cardType: 'AMEX', cardNumber: '1234 3210 9876' },
{ id: 'bank', cardType: 'MasterCard', cardNumber: '3210 9876 4567 1234 4567' }
];

export default function WorkspaceSettingsPage({
params
}: WorkspaceSettingsPageProps): JSX.Element {
const workspaceSettings = params.workspace
return <div>{workspaceSettings} settings</div>
const workspaceSettings = params.workspace;
const [selectedWorkspace] = useAtom(selectedWorkspaceAtom)
const [isDeleteWorkspaceOpen, setIsDeleteWorkspaceOpen] = useAtom(deleteWorkspaceOpenAtom)
const [showPicker, setShowPicker] = useState(false);
const [selectedEmoji, setSelectedEmoji] = useState<string>(selectedWorkspace?.icon || '😊');
const [updatedWorkspaceName, setUpdatedWorkspaceName] = useState<string>(selectedWorkspace?.name || 'Keyshade');
const [billingMethod, setBillingMethod] = useState<{ id: string; cardType: string; cardNumber: string }>(billingMethods[0]);

function handleEmojiSelect(emojiData: EmojiClickData) {
setSelectedEmoji(emojiData.emoji);
setShowPicker(false);
}

const handleBillingMethodChange = (id: string) => {
const method = billingMethods.find((billMethod) => billMethod.id === id);
if (!method) return;
setBillingMethod({
id: method.id,
cardType: method.cardType,
cardNumber: method.cardNumber
});
};

const hasChanges = () => {
return selectedEmoji !== selectedWorkspace?.icon || selectedWorkspace.name !== updatedWorkspaceName || billingMethod.id !== billingMethods[0].id;
};

const handleSaveDetails = () => {
// Logic to save the details goes here
};

return (
<main>
{/* header section */}
<section className="py-4 flex flex-col gap-2.5">
<h1 className="font-bold text-2xl">{selectedWorkspace?.name ? `${selectedWorkspace.name} - ${workspaceSettings}` : 'Workspace'}</h1>
<p className="text-white/60 font-medium text-lg">Update & manage your workspace.</p>
</section>

{/* content section */}
<section className="mt-8 pb-10 flex flex-col items-start gap-10 border-b border-b-white/20">
{/* emoji picker */}
<div className="flex items-center gap-9">
<div className="w-14 h-14 rounded-md bg-[#0B0D0F] flex items-center justify-center">
<span
aria-label='emoji'
className="text-4xl"
onClick={() => setShowPicker(!showPicker)}
onKeyPress={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
setShowPicker(!showPicker);
}
}}
role='button'
tabIndex={0}
>
{selectedEmoji}
</span>
</div>
<div className="flex flex-col gap-2">
<h3 className="font-semibold text-xl">Workspace Icon</h3>
<p className="text-white/60 font-medium text-sm">Upload a picture to change your workspace icon across Keyshade.</p>
</div>
</div>

{
showPicker ?
<EmojiPicker
onEmojiClick={handleEmojiSelect}
/> : null
}

{/* name & billing */}
<div className="flex gap-20">
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<Label className="text-xl" htmlFor="name">Name</Label>
<p className="text-white/60 text-sm">You can add the name of the workspace here.</p>
</div>
<Input
id="name"
onChange={(e) => setUpdatedWorkspaceName(e.target.value)}
placeholder="Workspace name"
value={selectedWorkspace?.name}
/>
</div>

<div className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<Label className="text-xl" htmlFor="billing-method">Billing Method</Label>
<p className="text-white/60 text-sm">Billing email is used for making payments.</p>
</div>
<Select
onValueChange={handleBillingMethodChange}
value={billingMethod.id}
>
<SelectTrigger className=" h-[2.25rem] w-[20rem] rounded-[0.375rem] border-[0.013rem] border-white/10 bg-white/5">
<SelectValue />
</SelectTrigger>
<SelectContent className="border-[0.013rem] border-white/10 bg-neutral-800">
<SelectGroup>
{billingMethods.map((method) => (
<SelectItem
className="group cursor-pointer rounded-sm"
key={method.id}
value={method.id}
>
Card ending in {method.cardNumber.slice(-4)}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
</div>

<Button disabled={!hasChanges()} onClick={handleSaveDetails}>
Save Details
</Button>
</section>

{/* delete workspace section */}
<section className="mt-20">
<div className="w-[782px] py-8 px-6 flex items-center gap-4 bg-[#21191A] rounded-3xl border-2 border-[#E92D1F]">
<div className="flex flex-col gap-2">
<h4 className="text-[#E92D1F] font-bold text-2xl">Delete Workspace</h4>
<p className="text-white/60 font-medium text-lg">Your workspace will be permanently deleted and access will be lost to any of your teams and data. This action is irreversible.</p>
</div>
<Button
className="bg-[#E92D1F] text-white hover:bg-[#E92D1F]/80"
onClick={() => setIsDeleteWorkspaceOpen(true)}
>
Delete
</Button>
</div>
</section>

{/* Delete environment alert dialog */}
{isDeleteWorkspaceOpen && selectedWorkspace ? (
<ConfirmDeleteWorkspace />
) : null}
</main>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use client'

import React, { useCallback, useState } from 'react'
import { toast } from 'sonner'
import { useAtom } from 'jotai'
import { TrashSVG } from '@public/svg/shared'
import { useRouter } from 'next/navigation'
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle
} from '@/components/ui/alert-dialog'
import { deleteWorkspaceOpenAtom, selectedWorkspaceAtom } from '@/store'
import ControllerInstance from '@/lib/controller-instance'
import { useHttp } from '@/hooks/use-http'

export default function ConfirmDeleteWorkspace(): React.JSX.Element {
const [selectedWorkspace, setSelectedWorkspace] = useAtom(selectedWorkspaceAtom)
const [isDeleteWorkspaceOpen, setIsDeleteWorkspaceOpen] = useAtom(deleteWorkspaceOpenAtom)
const [isLoading, setIsLoading] = useState<boolean>(false)
const router = useRouter()

const deleteWorkspace = useHttp(() =>
ControllerInstance.getInstance().workspaceController.deleteWorkspace({
workspaceSlug: selectedWorkspace!.slug
})
);

const handleDeleteWorkspace = async () => {
// Delete workspace logic goes here
if (selectedWorkspace) {
setIsLoading(true)
toast.loading('Deleting workspace...')

try {
const { success } = await deleteWorkspace()

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

// Set the selected environment to null
setSelectedWorkspace(null)
handleClose()
}
} finally {
setIsLoading(false)
toast.dismiss()
router.push('/')
}
}
}

const handleClose = useCallback(() => {
setIsDeleteWorkspaceOpen(false)
}, [setIsDeleteWorkspaceOpen])

return (
<AlertDialog
aria-hidden={!isDeleteWorkspaceOpen}
onOpenChange={handleClose}
open={isDeleteWorkspaceOpen}
>
<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 want to delete this workspace?
</AlertDialogTitle>
</div>
<AlertDialogDescription className="text-sm font-normal leading-5 text-[#71717A]">
This action cannot be undone. This will permanently delete your workspace and remove your environment 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"
disabled={isLoading}
onClick={handleDeleteWorkspace}
>
Yes, delete the wokspace
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}
1 change: 1 addition & 0 deletions apps/platform/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ export const deleteSecretOpenAtom = atom<boolean>(false)
export const createEnvironmentOpenAtom = atom<boolean>(false)
export const editEnvironmentOpenAtom = atom<boolean>(false)
export const deleteEnvironmentOpenAtom = atom<boolean>(false)
export const deleteWorkspaceOpenAtom = atom<boolean>(false)
Loading
Loading