Skip to content

Commit

Permalink
Merge pull request #26 from No-Country-simulation/front-lazaro
Browse files Browse the repository at this point in the history
login and register form connected to API
  • Loading branch information
lazaronazareno authored Oct 18, 2024
2 parents 15ea384 + ba4d5f3 commit 2fa336d
Show file tree
Hide file tree
Showing 11 changed files with 535 additions and 52 deletions.
2 changes: 1 addition & 1 deletion client/.env.example
Original file line number Diff line number Diff line change
@@ -1 +1 @@
API_URL=https://clinica-medica-production.up.railway.app/api/v1/
API_URL=https://clinica-medica-production.up.railway.app
66 changes: 66 additions & 0 deletions client/src/actions/auth/login-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'use server'
import { schemaLogin } from '@/schemas'

const BASE_URL = process.env.API_URL

export const loginUser = async (formData: FormData) => {
const url = BASE_URL + '/user'

const nameFromForm = formData.get('name') as string
const passwordFromForm = formData.get('password') as string

const validatedFields = schemaLogin.safeParse({
name: nameFromForm,
password: passwordFromForm,
})

if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
message: 'Debe rellenar todos los campos. Error al iniciar sesión.',
}
}

const body = {
name: nameFromForm,
password: passwordFromForm,
}

try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
})

const responseData = await response.json()

if (!responseData) {
return {
errors: {},
loginError: null,
message: 'Algo salió mal...',
}
}

if (responseData.error) {
return {
errors: {},
loginError: responseData.error,
message: 'Error al iniciar sesión',
}
}

return {
success: 'Inicio de sesión exitoso',
}
} catch (error) {
return {
errors: {},
loginError: 'Error al comunicarse con el servidor' + error,
message: 'Algo salió mal durante el inicio de sesión.' + error,
}
}
}
76 changes: 74 additions & 2 deletions client/src/actions/auth/register-action.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,79 @@
"use server"
'use server'
import { schemaRegister } from '@/schemas'

const BASE_URL = process.env.API_URL

export const createUser = async () => {
export const createUser = async (formData: FormData) => {
const url = BASE_URL + '/patients/create'

const nameFromForm = formData.get('name') as string
const emailFromForm = formData.get('email') as string
const passwordFromForm = formData.get('password') as string
const phoneFromForm = formData.get('phone') as string
const insurerFromForm = formData.get('insurer') as string

const validatedFields = schemaRegister.safeParse({
name: nameFromForm,
email: emailFromForm,
password: passwordFromForm,
phone: phoneFromForm,
insurer: insurerFromForm,
})

if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
message: 'Debe rellenar todos los campos. Error al Registrarse.',
}
}

const body = {
user: {
name: nameFromForm,
email: emailFromForm,
password: passwordFromForm,
phone: phoneFromForm,
img: 'https://res.cloudinary.com/db395v0wf/image/upload/v1729121057/vooufndzyzyyfnyi4zwv.png',
active: true,
},
insurer: insurerFromForm,
}

try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
})

const responseData = await response.json()

if (!responseData) {
return {
errors: {},
registerError: null,
message: 'Algo salio mal...',
}
}

if (responseData.message) {
return {
errors: {},
registerError: responseData.message,
message: 'Error al registrarse',
}
}

return {
success: 'Registro exitoso',
}
} catch (error) {
return {
errors: {},
registerError: 'Error al comunicarse con el servidor' + error,
message: 'Algo salió mal durante el registro.' + error,
}
}
}
2 changes: 1 addition & 1 deletion client/src/app/(patients)/specialty/[name]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default async function SpecialtyPage({ params }: { params: { name: string
<div className="max-w-[1200px] mx-auto ms-[240px] px-4">
<BackButton />
<div className="max-w-[900px]">
<h1 className="text-[32px] font-medium text-[#1A2C33]">Traumatología</h1>
<h1 className="text-[32px] font-medium text-[#1A2C33]">{specialty.charAt(0).toUpperCase() + specialty.slice(1)}</h1>

<div className="my-8 flex flex-col gap-6">
{
Expand Down
30 changes: 20 additions & 10 deletions client/src/schemas/schema-auth.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { z } from "zod"
import { z } from 'zod'

export const schemaRegister = z.object({
userName: z.string({ message: "Name required" }).min(8, { message: "first and last name" }),
email: z.string({ message: "Email required" }).email({ message: "Email invalid" }),
dni: z.string({ message: "DNI required" }).min(8, ({ message: "enter a valid DNI" })).regex(/^\d+$/, { message: "DNI must contain only numbers" }),
city: z.string(),
direction: z.string(),
password: z.string({ message: "Password required" }).min(6, { message: "min 6 character" }),
name: z
.string({ message: 'Nombre requerido' })
.min(8, { message: 'Rellene con su Nombre completo' }),
email: z
.string({ message: 'Email requerido' })
.email({ message: 'Email invalido' }),
phone: z
.string({ message: 'Telefono requerido' })
.min(10, { message: 'Numero de telefono debe tener al menos 10 digitos' })
.regex(/^\d+$/, { message: 'Phone must contain only numbers' }),
insurer: z.string({ message: 'Aseguradora u Obra social requerida' }),
password: z
.string({ message: 'Contraseña requerido' })
.min(6, { message: 'Minimo 6 Caracteres' }),
})

export const schemaLogin = z.object({
email: z.string({ message: "Email required" }).email({ message: "Email invalid" }),
password: z.string({ message: "Password required" }).min(6, { message: "min 6 character" }),
})
name: z.string({ message: 'Nombre requerido' }),
password: z
.string({ message: 'Contraseña requerido' })
.min(6, { message: 'Minimo 6 Caracteres' }),
})
82 changes: 67 additions & 15 deletions client/src/ui/auth/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,88 @@ import { zodResolver } from "@hookform/resolvers/zod"
import { schemaLogin } from "@/schemas"
import { useForm } from "react-hook-form"
import { z } from "zod"
import Link from "next/link"
import { useState } from "react"
import { SubmitButton } from "@/ui"
import { useRouter } from "next/navigation";
import { loginUser } from "@/actions/auth/login-action"

type TypeFormData = z.infer<typeof schemaLogin>

export function LoginForm() {

const { register, handleSubmit, reset, formState: { errors } } = useForm<TypeFormData>({ resolver: zodResolver(schemaLogin) })
const router = useRouter()

const submit = handleSubmit(data => {
const { register, handleSubmit, reset, formState: { errors } } = useForm<TypeFormData>({
resolver: zodResolver(schemaLogin)
})

const [success, setSuccess] = useState<string | undefined>('')
const [loading, setLoading] = useState<boolean>(false)
const [error, setError] = useState<string>('')

const submit = handleSubmit(async data => {
console.log(data)

reset({
email: "",
password: "",
})
const formData = new FormData()
formData.append('name', data.name)
formData.append('password', data.password)

setLoading(true)
setError('')
setSuccess('')

try {
const result = await loginUser(formData)
console.log(result)
setLoading(false)

if (result.errors || result.loginError) {
setError(result.message + ': ' + result.loginError || 'Error desconocido al iniciar sesión.')
return
}

if (result.success) {
setSuccess(result.success)
reset({
name: "",
password: ""
})
setTimeout(() => {
router.push('/dashboard')
}, 1000)
}
} catch (error: unknown) {
setLoading(false)
setError('Ha ocurrido un error al iniciar sesión: ' + error)
}
})

return (
<form onSubmit={submit} className="grid w-[500px] p-5 border gap-2">
<form onSubmit={submit} className="grid w-[500px] p-6 border gap-4 rounded-3xl text-secondaryBlue-700">
<h2 className="text-4xl my-2 font-medium">Iniciar Sesión</h2>

<label htmlFor="name" className="text-xl">Nombre <span className="text-red-500">*</span></label>
<input
type="text"
id="name"
{...register("name")}
className="min-h-9 border rounded-3xl bg-[#F6F7F7] px-4 py-2"
/>
{errors.name && <p className="text-red-500">{errors.name.message}</p>}

<label htmlFor="email">Email</label>
<input type="email" id="email" {...register("email")} className="border" />
{errors.email && (<p className="text-red-500">{errors.email.message}</p>)}
<label htmlFor="password" className="text-xl">Contraseña <span className="text-red-500">*</span></label>
<input
type="password"
id="password"
{...register("password")}
className="min-h-9 border rounded-3xl bg-[#F6F7F7] px-4 py-2"
/>
{errors.password && <p className="text-red-500">{errors.password.message}</p>}

<label htmlFor="password">Password </label>
<input type="password" id="password" {...register("password")} className="border" />
{errors.password && (<p className="text-red-500">{errors.password.message}</p>)}
<SubmitButton loading={loading} variant="dark" loadingText="Cargando" text="Iniciar Sesión" className="place-self-center mt-2" />

<Link href={'/dashboard'} className="border">Enviar</Link>
{success && <p className="text-xl text-emerald-500">{success}</p>}
{error && <p className="text-xl text-red-600">{error}</p>}
</form>
)
}
Loading

0 comments on commit 2fa336d

Please sign in to comment.