Feat: started admin panel

This commit is contained in:
2025-01-24 15:22:40 +03:00
parent d97cafa9ec
commit 2a9a49c5ec
11 changed files with 135 additions and 2 deletions

4
.gitignore vendored
View File

@@ -42,3 +42,7 @@ next-env.d.ts
# repomix
repomix-output.txt
# vscode
.vscode/*
!.vscode/settings.json

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"scss.lint.unknownAtRules": "ignore"
}

BIN
bun.lockb

Binary file not shown.

View File

@@ -10,12 +10,14 @@
},
"dependencies": {
"@mantine/core": "^7.16.1",
"@mantine/form": "^7.16.1",
"@mantine/hooks": "^7.16.1",
"@mantine/modals": "^7.16.1",
"next": "15.1.5",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-icons": "^5.4.0"
"react-icons": "^5.4.0",
"zod": "^3.24.1"
},
"devDependencies": {
"@eslint/eslintrc": "^3",

9
src/app/admin/actions.ts Normal file
View File

@@ -0,0 +1,9 @@
"use server";
import { redirect } from "next/navigation";
export async function login(formData: { name: string; password: string }) {
console.log("data");
console.log(formData);
redirect("/admin/panel");
}

View File

60
src/app/admin/page.tsx Normal file
View File

@@ -0,0 +1,60 @@
"use client";
import { Button, Card, Flex, PasswordInput, Text, TextInput } from "@mantine/core";
import { hasLength, useForm } from "@mantine/form";
import { login } from "./actions";
interface FormValues {
name: string;
password: string;
}
const AdminPage = () => {
const form = useForm<FormValues>({
mode: "uncontrolled",
initialValues: {
name: "",
password: "",
},
validate: {
name: hasLength({ min: 5 }, "Too short"),
password: hasLength({ min: 5 }, "Too short"),
},
});
return (
<Flex w="100vw" h="100vh" justify="center" align="center">
<Card shadow="md" w="400" radius="md">
<form onSubmit={form.onSubmit(login)}>
<Text c="dimmed" size="xl" ta="center">
Admin
</Text>
<TextInput
label="Name"
placeholder="Username"
key={form.key("name")}
withAsterisk
{...form.getInputProps("name")}
name="name"
autoComplete="username"
/>
<PasswordInput
label="Password"
mt="md"
withAsterisk
placeholder="password"
key={form.key("password")}
name="password"
autoComplete="current-password"
{...form.getInputProps("password")}
/>
<Button radius="md" type="submit" mt="md" w="100%">
Login
</Button>
</form>
</Card>
</Flex>
);
};
export default AdminPage;

View File

@@ -0,0 +1,35 @@
"use client";
import { ActionIcon, AppShell, Burger, Flex, Group, Skeleton, useMantineColorScheme } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { LuMoon, LuSun } from "react-icons/lu";
const PanelPage = () => {
const [opened, { toggle }] = useDisclosure();
const { setColorScheme, colorScheme } = useMantineColorScheme();
const changeColorScheme = () => {
setColorScheme(colorScheme === "light" ? "dark" : "light");
};
return (
<AppShell header={{ height: 60 }} navbar={{ width: 300, breakpoint: "sm", collapsed: { mobile: !opened } }}>
<AppShell.Header>
<Flex h="100%" px="md" justify="space-between" align="center">
<Group h="100%">
<Burger opened={opened} onClick={toggle} size="sm" hiddenFrom="sm" />
<div>Logo</div>
</Group>
<ActionIcon onClick={changeColorScheme} variant="default" size="md" aria-label="Toggle color scheme">
{colorScheme === "light" ? <LuMoon /> : <LuSun />}
</ActionIcon>
</Flex>
</AppShell.Header>
<AppShell.Navbar p="md">
{Array(15)
.fill(0)
.map((_, index) => (
<Skeleton key={index} h={28} mt="sm" animate={false} />
))}
</AppShell.Navbar>
</AppShell>
);
};
export default PanelPage;

3
src/app/api/route.ts Normal file
View File

@@ -0,0 +1,3 @@
export async function GET() {
return Response.json({ test: 1 });
}

3
src/lib/auth.ts Normal file
View File

@@ -0,0 +1,3 @@
export function isAuthenticated() {
return true;
}

14
src/middleware.ts Normal file
View File

@@ -0,0 +1,14 @@
import { isAuthenticated } from "@/lib/auth";
import { NextRequest, NextResponse } from "next/server";
export const config = {
matcher: "/admin/:path*",
};
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
if (pathname === "/admin" || isAuthenticated()) {
return NextResponse.next();
}
return NextResponse.redirect(new URL("/admin", request.url));
}