First Commit

This commit is contained in:
2026-09-12 13:56:36 +01:00
commit 4d75af0418
426 changed files with 36452 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
export const server: BunextPageServerFn = async () => {
return {
redirect: {
destination: "/auth/login",
permanent: false,
},
};
};
+31
View File
@@ -0,0 +1,31 @@
import type { BunextPageModuleMeta } from "@moduletrace/bunext/types";
import Section from "@/src/components/twui/layout/Section";
import Container from "@/src/components/twui/layout/Container";
import Stack from "@/src/components/twui/layout/Stack";
import H1 from "@/src/components/twui/layout/H1";
import Span from "@/src/components/twui/layout/Span";
import BlurredImageBG from "@/src/components/general/blured-image-bg";
import { SiteData } from "@/src/data/site-data";
export default function AuthPage() {
return (
<>
<Section className="hero-section">
<BlurredImageBG src="/images/children-school-1.webp" />
<Container className="relative z-10">
<Stack className="w-full items-center max-w-3xl mx-auto gap-7">
<Span className="htag">Admin Section</Span>
<H1 className="text-center font-bold">
Redirecting you to login ...
</H1>
</Stack>
</Container>
</Section>
</>
);
}
export const meta: BunextPageModuleMeta = {
title: `Admin Login | ${SiteData["SiteName"]}`,
description: `Admin section access. Redirecting to login.`,
};
@@ -0,0 +1,37 @@
import fetchApi from "@/src/components/twui/utils/fetch/fetchApi";
import type useFormInit from "@/src/hooks/use-form-init";
import type { ApiReqParams, LoginFormObject } from "@/src/types";
import type { APIResponseObject } from "@moduletrace/bunext/types";
export default async function submitLoginForm({
setLoading,
setStatus,
form,
}: ReturnType<typeof useFormInit<LoginFormObject>>) {
setLoading(true);
const res = await fetchApi<ApiReqParams, APIResponseObject>(
`/api/auth/get-login-code`,
{
method: "POST",
body: {
login: {
email_or_username: form.username_or_email,
},
},
},
);
if (res.success) {
window.location.pathname = `/auth/sso`;
} else {
setStatus({
error: true,
msg: res.msg || "Login Failed",
});
console.log("res", res);
console.log("form", form);
setLoading(false);
}
}
@@ -0,0 +1,200 @@
import fetchApi from "@/src/components/twui/utils/fetch/fetchApi";
import type useFormInit from "@/src/hooks/use-form-init";
import { AppContext } from "@/src/pages/__root";
import type { ApiReqParams, GoogleWindow, LoginFormObject } from "@/src/types";
import type { APIResponseObject } from "@moduletrace/bunext/types";
import { useContext, useEffect, useRef, useState } from "react";
const GoogleScriptSelector =
'script[src="https://accounts.google.com/gsi/client"]';
export default function useGoogleLoginInit({
loading,
setStatus,
status,
setLoading,
}: ReturnType<typeof useFormInit<LoginFormObject>>) {
const { pageProps } = useContext(AppContext);
const googleButtonRef = useRef<HTMLDivElement>(null);
const googleInitializedRef = useRef(false);
const [scriptLoaded, setScriptLoaded] = useState(false);
const [buttonWidth, setButtonWidth] = useState(0);
const [googleReady, setGoogleReady] = useState(false);
const googleClientId = pageProps?.envs?.GOOGLE_CLIENT_ID;
const submitGoogleLogin = async (google_token: string) => {
setLoading(true);
const res = await fetchApi<ApiReqParams, APIResponseObject>(
`/api/auth/google-login`,
{
method: "POST",
body: {
google_token,
},
},
);
if (res.success) {
window.location.pathname = `/admin`;
} else {
setStatus({
error: true,
msg: res.msg || "Google Login Failed",
});
setLoading(false);
}
};
useEffect(() => {
if (!googleClientId) {
return;
}
const clientWindow = window as GoogleWindow;
if (clientWindow.google?.accounts?.id) {
setScriptLoaded(true);
return;
}
const existingScript = document.querySelector(
GoogleScriptSelector,
) as HTMLScriptElement | null;
const handleLoad = () => {
setScriptLoaded(true);
setStatus(undefined);
};
const handleError = () => {
setStatus({
error: true,
msg: "Couldn't load Google login.",
});
};
if (existingScript) {
existingScript.addEventListener("load", handleLoad);
existingScript.addEventListener("error", handleError);
return () => {
existingScript.removeEventListener("load", handleLoad);
existingScript.removeEventListener("error", handleError);
};
}
const script = document.createElement("script");
script.src = "https://accounts.google.com/gsi/client";
script.async = true;
script.defer = true;
script.addEventListener("load", handleLoad);
script.addEventListener("error", handleError);
document.head.appendChild(script);
return () => {
script.removeEventListener("load", handleLoad);
script.removeEventListener("error", handleError);
};
}, [status]);
useEffect(() => {
if (!googleButtonRef.current || typeof ResizeObserver === "undefined") {
return;
}
const resizeObserver = new ResizeObserver((entries) => {
const nextWidth = Math.round(entries[0]?.contentRect.width || 0);
if (!nextWidth) {
return;
}
setButtonWidth((prev) => (prev === nextWidth ? prev : nextWidth));
});
resizeObserver.observe(googleButtonRef.current);
return () => {
resizeObserver.disconnect();
};
}, []);
useEffect(() => {
if (
!googleClientId ||
!scriptLoaded ||
!googleButtonRef.current ||
!buttonWidth
) {
return;
}
const googleId = (window as GoogleWindow).google?.accounts?.id;
if (!googleId) {
return;
}
if (!googleInitializedRef.current) {
googleId.initialize({
client_id: googleClientId,
callback: async ({ credential }) => {
if (!credential) {
setStatus({
error: true,
msg: "Google login did not return a token.",
});
return;
}
await submitGoogleLogin(credential);
},
});
googleInitializedRef.current = true;
}
googleButtonRef.current.innerHTML = "";
googleId.renderButton(googleButtonRef.current, {
theme: "outline",
size: "large",
text: "signin_with",
shape: "rectangular",
width: Math.min(buttonWidth, 400),
});
setGoogleReady(true);
}, [buttonWidth, scriptLoaded, status, submitGoogleLogin]);
const handleButtonClick = () => {
if (loading) {
return;
}
if (!googleClientId) {
setStatus({
error: true,
msg: "Google login is not configured yet.",
});
return;
}
if (!googleInitializedRef.current) {
setStatus({
error: true,
msg: "Google login is still loading. Please try again.",
});
}
};
return {
loading,
handleButtonClick,
googleClientId,
googleButtonRef,
googleReady,
};
}
@@ -0,0 +1,54 @@
import Button from "@/src/components/twui/layout/Button";
import Img from "@/src/components/twui/layout/Img";
import Row from "@/src/components/twui/layout/Row";
import type useFormInit from "@/src/hooks/use-form-init";
import type { LoginFormObject } from "@/src/types";
import { twMerge } from "tailwind-merge";
import useGoogleLoginInit from "../../(hooks)/use-google-login-init";
export default function GoogleLogin(
init: ReturnType<typeof useFormInit<LoginFormObject>>,
) {
const {
loading,
handleButtonClick,
googleClientId,
googleButtonRef,
googleReady,
} = useGoogleLoginInit(init);
return (
<Row className="w-full relative justify-center">
<Button
title="Login with Google"
type="button"
variant="outlined"
color="gray"
className="w-full py-3 relative"
loading={loading}
onClick={handleButtonClick}
>
<Img
alt="Google Logo Icon"
src={`/icons/google.png`}
size={17}
/>
<Row>
<span>Login with Google</span>
</Row>
</Button>
{googleClientId ? (
<div
ref={googleButtonRef}
aria-hidden
className={twMerge(
"absolute inset-0 z-10 opacity-0",
googleReady && !loading
? "pointer-events-auto"
: "pointer-events-none",
)}
/>
) : null}
</Row>
);
}
@@ -0,0 +1,38 @@
import Form from "@/src/components/twui/form/Form";
import LoadingOverlay from "@/src/components/twui/elements/LoadingOverlay";
import Row from "@/src/components/twui/layout/Row";
import Divider from "@/src/components/twui/layout/Divider";
import Span from "@/src/components/twui/layout/Span";
import useFormInit from "@/src/hooks/use-form-init";
import { type LoginFormObject } from "@/src/types";
import LoginShell from "@/src/components/general/login-shell";
import GoogleLogin from "./google-login";
import LoginFormEmailUsername from "./login-form-email-username";
import submitLoginForm from "../../(functions)/submit-login-form";
import LoginFormAction from "./login-form-action";
export default function LoginForm() {
const init = useFormInit<LoginFormObject>();
const { loading, status } = init;
return (
<>
<GoogleLogin {...init} />
<Row className="w-full flex-nowrap gap-4 -my-2">
<Divider />
<Span className="text-sm font-semibold opacity-50">OR</Span>
<Divider />
</Row>
<Form
className="w-full flex items-center justify-center relative gap-4"
onSubmit={() => {
submitLoginForm(init);
}}
>
{loading && <LoadingOverlay />}
<LoginFormEmailUsername {...init} />
<LoginFormAction {...init} />
</Form>
</>
);
}
@@ -0,0 +1,16 @@
import Input from "@/src/components/twui/form/Input";
import Button from "@/src/components/twui/layout/Button";
import useFormInit from "@/src/hooks/use-form-init";
import { type LoginFormObject } from "@/src/types";
export default function LoginFormAction({}: ReturnType<
typeof useFormInit<LoginFormObject>
>) {
return (
<>
<Button title="Submit Login Form" type="submit" className="w-full">
Get Login Code
</Button>
</>
);
}
@@ -0,0 +1,22 @@
import Input from "@/src/components/twui/form/Input";
import useFormInit from "@/src/hooks/use-form-init";
import { type LoginFormObject } from "@/src/types";
export default function LoginFormEmailUsername({
setForm,
}: ReturnType<typeof useFormInit<LoginFormObject>>) {
return (
<Input
type="email"
placeholder="Email or Username"
onChange={(e) => {
setForm((prev) => ({
...prev,
username_or_email: e.target.value,
}));
}}
showLabel
required
/>
);
}
+22
View File
@@ -0,0 +1,22 @@
import Section from "@/src/components/twui/layout/Section";
import Container from "@/src/components/twui/layout/Container";
import Stack from "@/src/components/twui/layout/Stack";
import H1 from "@/src/components/twui/layout/H1";
import Span from "@/src/components/twui/layout/Span";
import LoginShell from "@/src/components/general/login-shell";
export default function Hero() {
// return <LoginShell></LoginShell>;
return (
<Section className="">
<Container className="relative z-10">
<Stack className="w-full items-center max-w-3xl mx-auto gap-7">
<Span className="htag">Welcome Back Admin</Span>
<H1 className="text-center font-bold">
Login to your account
</H1>
</Stack>
</Container>
</Section>
);
}
@@ -0,0 +1,21 @@
import Stack from "@/src/components/twui/layout/Stack";
import LoginForm from "../(partials)/login-form";
import Span from "@/src/components/twui/layout/Span";
import ArrowedLink from "@/src/components/twui/layout/ArrowedLink";
export default function LoginFormSection() {
return (
<Stack className="w-full items-center max-w-3xl mx-auto gap-7">
<LoginForm />
<Stack className="gap-2 items-center">
<Span variant="faded">Received an SSO code already?</Span>
<ArrowedLink
link={{
title: "Complete Login",
url: "/auth/sso",
}}
/>
</Stack>
</Stack>
);
}
+16
View File
@@ -0,0 +1,16 @@
import grabUsers from "@/src/functions/backend/db/users/grab-users";
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
export const server: BunextPageServerFn = async (ctx) => {
const users_res = await grabUsers();
if (!users_res.singleRes?.id) {
return {
redirect: {
destination: `/auth/signup`,
},
};
}
return {};
};
+11
View File
@@ -0,0 +1,11 @@
import Hero from "./(sections)/hero";
import LoginFormSection from "./(sections)/login-form-section";
export default function LoginPage() {
return (
<>
{/* <Hero /> */}
<LoginFormSection />
</>
);
}
+26
View File
@@ -0,0 +1,26 @@
import { AppData } from "@/src/data/app-data";
import { deleteCookies } from "@/src/utils/cookies";
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
export const server: BunextPageServerFn = async ({ req }) => {
return {
res_transform(res) {
const new_res = res.clone();
deleteCookies(new_res, [
{
name: AppData["AuthKeyCookieName"],
httpOnly: true,
},
{
name: AppData["AuthCSRFCookieName"],
httpOnly: true,
},
{
name: AppData["SSOAuthCookieName"],
httpOnly: true,
},
]);
return new_res;
},
};
};
+47
View File
@@ -0,0 +1,47 @@
import type { BunextPageModuleMeta } from "@moduletrace/bunext/types";
import Section from "@/src/components/twui/layout/Section";
import Loading from "@/src/components/twui/elements/Loading";
import Row from "@/src/components/twui/layout/Row";
import Span from "@/src/components/twui/layout/Span";
import { useEffect } from "react";
import { twMerge } from "tailwind-merge";
import Logo from "@/src/components/general/logo";
import Paper from "@/src/components/twui/elements/Paper";
import Container from "@/src/components/twui/layout/Container";
import Center from "@/src/components/twui/layout/Center";
import { SiteData } from "@/src/data/site-data";
export default function LogoutPage() {
useEffect(() => {
setTimeout(() => {
window.location.pathname = "/";
}, 1000);
}, []);
return (
<Section
className={twMerge(
"h-screen w-screen px-0 items-center justify-center",
)}
>
<Center>
<Paper className="w-auto p-10 items-center">
<Logo
text_props={{
className: "text-dark",
}}
/>
<Row>
<Loading />
<Span>Logging out ...</Span>
</Row>
</Paper>
</Center>
</Section>
);
}
export const meta: BunextPageModuleMeta = {
title: `Logging Out | ${SiteData["SiteName"]}`,
description: `You are being logged out and redirected to the homepage.`,
};
+25
View File
@@ -0,0 +1,25 @@
import grabUsers from "@/src/functions/backend/db/users/grab-users";
import type { PagePropsType } from "@/src/types";
import type { BunextPageServerFn } from "@moduletrace/bunext/types";
export const server: BunextPageServerFn<PagePropsType> = async (ctx) => {
if (ctx.props.user?.id) {
return {
redirect: {
destination: `/admin`,
},
};
}
const users_res = await grabUsers();
if (users_res.singleRes?.id) {
return {
redirect: {
destination: `/auth/login`,
},
};
}
return {};
};
+19
View File
@@ -0,0 +1,19 @@
import type { BunextPageModuleMeta } from "@moduletrace/bunext/types";
import Stack from "@/src/components/twui/layout/Stack";
import UserForm from "@/src/components/general/user-form";
import { SiteData } from "@/src/data/site-data";
import H1 from "@/src/components/twui/layout/H1";
export default function LogoutPage() {
return (
<Stack className="items-center gap-10">
<H1 className="text-center text-xl!">Create Admin User</H1>
<UserForm is_first_user />
</Stack>
);
}
export const meta: BunextPageModuleMeta = {
title: `Create Super Admin Account | ${SiteData["SiteName"]}`,
description: `Create Super Admin Account`,
};
@@ -0,0 +1,73 @@
import Form from "@/src/components/twui/form/Form";
import LoadingOverlay from "@/src/components/twui/elements/LoadingOverlay";
import Input from "@/src/components/twui/form/Input";
import Button from "@/src/components/twui/layout/Button";
import useFormInit from "@/src/hooks/use-form-init";
import fetchApi from "@/src/components/twui/utils/fetch/fetchApi";
import { type ApiReqParams, type SSOFormObject } from "@/src/types";
import type { APIResponseObject } from "@moduletrace/bunext/types";
import LoginShell from "@/src/components/general/login-shell";
export default function SSOForm() {
const init = useFormInit<SSOFormObject>();
const { form, loading, setForm, setLoading, status, setStatus } = init;
const submitSSOLoginForm = async () => {
setLoading(true);
const res = await fetchApi<ApiReqParams, APIResponseObject>(
`/api/auth/login`,
{
method: "POST",
body: {
sso_code: form.code,
},
},
);
if (res.success) {
window.location.pathname = `/admin`;
} else {
setStatus({
error: true,
msg: res.msg || "Login Failed",
});
console.log("res", res);
console.log("form", form);
setLoading(false);
}
};
return (
<>
<LoginShell status={status}>
<Form
className="w-full flex items-center justify-center relative gap-4"
onSubmit={submitSSOLoginForm}
>
{loading && <LoadingOverlay />}
<Input
placeholder="SSO Code"
onChange={(e) => {
setForm((prev) => ({
...prev,
code: e.target.value,
}));
}}
showLabel
required
/>
<Button
title="Submit Login Form"
type="submit"
className="w-full"
>
Complete Login
</Button>
</Form>
</LoginShell>
</>
);
}
+20
View File
@@ -0,0 +1,20 @@
import Section from "@/src/components/twui/layout/Section";
import Container from "@/src/components/twui/layout/Container";
import Stack from "@/src/components/twui/layout/Stack";
import H1 from "@/src/components/twui/layout/H1";
import Span from "@/src/components/twui/layout/Span";
export default function Hero() {
return (
<Section className="hero-section">
<Container className="relative z-10">
<Stack className="w-full items-center max-w-3xl mx-auto gap-7">
<Span className="htag">SSO Login</Span>
<H1 className="text-center font-bold">
Complete your login
</H1>
</Stack>
</Container>
</Section>
);
}
@@ -0,0 +1,29 @@
import Section from "@/src/components/twui/layout/Section";
import Container from "@/src/components/twui/layout/Container";
import Stack from "@/src/components/twui/layout/Stack";
import SSOForm from "../(partials)/sso-form";
import Span from "@/src/components/twui/layout/Span";
import ArrowedLink from "@/src/components/twui/layout/ArrowedLink";
export default function SSOFormSection() {
return (
<Section className="py-0!">
<Container className="relative z-10 py-20 -mt-28">
<Stack className="w-full items-center max-w-3xl mx-auto gap-7">
<SSOForm />
<Stack className="gap-2 items-center">
<Span variant="faded">
Login Failed or Code Expired?
</Span>
<ArrowedLink
link={{
title: "Login Again",
url: "/auth/login",
}}
/>
</Stack>
</Stack>
</Container>
</Section>
);
}
+18
View File
@@ -0,0 +1,18 @@
import type { BunextPageModuleMeta } from "@moduletrace/bunext/types";
import Hero from "./(sections)/hero";
import SSOFormSection from "./(sections)/sso-form-section";
import { SiteData } from "@/src/data/site-data";
export default function SSOPage() {
return (
<>
<Hero />
<SSOFormSection />
</>
);
}
export const meta: BunextPageModuleMeta = {
title: `Sign In | ${SiteData["SiteName"]}`,
description: `Sign in to your account to access the admin dashboard.`,
};