diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8540516..2efae87 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -29,3 +29,8 @@ model ApiKey { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } + +model Configs { + id String @id @default("1") + allowRegister Boolean @default(false) +} diff --git a/prisma/seed.ts b/prisma/seed.ts index 3706d26..651f4f4 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -8,6 +8,10 @@ const user = [ } ]; +const configs = { + allowRegister: false +} + ; (async () => { for (const u of user) { await prisma.user.upsert({ @@ -19,7 +23,13 @@ const user = [ console.log(`✅ User ${u.email} seeded successfully`) } + await prisma.configs.upsert({ + where: { id: "1" }, + create: configs, + update: configs, + }) + console.log(`✅ Configs seeded successfully`) })().catch((e) => { console.error(e) process.exit(1) diff --git a/src/AppRoutes.tsx b/src/AppRoutes.tsx index acbc003..459e80c 100644 --- a/src/AppRoutes.tsx +++ b/src/AppRoutes.tsx @@ -64,6 +64,16 @@ const Register = { preload: () => import("./pages/Register"), }; +const ConfigLayout = { + Component: React.lazy(() => import("./pages/dashboard/config/config_layout")), + preload: () => import("./pages/dashboard/config/config_layout"), +}; + +const ConfigPage = { + Component: React.lazy(() => import("./pages/dashboard/config/config_page")), + preload: () => import("./pages/dashboard/config/config_page"), +}; + const ApikeyPage = { Component: React.lazy(() => import("./pages/dashboard/apikey/apikey_page")), preload: () => import("./pages/dashboard/apikey/apikey_page"), @@ -118,6 +128,19 @@ export default function AppRoutes() { }> } /> + }> + } /> + + }> + + + } + /> + + { + const configs = await prisma.configs.findUnique({ where: { id: "1" } }) + return { allowRegister: configs?.allowRegister } + }, { + detail: { + description: "Get allow register", + summary: "get allow register", + }, + }) .get( "/assets/:name", (ctx) => { diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index f3acd80..b4aa324 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -13,6 +13,8 @@ import { import { useEffect, useState } from "react"; import { Navigate } from "react-router-dom"; import apiFetch from "../lib/apiFetch"; +import useSWR from "swr"; +import { useNavigate } from "react-router-dom"; export default function Register() { const [name, setName] = useState(""); @@ -20,6 +22,10 @@ export default function Register() { const [password, setPassword] = useState(""); const [loading, setLoading] = useState(false); const [isAuthenticated, setIsAuthenticated] = useState(null); + const navigate = useNavigate(); + + const { data, error, isLoading } = useSWR("/", apiFetch["get-allow-register"].get); + const allowRegister = data?.data?.allowRegister ?? false; const handleSubmit = async () => { setLoading(true); @@ -57,10 +63,22 @@ export default function Register() { checkSession(); }, []); + if (isLoading) return Loading...; + if (error) return Error: {error.message}; + if (isAuthenticated === null) return null; if (isAuthenticated) return ; + if (!allowRegister) return + + + Allow register is disabled + + + + ; + return ( diff --git a/src/pages/dashboard/config/config_layout.tsx b/src/pages/dashboard/config/config_layout.tsx new file mode 100644 index 0000000..eaa881a --- /dev/null +++ b/src/pages/dashboard/config/config_layout.tsx @@ -0,0 +1,5 @@ +import { Outlet } from "react-router-dom"; + +export default function ConfigLayout() { + return ; +} diff --git a/src/pages/dashboard/config/config_page.tsx b/src/pages/dashboard/config/config_page.tsx new file mode 100644 index 0000000..0a2e2f2 --- /dev/null +++ b/src/pages/dashboard/config/config_page.tsx @@ -0,0 +1,37 @@ +import apiFetch from "@/lib/apiFetch"; +import { Container, Stack, Switch, Text } from "@mantine/core"; +import { useShallowEffect } from "@mantine/hooks"; +import { useState } from "react"; +import useSWR from "swr"; + +export default function ConfigPage() { + + const { data, error, isLoading } = useSWR("/", apiFetch["get-allow-register"].get); + + const [allowRegister, setAllowRegister] = useState(false); + + useShallowEffect(() => { + if (data) { + setAllowRegister(data.data?.allowRegister ?? false) + } + }, [data]) + + if (isLoading) return Loading... + if (error) return Error: {error.message} + + + async function updateAllowRegister({ allowRegister }: { allowRegister: boolean }) { + const res = await apiFetch.api.configs["update-allow-register"].post({ allowRegister: allowRegister }) + console.log(res.data) + setAllowRegister(res.data?.allowRegister ?? false) + } + + return + + Config Page + { + updateAllowRegister({ allowRegister: !allowRegister }) + }} /> + + +} diff --git a/src/pages/dashboard/dashboard_layout.tsx b/src/pages/dashboard/dashboard_layout.tsx index a65efb8..fd13d34 100644 --- a/src/pages/dashboard/dashboard_layout.tsx +++ b/src/pages/dashboard/dashboard_layout.tsx @@ -22,6 +22,8 @@ import { IconChevronLeft, IconChevronRight, IconDashboard, + IconKey, + IconSettings, } from "@tabler/icons-react"; import type { User } from "generated/prisma"; import { useLocation, useNavigate } from "react-router-dom"; @@ -43,13 +45,12 @@ function Logout() { color="red" size="xs" onClick={async () => { - modals.openConfirmModal({ title: "Confirm Logout", children: "Are you sure you want to logout?", labels: { confirm: "Logout", cancel: "Cancel" }, confirmProps: { color: "red" }, - onCancel: () => { }, + onCancel: () => {}, onConfirm: async () => { await apiFetch.auth.logout.delete(); localStorage.removeItem("token"); @@ -205,11 +206,19 @@ function NavigationDashboard() { } + leftSection={} label="API Keys" description="Manage your API credentials" onClick={() => navigate(clientRoutes["/dashboard/apikey/apikey"])} /> + + } + label="Config" + description="Manage your app config" + onClick={() => navigate(clientRoutes["/dashboard/config/config"])} + /> ); } diff --git a/src/pages/dashboard/dashboard_page.tsx b/src/pages/dashboard/dashboard_page.tsx index 202b7fe..f520cb7 100644 --- a/src/pages/dashboard/dashboard_page.tsx +++ b/src/pages/dashboard/dashboard_page.tsx @@ -8,7 +8,7 @@ import { Stack, Table, Text, - Title + Title, } from "@mantine/core"; export default function Dashboard() { diff --git a/src/routeTypes.ts b/src/routeTypes.ts index 2c8934f..35e8119 100644 --- a/src/routeTypes.ts +++ b/src/routeTypes.ts @@ -1,5 +1,5 @@ -export type AppRoute = "/login" | "/" | "/register" | "/dashboard" | "/dashboard/apikey/apikey" | "/dashboard/dashboard"; +export type AppRoute = "/login" | "/" | "/register" | "/dashboard" | "/dashboard/config" | "/dashboard/config/config" | "/dashboard/apikey/apikey" | "/dashboard/dashboard"; export function route(path: AppRoute, params?: Record) { if (!params) return path; diff --git a/src/server/routes/configs_route.ts b/src/server/routes/configs_route.ts new file mode 100644 index 0000000..2d62496 --- /dev/null +++ b/src/server/routes/configs_route.ts @@ -0,0 +1,26 @@ +import Elysia, { t } from "elysia"; +import { prisma } from "@/server/lib/prisma"; + +const Configs = new Elysia({ + prefix: "/configs", + detail: { description: "Configs API", summary: "Configs API", tags: ["configs"] }, +}) + .post("/update-allow-register", async ({ body }) => { + const { allowRegister } = body + await prisma.configs.update({ + where: { id: "1" }, + data: { allowRegister }, + }) + return { success: true, message: "Configs updated successfully", allowRegister } + }, { + body: t.Object({ + allowRegister: t.Boolean(), + }), + detail: { + description: "Update configs", + summary: "update configs", + }, + }) + +export default Configs +