tambahan
This commit is contained in:
@@ -29,3 +29,8 @@ model ApiKey {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Configs {
|
||||
id String @id @default("1")
|
||||
allowRegister Boolean @default(false)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
<Route path="/dashboard" element={<DashboardLayout.Component />}>
|
||||
<Route index element={<DashboardPage.Component />} />
|
||||
|
||||
<Route path="/dashboard/config" element={<ConfigLayout.Component />}>
|
||||
<Route index element={<ConfigPage.Component />} />
|
||||
|
||||
<Route
|
||||
path="/dashboard/config/config"
|
||||
element={
|
||||
<React.Suspense fallback={<SkeletonLoading />}>
|
||||
<ConfigPage.Component />
|
||||
</React.Suspense>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
path="/dashboard/apikey/apikey"
|
||||
element={
|
||||
|
||||
@@ -4,6 +4,8 @@ const clientRoutes = {
|
||||
"/": "/",
|
||||
"/register": "/register",
|
||||
"/dashboard": "/dashboard",
|
||||
"/dashboard/config": "/dashboard/config",
|
||||
"/dashboard/config/config": "/dashboard/config/config",
|
||||
"/dashboard/apikey/apikey": "/dashboard/apikey/apikey",
|
||||
"/dashboard/dashboard": "/dashboard/dashboard",
|
||||
"/*": "/*"
|
||||
|
||||
@@ -9,6 +9,8 @@ import { LandingPage } from "./Landing";
|
||||
import { renderToReadableStream } from "react-dom/server";
|
||||
import { cors } from "@elysiajs/cors";
|
||||
import packageJson from "./../package.json";
|
||||
import Configs from "./server/routes/configs_route";
|
||||
import { prisma } from "./server/lib/prisma";
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
const Docs = new Elysia().use(
|
||||
@@ -68,6 +70,7 @@ const ApiUser = new Elysia({
|
||||
const Api = new Elysia({
|
||||
prefix: "/api",
|
||||
})
|
||||
.use(Configs)
|
||||
.use(apiAuth)
|
||||
.use(ApiKeyRoute)
|
||||
.use(ApiUser);
|
||||
@@ -77,6 +80,15 @@ const app = new Elysia()
|
||||
.use(Api)
|
||||
.use(Docs)
|
||||
.use(Auth)
|
||||
.get("/get-allow-register", async () => {
|
||||
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) => {
|
||||
|
||||
@@ -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<boolean | null>(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 <Text>Loading...</Text>;
|
||||
if (error) return <Text>Error: {error.message}</Text>;
|
||||
|
||||
if (isAuthenticated === null) return null;
|
||||
if (isAuthenticated)
|
||||
return <Navigate to={clientRoutes["/dashboard"]} replace />;
|
||||
|
||||
if (!allowRegister) return <Container size={"md"} w={"100%"}>
|
||||
<Group justify="center">
|
||||
<Stack>
|
||||
<Text>Allow register is disabled</Text>
|
||||
<Button onClick={() => navigate(clientRoutes["/login"])}>Back to login</Button>
|
||||
</Stack>
|
||||
</Group>
|
||||
</Container>;
|
||||
|
||||
return (
|
||||
<Container size={420} py={80}>
|
||||
<Card shadow="sm" radius="md" padding="xl">
|
||||
|
||||
5
src/pages/dashboard/config/config_layout.tsx
Normal file
5
src/pages/dashboard/config/config_layout.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import { Outlet } from "react-router-dom";
|
||||
|
||||
export default function ConfigLayout() {
|
||||
return <Outlet />;
|
||||
}
|
||||
37
src/pages/dashboard/config/config_page.tsx
Normal file
37
src/pages/dashboard/config/config_page.tsx
Normal file
@@ -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 <Container size="lg" w={"100%"}><Text>Loading...</Text></Container>
|
||||
if (error) return <Container size="lg" w={"100%"}><Text>Error: {error.message}</Text></Container>
|
||||
|
||||
|
||||
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 <Container size="lg" w={"100%"}>
|
||||
<Stack>
|
||||
<Text>Config Page</Text>
|
||||
<Switch label="Allow Register" checked={allowRegister} onChange={(e) => {
|
||||
updateAllowRegister({ allowRegister: !allowRegister })
|
||||
}} />
|
||||
</Stack>
|
||||
</Container>
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
<NavLink
|
||||
active={isActive("/dashboard/apikey/apikey")}
|
||||
leftSection={<IconDashboard size={18} />}
|
||||
leftSection={<IconKey size={18} />}
|
||||
label="API Keys"
|
||||
description="Manage your API credentials"
|
||||
onClick={() => navigate(clientRoutes["/dashboard/apikey/apikey"])}
|
||||
/>
|
||||
|
||||
<NavLink
|
||||
active={isActive("/dashboard/config/config")}
|
||||
leftSection={<IconSettings size={18} />}
|
||||
label="Config"
|
||||
description="Manage your app config"
|
||||
onClick={() => navigate(clientRoutes["/dashboard/config/config"])}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
Stack,
|
||||
Table,
|
||||
Text,
|
||||
Title
|
||||
Title,
|
||||
} from "@mantine/core";
|
||||
|
||||
export default function Dashboard() {
|
||||
|
||||
@@ -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<string,string|number>) {
|
||||
if (!params) return path;
|
||||
|
||||
26
src/server/routes/configs_route.ts
Normal file
26
src/server/routes/configs_route.ts
Normal file
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user