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
+