Skip to content

Commit

Permalink
feat: add login and register logic to components
Browse files Browse the repository at this point in the history
TODO: Add same logic to organizer registration.
  • Loading branch information
raczu committed Jun 23, 2024
1 parent a1b88eb commit 6c563f6
Show file tree
Hide file tree
Showing 16 changed files with 595 additions and 403 deletions.
32 changes: 32 additions & 0 deletions Client/reasn-client/apps/web/app/login/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use server";

import { LoginRequestSchema } from "@reasn/common/src/schemas/LoginRequest";
import { login } from "@/services/auth";
import { setToken } from "@/lib/token";
import { redirect } from "next/navigation";

export type LoginFormState = {
message?: string | null;
errors?: Record<string, string[]>;
};

export const loginAction = async (
prevState: any,
formData: FormData,
): Promise<LoginFormState | undefined> => {
const result = LoginRequestSchema.safeParse({
email: formData.get("email"),
password: formData.get("password"),
});

if (!result.success) {
return {
errors: result.error.flatten().fieldErrors,
message: "Niepoprawne wartości formularza.",
};
}

const payload = await login(result.data);
setToken(payload);
redirect("/");
};
20 changes: 13 additions & 7 deletions Client/reasn-client/apps/web/app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ import {
} from "@reasn/ui/src/components/shared/form";
import Link from "next/link";
import React, { useRef } from "react";
import { useFormState } from "react-dom";
import { loginAction } from "@/app/login/action";

const LoginPage = () => {
const initialState = { message: null, errors: {} };
const formRef = useRef<HTMLFormElement>(null);

const handleFormSubmit = () => {
console.log("form submitted");
formRef.current?.submit();
};
const [state, formAction] = useFormState(loginAction, initialState);

return (
<>
<div className="relative z-10 flex w-full items-center justify-center sm:w-1/2">
<form className="flex w-full flex-col gap-2 sm:gap-8" ref={formRef}>
<form
className="flex w-full flex-col gap-2 sm:gap-8"
ref={formRef}
action={formAction}
>
<FloatingInput type="email" label="email" name="email" />
<FloatingInput type="password" label="hasło" name="password" />
<div className="flex justify-end gap-2 text-sm">
Expand All @@ -33,7 +36,10 @@ const LoginPage = () => {
<p className="bg-gradient-to-r from-[#FF6363] to-[#1E34FF] bg-clip-text text-right text-4xl font-bold leading-tight text-transparent sm:text-left lg:text-5xl">
miło, że do nas wracasz
</p>
<ButtonBase text={"zaloguj"} onClick={handleFormSubmit} />
<ButtonBase
text={"zaloguj"}
onClick={() => formRef.current?.requestSubmit()}
/>
</div>
<div className="absolute right-[-50%] top-0 z-0 h-full w-4/5 rounded-full bg-[#000b6d] opacity-15 blur-3xl"></div>
</>
Expand Down
54 changes: 54 additions & 0 deletions Client/reasn-client/apps/web/app/register/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use server";

import {
RegisterRequestSchema,
RegisterRequestMapper,
} from "@reasn/common/src/schemas/RegisterRequest";
import { register } from "@/services/auth";
import { redirect } from "next/navigation";
import { z } from "zod";

export type RegisterFormState = {
message?: string | null;
errors?: Record<string, string[]>;
};

const RegisterRequestExtendedSchema = RegisterRequestSchema.extend({
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword);

export type RegisterFormData = z.infer<typeof RegisterRequestExtendedSchema>;

export const registerAction = async (
prevState: any,
formData: FormData,
): Promise<RegisterFormState | undefined> => {
const result = RegisterRequestExtendedSchema.safeParse({
name: formData.get("name"),
surname: formData.get("surname"),
email: formData.get("email"),
username: formData.get("username"),
password: formData.get("password"),
confirmPassword: formData.get("confirmPassword"),
phone: formData.get("phone"),
address: {
country: formData.get("country"),
city: formData.get("city"),
street: formData.get("street"),
state: formData.get("state"),
zipCode: formData.get("postcode"),
},
role: formData.get("role"),
});

if (!result.success) {
console.log(result.error.flatten().fieldErrors);
return {
errors: result.error.flatten().fieldErrors,
message: "Niepoprawne wartości formularza.",
};
}

await register(RegisterRequestMapper.fromObject(result.data));
redirect("/login");
};
169 changes: 124 additions & 45 deletions Client/reasn-client/apps/web/app/register/user/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,67 +4,146 @@ import {
ButtonBase,
FloatingInput,
} from "@reasn/ui/src/components/shared/form";
import React, { useRef, useState } from "react";
import React, { useRef, useState, ChangeEvent } from "react";
import { useFormState } from "react-dom";
import { registerAction } from "@/app/register/action";
import { UserRole } from "@reasn/common/src/enums/schemasEnums";

const RegisterUser = () => {
const initialState = { message: null, errors: {} };
const [currentStep, setCurrentStep] = useState(1);
const formRef = useRef<HTMLFormElement>(null);
const [state, formAction] = useFormState(registerAction, initialState);
const [formData, setFormData] = useState({
name: "",
surname: "",
email: "",
username: "",
password: "",
confirmPassword: "",
phone: "",
country: "",
city: "",
street: "",
state: "",
postcode: "",
role: UserRole.USER,
});

const handleFormSubmit = () => {
console.log("form submitted");
formRef.current?.submit();
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};

const formRef = useRef<HTMLFormElement>(null);

return (
<>
<div className="flex w-full items-center justify-center sm:w-1/2">
<form className="flex w-full flex-col gap-8" ref={formRef}>
{currentStep === 1 && (
<>
<FloatingInput type="text" label="imię" name="name" />
<FloatingInput type="text" label="nazwisko" name="surname" />
<FloatingInput
type="text"
label="nazwa użytkownika"
name="username"
/>
<FloatingInput type="email" label="email" name="email" />
<FloatingInput type="tel" label="numer telefonu" name="phone" />
<FloatingInput type="password" label="hasło" name="password" />
<FloatingInput
type="password"
label="powtórz hasło"
name="confirm-password"
/>
</>
)}
{currentStep === 2 && (
<>
<FloatingInput type="text" label="miasto" name="city" />
<FloatingInput type="text" label="kraj" name="country" />
<FloatingInput type="text" label="ulica" name="street" />
<FloatingInput type="text" label="województwo" name="state" />
<FloatingInput type="text" label="kod pocztowy" name="postcode" />
</>
)}
<form
className="flex w-full flex-col gap-8"
ref={formRef}
action={formAction}
>
<FloatingInput
type={currentStep === 1 ? "text" : "hidden"}
label="imię"
name="name"
defaultValue={formData.name}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 1 ? "text" : "hidden"}
label="nazwisko"
name="surname"
defaultValue={formData.surname}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 1 ? "text" : "hidden"}
label="nazwa użytkownika"
name="username"
defaultValue={formData.username}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 1 ? "email" : "hidden"}
label="email"
name="email"
defaultValue={formData.email}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 1 ? "tel" : "hidden"}
label="numer telefonu"
name="phone"
defaultValue={formData.phone}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 1 ? "password" : "hidden"}
label="hasło"
name="password"
defaultValue={formData.password}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 1 ? "password" : "hidden"}
label="powtórz hasło"
name="confirmPassword"
defaultValue={formData.confirmPassword}
onChange={handleChange}
/>
<input type="hidden" name="role" defaultValue={formData.role} />
<FloatingInput
type={currentStep === 2 ? "text" : "hidden"}
label="miasto"
name="city"
defaultValue={formData.city}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 2 ? "text" : "hidden"}
label="kraj"
name="country"
defaultValue={formData.country}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 2 ? "text" : "hidden"}
label="ulica"
name="street"
defaultValue={formData.street}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 2 ? "text" : "hidden"}
label="województwo"
name="state"
defaultValue={formData.state}
onChange={handleChange}
/>
<FloatingInput
type={currentStep === 2 ? "text" : "hidden"}
label="kod pocztowy"
name="postcode"
defaultValue={formData.postcode}
onChange={handleChange}
/>
</form>
</div>
<div className="relative z-10 flex h-fit w-full flex-col flex-wrap items-end justify-center gap-10 sm:h-full sm:w-1/3 sm:items-start sm:gap-24">
{currentStep === 1 && (
<p className="bg-gradient-to-r from-[#FF6363] to-[#1E34FF] bg-clip-text text-right text-4xl font-bold leading-tight text-transparent sm:text-left lg:text-5xl">
znalazłeś już swój powód do spotkań?
</p>
)}
{currentStep === 2 && (
<p className="bg-gradient-to-r from-[#FF6363] to-[#1E34FF] bg-clip-text text-right text-4xl font-bold leading-tight text-transparent sm:text-left lg:text-5xl">
gdzie powinniśmy cię szukać?
</p>
)}
<p className="bg-gradient-to-r from-[#FF6363] to-[#1E34FF] bg-clip-text text-right text-4xl font-bold leading-tight text-transparent sm:text-left lg:text-5xl">
{currentStep === 1
? "znalazłeś już swój powód do spotkań?"
: "gdzie powinniśmy cię szukać?"}
</p>
<ButtonBase
text={currentStep === 2 ? "zarejestruj" : "kontynuuj"}
onClick={() =>
currentStep === 2
? handleFormSubmit()
? formRef.current?.requestSubmit()
: setCurrentStep(currentStep + 1)
}
/>
Expand Down
2 changes: 1 addition & 1 deletion Client/reasn-client/apps/web/lib/session.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { jwtDecode, JwtPayload } from "jwt-decode";
import { UserRole } from "@reasn/common/src/enums/modelsEnums";
import { UserRole } from "@reasn/common/src/enums/schemasEnums";
import { getToken } from "@/lib/token";

export const SESSION_DEFAULT = {
Expand Down
2 changes: 1 addition & 1 deletion Client/reasn-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"prettier-plugin-tailwindcss": "^0.6.1",
"ts-jest": "^29.1.2",
"ts-node": "^10.9.2",
"turbo": "latest"
"turbo": "^2.0.4"
},
"packageManager": "[email protected]",
"engines": {
Expand Down
Loading

0 comments on commit 6c563f6

Please sign in to comment.