Updates
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import Link from "next/link";
|
||||
import { useId } from "react";
|
||||
|
||||
export default function Logo() {
|
||||
const mainGradientId = useId();
|
||||
const foldGradientId = useId();
|
||||
|
||||
return (
|
||||
<Link
|
||||
href="/"
|
||||
aria-label="TurboCI home"
|
||||
className="inline-flex items-center gap-3"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 48 48"
|
||||
aria-hidden="true"
|
||||
className="h-10 w-10 shrink-0"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={mainGradientId}
|
||||
x1="9"
|
||||
y1="9"
|
||||
x2="31"
|
||||
y2="34"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0%" stopColor="#9cf0c0" />
|
||||
<stop offset="100%" stopColor="#42d392" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id={foldGradientId}
|
||||
x1="22"
|
||||
y1="22"
|
||||
x2="36"
|
||||
y2="40"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0%" stopColor="#2bc67e" />
|
||||
<stop offset="100%" stopColor="#1f8458" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<path
|
||||
d="M35 6H23.6c-2 0-3.8 1-4.8 2.7L7.5 28.3c-1.4 2.5.4 5.7 3.2 5.7h9.1c2 0 3.8-1 4.8-2.7l11.2-19.6C39.6 9.2 37.8 6 35 6Z"
|
||||
fill={`url(#${mainGradientId})`}
|
||||
/>
|
||||
<path
|
||||
d="M23.9 24h13.4c2.8 0 4.6 3.1 3.2 5.6l-4.1 7.1c-1 1.7-2.8 2.7-4.8 2.7H18.2c-2.8 0-4.6-3.1-3.2-5.6l4.1-7.1c1-1.7 2.8-2.7 4.8-2.7Z"
|
||||
fill={`url(#${foldGradientId})`}
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span className="font-display text-[1.02rem] font-semibold tracking-tight text-foreground">
|
||||
TurboCI
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,85 @@
|
||||
import useLoginForm from "@/src/hooks/use-login-form";
|
||||
import Tag from "@/twui/components/elements/Tag";
|
||||
import Form from "@/twui/components/form/Form";
|
||||
import Input from "@/twui/components/form/Input";
|
||||
import Button from "@/twui/components/layout/Button";
|
||||
import Stack from "@/twui/components/layout/Stack";
|
||||
import z from "zod";
|
||||
|
||||
export default function LoginForm() {
|
||||
return <Stack></Stack>;
|
||||
const { loading, setLoginData, submitLogin, alert } = useLoginForm();
|
||||
|
||||
return (
|
||||
<Form
|
||||
className="w-full"
|
||||
submitHandler={() => {
|
||||
submitLogin();
|
||||
}}
|
||||
>
|
||||
<Stack className="w-full items-stretch gap-6">
|
||||
{alert?.text ? (
|
||||
<Tag
|
||||
color="error"
|
||||
variant="outlined"
|
||||
className="py-2 px-6 opacity-70"
|
||||
>
|
||||
{alert.text}
|
||||
</Tag>
|
||||
) : null}
|
||||
|
||||
<Input
|
||||
placeholder="Email Address or Username"
|
||||
title="Email/Username"
|
||||
changeHandler={(v) => {
|
||||
const email_schema = z.email();
|
||||
const is_email = email_schema.safeParse(v);
|
||||
|
||||
setLoginData((prev) => ({
|
||||
...prev,
|
||||
email: is_email.success ? v : undefined,
|
||||
username: is_email.success ? undefined : v,
|
||||
}));
|
||||
}}
|
||||
validity={
|
||||
alert?.field_name == "email-username"
|
||||
? {
|
||||
isValid: false,
|
||||
msg: alert?.text,
|
||||
}
|
||||
: {
|
||||
isValid: true,
|
||||
}
|
||||
}
|
||||
showLabel
|
||||
/>
|
||||
|
||||
<Input
|
||||
placeholder="Password"
|
||||
title="Password"
|
||||
type="password"
|
||||
changeHandler={(v) => {
|
||||
setLoginData((prev) => ({
|
||||
...prev,
|
||||
password: v,
|
||||
}));
|
||||
}}
|
||||
validity={
|
||||
alert?.field_name == "password"
|
||||
? {
|
||||
isValid: false,
|
||||
msg: alert?.text,
|
||||
}
|
||||
: {
|
||||
isValid: true,
|
||||
}
|
||||
}
|
||||
showLabel
|
||||
/>
|
||||
|
||||
<Button title="Login" loading={loading} onClick={submitLogin}>
|
||||
Login
|
||||
</Button>
|
||||
</Stack>{" "}
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import Paper from "@/twui/components/elements/Paper";
|
||||
import H2 from "@/twui/components/layout/H2";
|
||||
import Stack from "@/twui/components/layout/Stack";
|
||||
import LoginForm from "./(partials)/login-form";
|
||||
import Span from "@/twui/components/layout/Span";
|
||||
|
||||
export default function Main() {
|
||||
return (
|
||||
<Paper>
|
||||
<Stack>
|
||||
<H2>Home</H2>
|
||||
<Stack className="w-full items-center max-w-lg gap-10">
|
||||
<Stack className="gap-4">
|
||||
<H2>Login</H2>
|
||||
<Span>Welcome Back</Span>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<LoginForm />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { TurboCISignupFormObject } from "@/src/types";
|
||||
import useStatus from "@/twui/components/hooks/useStatus";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function useSignupForm() {
|
||||
const [newUser, setNewUser] = useState<TurboCISignupFormObject>({});
|
||||
const { loading, setLoading } = useStatus();
|
||||
const [isPasswordConfirmed, setIsPasswordConfirmed] = useState(false);
|
||||
|
||||
return {
|
||||
newUser,
|
||||
setNewUser,
|
||||
loading,
|
||||
setLoading,
|
||||
isPasswordConfirmed,
|
||||
setIsPasswordConfirmed,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import Input from "@/twui/components/form/Input";
|
||||
import Button from "@/twui/components/layout/Button";
|
||||
import Stack from "@/twui/components/layout/Stack";
|
||||
import useSignupForm from "../(hooks)/use-signup-form";
|
||||
import fetchApi from "@/twui/components/utils/fetch/fetchApi";
|
||||
import { APIReqObject } from "@/src/types";
|
||||
import { APIResponseObject } from "@moduletrace/datasquirel/dist/package-shared/types";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function SignupForm() {
|
||||
const {
|
||||
newUser,
|
||||
setNewUser,
|
||||
loading,
|
||||
setLoading,
|
||||
isPasswordConfirmed,
|
||||
setIsPasswordConfirmed,
|
||||
} = useSignupForm();
|
||||
|
||||
const is_password_valid = Boolean(
|
||||
isPasswordConfirmed &&
|
||||
Boolean(newUser.password?.match(/./)) &&
|
||||
Boolean(newUser.confirmed_password?.match(/./)),
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack className="w-full items-stretch">
|
||||
<Input
|
||||
placeholder="Eg. John"
|
||||
title="First Name"
|
||||
changeHandler={(v) => {
|
||||
setNewUser((prev) => ({
|
||||
...prev,
|
||||
first_name: v,
|
||||
}));
|
||||
}}
|
||||
showLabel
|
||||
/>
|
||||
<Input
|
||||
placeholder="Eg. Doe"
|
||||
title="Last Name"
|
||||
changeHandler={(v) => {
|
||||
setNewUser((prev) => ({
|
||||
...prev,
|
||||
last_name: v,
|
||||
}));
|
||||
}}
|
||||
showLabel
|
||||
/>
|
||||
<Input
|
||||
placeholder="Email Address or Username"
|
||||
title="Email/Username"
|
||||
type="email"
|
||||
changeHandler={(v) => {
|
||||
setNewUser((prev) => ({
|
||||
...prev,
|
||||
email: v,
|
||||
}));
|
||||
}}
|
||||
showLabel
|
||||
/>
|
||||
<Input
|
||||
placeholder="Password"
|
||||
title="Password"
|
||||
type="password"
|
||||
changeHandler={(v) => {
|
||||
setNewUser((prev) => ({
|
||||
...prev,
|
||||
password: v,
|
||||
}));
|
||||
}}
|
||||
validity={{
|
||||
isValid:
|
||||
!Boolean(newUser.password?.match(/./)) ||
|
||||
!Boolean(newUser.confirmed_password?.match(/./))
|
||||
? true
|
||||
: is_password_valid,
|
||||
msg: `Passwords don't match`,
|
||||
}}
|
||||
showLabel
|
||||
/>
|
||||
<Input
|
||||
placeholder="Confirm Password"
|
||||
title="Confirm Password"
|
||||
type="password"
|
||||
changeHandler={(v) => {
|
||||
setNewUser((prev) => ({
|
||||
...prev,
|
||||
confirmed_password: v,
|
||||
}));
|
||||
|
||||
setIsPasswordConfirmed(v == newUser.password);
|
||||
}}
|
||||
showLabel
|
||||
/>
|
||||
<Button
|
||||
title="Login"
|
||||
onClick={() => {
|
||||
if (!is_password_valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.confirm(`Create Super Admin Account?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
fetchApi<APIReqObject, APIResponseObject>(
|
||||
`/api/auth/signup`,
|
||||
{
|
||||
method: "POST",
|
||||
body: {
|
||||
new_user: newUser,
|
||||
},
|
||||
},
|
||||
)
|
||||
.then((res) => {
|
||||
console.log("res", res);
|
||||
|
||||
if (res.success) {
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
.finally(() => {});
|
||||
}}
|
||||
loading={loading}
|
||||
>
|
||||
Signup
|
||||
</Button>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import H2 from "@/twui/components/layout/H2";
|
||||
import Stack from "@/twui/components/layout/Stack";
|
||||
import SignupForm from "./(partials)/signup-form";
|
||||
|
||||
export default function Main() {
|
||||
return (
|
||||
<Stack className="w-full items-center max-w-lg">
|
||||
<H2>Create Super Admin Account</H2>
|
||||
<SignupForm />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user