The Authorization header in the apiRequest now utilizes JSON.parse for the accessToken. This change ensures proper parsing and retrieval of the item from the local storage when the window object is defined.
248 lines
6.6 KiB
TypeScript
248 lines
6.6 KiB
TypeScript
"use client";
|
|
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
|
|
import AutoForm, { AutoFormSubmit } from "@/components/auto-form";
|
|
import { UserDataContext } from "@/components/providers/userdata-provider";
|
|
import { ToastBox, toastType } from "@/components/ui/toast-box";
|
|
import { useToast } from "@/components/ui/use-toast";
|
|
import type {
|
|
IApiLoginReq,
|
|
IApiLoginRes,
|
|
IApiRegisterReq,
|
|
IApiRegisterRes,
|
|
} from "@/interfaces/api.interface";
|
|
import { EReturnState, type IStandardisedReturn } from "@/interfaces/general.interface";
|
|
import type { IUserData } from "@/interfaces/userdata.interface";
|
|
import ApiRequest from "@/services/apiRequest";
|
|
import { useLocalStorage } from "@/services/localStorage";
|
|
import { Bug, RefreshCw } from "lucide-react";
|
|
import Link from "next/link";
|
|
import { type Dispatch, type SetStateAction, useContext, useState } from "react";
|
|
import * as z from "zod";
|
|
|
|
const loginSchema = z.object({
|
|
email: z
|
|
.string({
|
|
required_error: "Email is needed.",
|
|
})
|
|
.email({
|
|
message: "Should be a valid email.",
|
|
})
|
|
.describe("Your account email."),
|
|
password: z
|
|
.string({
|
|
required_error: "Password is needed.",
|
|
})
|
|
.describe("Your account password."),
|
|
});
|
|
|
|
const registerSchema = z.object({
|
|
firstName: z.string({
|
|
required_error: "",
|
|
}),
|
|
lastName: z.string(),
|
|
age: z.number().min(18).max(120),
|
|
pseudo: z.string({
|
|
required_error: "",
|
|
}),
|
|
city: z.string({
|
|
required_error: "",
|
|
}),
|
|
|
|
email: z
|
|
.string({
|
|
required_error: "Email is needed.",
|
|
})
|
|
.email("Should be a valid email."),
|
|
password: z
|
|
.string({
|
|
required_error: "Password is needed.",
|
|
})
|
|
.describe("Your account password."),
|
|
});
|
|
|
|
export function AuthForms() {
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [sub, setSub] = useLocalStorage<string | undefined>("sub", "");
|
|
const userContext = useContext(UserDataContext);
|
|
const { toast } = useToast();
|
|
|
|
async function doRegister(
|
|
registerData: IApiRegisterReq,
|
|
userDataSetter: Dispatch<SetStateAction<IUserData | null>>,
|
|
): Promise<IStandardisedReturn<IApiRegisterRes>> {
|
|
console.trace(registerData);
|
|
try {
|
|
const ReqRes = await ApiRequest.standard.post.json<
|
|
IApiRegisterReq,
|
|
IApiRegisterRes
|
|
>("auth/signup", registerData);
|
|
console.trace(ReqRes.data);
|
|
if (ReqRes.data.user) {
|
|
userDataSetter({
|
|
...ReqRes.data.user,
|
|
wallet: {
|
|
uat: Date.now(),
|
|
update_interval: 30_000,
|
|
owned_cryptos: [],
|
|
},
|
|
});
|
|
|
|
setSub(ReqRes.data.access_token);
|
|
}
|
|
console.debug(ReqRes.data.message || "Not additional message from request");
|
|
return {
|
|
state: EReturnState.done,
|
|
resolved: ReqRes.data,
|
|
};
|
|
} catch (error) {
|
|
console.error("Error during registration:", error);
|
|
return {
|
|
state: EReturnState.serverError,
|
|
message: error as string,
|
|
};
|
|
}
|
|
}
|
|
|
|
async function doLogin(
|
|
loginData: IApiLoginReq,
|
|
): Promise<IStandardisedReturn<IApiLoginRes>> {
|
|
try {
|
|
const ReqRes = await ApiRequest.standard.post.json<IApiLoginReq, IApiLoginRes>(
|
|
"auth/signin",
|
|
loginData,
|
|
);
|
|
console.trace(ReqRes.data);
|
|
if (ReqRes.data.access_token) {
|
|
setSub(ReqRes.data.access_token);
|
|
}
|
|
return {
|
|
state: EReturnState.done,
|
|
};
|
|
} catch (err) {
|
|
console.error("Error during login:", err);
|
|
return {
|
|
state: EReturnState.serverError,
|
|
message: err as string,
|
|
};
|
|
}
|
|
}
|
|
|
|
if (!userContext || !userContext.setUserData) {
|
|
return (
|
|
<div
|
|
className={
|
|
"bg-destructive text-destructive-foreground p-3 gap-2 border rounded flex flex-row justify-center items-center"
|
|
}
|
|
>
|
|
<Bug />
|
|
<p>It seems that the context is missing..</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Tabs defaultValue="login" className="w-full p-2 md:w-[400px] my-4">
|
|
<TabsList className="grid w-full grid-cols-2">
|
|
<TabsTrigger value="login">Login</TabsTrigger>
|
|
<TabsTrigger value="register">Register</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="login">
|
|
<AutoForm
|
|
// Pass the schema to the form
|
|
formSchema={loginSchema}
|
|
onSubmit={(data: IApiLoginReq) => {
|
|
setIsLoading(true);
|
|
doLogin(data).then((res) => {
|
|
if (res.state !== EReturnState.done) {
|
|
toast({
|
|
description: res.message || "An unexpected error occurred..",
|
|
variant: "destructive",
|
|
});
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
//toast.custom(<ToastBox message={"Login successful ! \n You will be redirected."} type={toastType.success}/>)
|
|
toast({
|
|
description: "Login successful ! \n You will be redirected.",
|
|
});
|
|
setTimeout(() => {
|
|
setIsLoading(false);
|
|
location.href = "/";
|
|
console.log("Moving to home.");
|
|
}, 3_000);
|
|
});
|
|
}}
|
|
fieldConfig={{
|
|
password: {
|
|
inputProps: {
|
|
type: "password",
|
|
placeholder: "••••••••",
|
|
},
|
|
},
|
|
}}
|
|
>
|
|
<AutoFormSubmit
|
|
disabled={!!isLoading}
|
|
className={"gap-2 disabled:bg-secondary"}
|
|
>
|
|
{/* biome-ignore lint/style/useTemplate: <explanation> */}
|
|
<RefreshCw className={"animate-spin" + isLoading && "hidden"} />
|
|
<p>Login</p>
|
|
</AutoFormSubmit>
|
|
</AutoForm>
|
|
</TabsContent>
|
|
<TabsContent value="register">
|
|
<AutoForm
|
|
// Pass the schema to the form
|
|
formSchema={registerSchema}
|
|
onSubmit={(data: IApiRegisterReq) => {
|
|
setIsLoading(true);
|
|
doRegister(
|
|
data,
|
|
userContext.setUserData as Dispatch<SetStateAction<IUserData | null>>,
|
|
).then((res) => {
|
|
if (res.state !== EReturnState.done) {
|
|
//toast.custom(<ToastBox message={res.message || "An unexpected error occurred.."} type={toastType.error}/>)
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
//toast.custom(<ToastBox message={"Register successful ! \n You will be redirected."} type={toastType.success}/>)
|
|
setTimeout(() => {
|
|
setIsLoading(false);
|
|
//location.href = "/"
|
|
console.log("Moving to home.");
|
|
}, 5_000);
|
|
});
|
|
}}
|
|
fieldConfig={{
|
|
password: {
|
|
inputProps: {
|
|
type: "password",
|
|
placeholder: "••••••••",
|
|
},
|
|
},
|
|
}}
|
|
>
|
|
<AutoFormSubmit
|
|
disabled={!!isLoading}
|
|
className={"gap-2 disabled:bg-secondary"}
|
|
>
|
|
{/* biome-ignore lint/style/useTemplate: <explanation> */}
|
|
<RefreshCw className={"animate-spin" + !isLoading && "hidden"} />
|
|
<p>Register</p>
|
|
</AutoFormSubmit>
|
|
<p className="text-gray-500 text-sm">
|
|
By submitting this form, you agree to our{" "}
|
|
<Link href="#" className="text-primary underline">
|
|
terms and conditions
|
|
</Link>
|
|
.
|
|
</p>
|
|
</AutoForm>
|
|
</TabsContent>
|
|
</Tabs>
|
|
);
|
|
}
|