diff --git a/app/api/applications/get/route.ts b/app/api/applications/get/route.ts index 5c0eaab..9f64dc0 100644 --- a/app/api/applications/get/route.ts +++ b/app/api/applications/get/route.ts @@ -32,6 +32,8 @@ export async function POST(request: NextRequest) { } }); + const servers_all = await prisma.server.findMany() + const applicationsWithServers = applications.map(app => ({ ...app, server: servers.find(s => s.id === app.serverId)?.name || 'No server' @@ -42,7 +44,7 @@ export async function POST(request: NextRequest) { return NextResponse.json({ applications: applicationsWithServers, - servers, + servers: servers_all, maxPage }); } catch (error: any) { diff --git a/app/dashboard/applications/Applications.tsx b/app/dashboard/applications/Applications.tsx index ec4b8d7..d86c549 100644 --- a/app/dashboard/applications/Applications.tsx +++ b/app/dashboard/applications/Applications.tsx @@ -75,7 +75,7 @@ export default function Dashboard() { const [loading, setLoading] = useState(true); useEffect(() => { - const savedLayout = Cookies.get('layoutPreference'); + const savedLayout = Cookies.get('layoutPreference-app'); const layout_bool = savedLayout === 'grid' setIsGridLayout(layout_bool); setItemsPerPage(layout_bool ? 15 : 5) @@ -84,7 +84,7 @@ export default function Dashboard() { const toggleLayout = () => { const newLayout = !isGridLayout; setIsGridLayout(newLayout); - Cookies.set('layoutPreference', newLayout ? 'grid' : 'standard', { + Cookies.set('layoutPreference-app', newLayout ? 'grid' : 'standard', { expires: 365, path: '/', sameSite: 'strict' diff --git a/app/dashboard/servers/Servers.tsx b/app/dashboard/servers/Servers.tsx index bf82b38..a15d877 100644 --- a/app/dashboard/servers/Servers.tsx +++ b/app/dashboard/servers/Servers.tsx @@ -76,14 +76,14 @@ export default function Dashboard() { const [loading, setLoading] = useState(true); useEffect(() => { - const savedLayout = Cookies.get('layoutPreference'); + const savedLayout = Cookies.get('layoutPreference-servers'); setIsGridLayout(savedLayout === 'grid'); }, []); const toggleLayout = () => { const newLayout = !isGridLayout; setIsGridLayout(newLayout); - Cookies.set('layoutPreference', newLayout ? 'grid' : 'standard', { + Cookies.set('layoutPreference-servers', newLayout ? 'grid' : 'standard', { expires: 365, path: '/', sameSite: 'strict' diff --git a/app/dashboard/settings/Settings.tsx b/app/dashboard/settings/Settings.tsx new file mode 100644 index 0000000..e245c13 --- /dev/null +++ b/app/dashboard/settings/Settings.tsx @@ -0,0 +1,78 @@ +import { AppSidebar } from "@/components/app-sidebar" +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb" +import { Separator } from "@/components/ui/separator" +import { + SidebarInset, + SidebarProvider, + SidebarTrigger, +} from "@/components/ui/sidebar" +import { Card, CardHeader } from "@/components/ui/card" +import { useTheme } from "next-themes" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" + +export default function Settings() { + const { theme, setTheme } = useTheme() + + return ( + + + +
+
+ + + + + + / + + + + Dashboard + + + + Settings + + + +
+
+
+ Settings +
+ + + Theme + + + +
+
+
+
+ ) +} \ No newline at end of file diff --git a/app/dashboard/settings/page.tsx b/app/dashboard/settings/page.tsx new file mode 100644 index 0000000..4334702 --- /dev/null +++ b/app/dashboard/settings/page.tsx @@ -0,0 +1,59 @@ +"use client"; + +import { useEffect, useState } from "react"; +import Cookies from "js-cookie"; +import { useRouter } from "next/navigation"; +import Settings from "./Settings" +import axios from "axios"; + +export default function DashboardPage() { + const router = useRouter(); + const [isAuthChecked, setIsAuthChecked] = useState(false); + const [isValid, setIsValid] = useState(false); + + useEffect(() => { + const token = Cookies.get("token"); + if (!token) { + router.push("/"); + } else { + const checkToken = async () => { + try { + const response = await axios.post("/api/auth/validate", { + token: token, + }); + + if (response.status === 200) { + setIsValid(true); + } + } catch (error: any) { + Cookies.remove("token"); + router.push("/"); + } + } + checkToken(); + } + setIsAuthChecked(true); + }, [router]); + + if (!isAuthChecked) { + return ( +
+
+ + + + + + + + + + + Loading... +
+
+ ) + } + + return isValid ? : null; +} \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index 1ca1b4b..332c576 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -30,7 +30,7 @@ export default function RootLayout({ > diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx index a90016b..f2a601d 100644 --- a/components/app-sidebar.tsx +++ b/components/app-sidebar.tsx @@ -50,7 +50,7 @@ const data = { { title: "Settings", icon: Settings, - url: "/Dashboard/setting", + url: "/dashboard/settings", }, ], } diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..ec51e9c --- /dev/null +++ b/components/ui/dropdown-menu.tsx @@ -0,0 +1,257 @@ +"use client" + +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function DropdownMenu({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function DropdownMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean + variant?: "default" | "destructive" +}) { + return ( + + ) +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + ) +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ) +} + +function DropdownMenuSub({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + {children} + + + ) +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +} diff --git a/package-lock.json b/package-lock.json index f326c3e..70208ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@prisma/extension-accelerate": "^1.3.0", "@radix-ui/react-alert-dialog": "^1.1.7", "@radix-ui/react-dialog": "^1.1.7", + "@radix-ui/react-dropdown-menu": "^2.1.7", "@radix-ui/react-label": "^2.1.3", "@radix-ui/react-select": "^2.1.7", "@radix-ui/react-separator": "^1.1.3", @@ -1332,6 +1333,35 @@ } } }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.7.tgz", + "integrity": "sha512-7/1LiuNZuCQE3IzdicGoHdQOHkS2Q08+7p8w6TXZ6ZjgAULaCI85ZY15yPl4o4FVgoKLRT43/rsfNVN8osClQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.7", + "@radix-ui/react-primitive": "2.0.3", + "@radix-ui/react-use-controllable-state": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", @@ -1413,6 +1443,46 @@ } } }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.7.tgz", + "integrity": "sha512-tBODsrk68rOi1/iQzbM54toFF+gSw/y+eQgttFflqlGekuSebNqvFNHjJgjqPhiMb4Fw9A0zNFly1QT6ZFdQ+Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.6", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.3", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.3", + "@radix-ui/react-portal": "1.1.5", + "@radix-ui/react-presence": "1.1.3", + "@radix-ui/react-primitive": "2.0.3", + "@radix-ui/react-roving-focus": "1.1.3", + "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.3.tgz", @@ -1516,6 +1586,37 @@ } } }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.3.tgz", + "integrity": "sha512-ufbpLUjZiOg4iYgb2hQrWXEPYX6jOLBbR27bDyAff5GYMRrCzcze8lukjuXVUQvJ6HZe8+oL+hhswDcjmcgVyg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.0.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-select": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.7.tgz", diff --git a/package.json b/package.json index 59472ef..a76a688 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@prisma/extension-accelerate": "^1.3.0", "@radix-ui/react-alert-dialog": "^1.1.7", "@radix-ui/react-dialog": "^1.1.7", + "@radix-ui/react-dropdown-menu": "^2.1.7", "@radix-ui/react-label": "^2.1.3", "@radix-ui/react-select": "^2.1.7", "@radix-ui/react-separator": "^1.1.3",