login #2
41
AGENTS.md
Normal file
41
AGENTS.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# AGENTS.md — findyourpilot
|
||||
|
||||
Project context for AI coding agents. This file defines which skill files to load
|
||||
depending on the task at hand.
|
||||
|
||||
<!-- intent-skills:start -->
|
||||
# Skill mappings - when working in these areas, load the linked skill file into context.
|
||||
skills:
|
||||
- task: "Building or modifying routes, loaders, search params, or navigation with TanStack Router"
|
||||
load: "node_modules/.pnpm/@tanstack+router-core@1.167.5/node_modules/@tanstack/router-core/skills/router-core/SKILL.md"
|
||||
|
||||
- task: "Working with route search params, type-safe URL state, or Zod-validated search params"
|
||||
load: "node_modules/.pnpm/@tanstack+router-core@1.167.5/node_modules/@tanstack/router-core/skills/router-core/search-params/SKILL.md"
|
||||
|
||||
- task: "Implementing route guards, authentication redirects, or protected routes"
|
||||
load: "node_modules/.pnpm/@tanstack+router-core@1.167.5/node_modules/@tanstack/router-core/skills/router-core/auth-and-guards/SKILL.md"
|
||||
|
||||
- task: "Loading data in routes, using loaders, or integrating with TanStack Query"
|
||||
load: "node_modules/.pnpm/@tanstack+router-core@1.167.5/node_modules/@tanstack/router-core/skills/router-core/data-loading/SKILL.md"
|
||||
|
||||
- task: "Creating server functions, SSR patterns, full-stack logic, or the TanStack Start execution model"
|
||||
load: "node_modules/.pnpm/@tanstack+start-client-core@1.166.13/node_modules/@tanstack/start-client-core/skills/start-core/SKILL.md"
|
||||
|
||||
- task: "Creating or modifying createServerFn, input validation on server functions, or handling server errors"
|
||||
load: "node_modules/.pnpm/@tanstack+start-client-core@1.166.13/node_modules/@tanstack/start-client-core/skills/start-core/server-functions/SKILL.md"
|
||||
|
||||
- task: "Creating middleware, request middleware, or passing context between server functions"
|
||||
load: "node_modules/.pnpm/@tanstack+start-client-core@1.166.13/node_modules/@tanstack/start-client-core/skills/start-core/middleware/SKILL.md"
|
||||
|
||||
- task: "Creating API endpoints or server-only routes (server property on createFileRoute)"
|
||||
load: "node_modules/.pnpm/@tanstack+start-client-core@1.166.13/node_modules/@tanstack/start-client-core/skills/start-core/server-routes/SKILL.md"
|
||||
|
||||
- task: "Deploying the app to Cloudflare, Vercel, Netlify, Node.js/Docker, or configuring SSR/SPA/prerendering"
|
||||
load: "node_modules/.pnpm/@tanstack+start-client-core@1.166.13/node_modules/@tanstack/start-client-core/skills/start-core/deployment/SKILL.md"
|
||||
|
||||
- task: "Writing, reviewing, or optimising Supabase/Postgres queries, schema design, RLS policies, or migrations"
|
||||
load: ".agents/skills/supabase-postgres-best-practices/SKILL.md"
|
||||
|
||||
- task: "Designing or improving UI layouts, dashboards, component composition, or interactive product interfaces with HeroUI"
|
||||
load: ".agents/skills/interface-design/SKILL.md"
|
||||
<!-- intent-skills:end -->
|
||||
46
package.json
46
package.json
@@ -14,43 +14,45 @@
|
||||
"machine-translate": "inlang machine translate --project project.inlang"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroui/react": "^3.0.0-beta.8",
|
||||
"@heroui/styles": "^3.0.0-beta.8",
|
||||
"@sentry/tanstackstart-react": "^10.42.0",
|
||||
"@heroui/react": "^3.0.0-rc.1",
|
||||
"@heroui/styles": "^3.0.0-rc.1",
|
||||
"@sentry/tanstackstart-react": "^10.45.0",
|
||||
"@supabase/ssr": "^0.9.0",
|
||||
"@supabase/supabase-js": "^2.99.1",
|
||||
"@tailwindcss/vite": "^4.2.1",
|
||||
"@tanstack/react-query": "^5.90.21",
|
||||
"@tanstack/react-router": "^1.166.7",
|
||||
"@tanstack/react-router-ssr-query": "^1.166.7",
|
||||
"@tanstack/react-start": "^1.166.8",
|
||||
"@tanstack/router-plugin": "^1.166.7",
|
||||
"@supabase/supabase-js": "^2.99.3",
|
||||
"@tailwindcss/vite": "^4.2.2",
|
||||
"@tanstack/react-query": "^5.91.2",
|
||||
"@tanstack/react-router": "^1.167.5",
|
||||
"@tanstack/react-router-ssr-query": "^1.166.9",
|
||||
"@tanstack/react-start": "^1.166.17",
|
||||
"@tanstack/router-plugin": "^1.166.14",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.577.0",
|
||||
"maplibre-gl": "^5.19.0",
|
||||
"maplibre-gl": "^5.20.2",
|
||||
"nitro": "^3.0.1-alpha.2",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"tailwindcss": "^4.2.1",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"tailwindcss": "^4.2.2",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.4.6",
|
||||
"@inlang/paraglide-js": "^2.13.1",
|
||||
"@tanstack/devtools-vite": "^0.5.5",
|
||||
"@tanstack/react-devtools": "^0.9.13",
|
||||
"@biomejs/biome": "^2.4.8",
|
||||
"@inlang/paraglide-js": "^2.15.0",
|
||||
"@tanstack/devtools-vite": "^0.6.0",
|
||||
"@tanstack/react-devtools": "^0.10.0",
|
||||
"@tanstack/react-query-devtools": "^5.91.3",
|
||||
"@tanstack/react-router-devtools": "^1.166.7",
|
||||
"@tanstack/react-router-devtools": "^1.166.9",
|
||||
"@testing-library/dom": "^10.4.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/node": "^22.19.15",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
"jsdom": "^28.1.0",
|
||||
"@vitejs/plugin-react": "^6.0.1",
|
||||
"jsdom": "^29.0.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1",
|
||||
"vite": "^8.0.1",
|
||||
"vite-tsconfig-paths": "^6.1.1",
|
||||
"vitest": "^3.2.4"
|
||||
"vitest": "^4.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
3858
pnpm-lock.yaml
generated
3858
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,38 +1,44 @@
|
||||
import { toast } from "@heroui/react"
|
||||
import { useMutation } from "@tanstack/react-query"
|
||||
import { useNavigate } from "@tanstack/react-router"
|
||||
import type z from "zod"
|
||||
import { user } from "@/lib/server/user"
|
||||
import { signupFormSchema } from "@/lib/validation/user"
|
||||
import type { signupClientFormSchema } from "@/lib/validation/user"
|
||||
|
||||
type TSignupForm = z.infer<typeof signupFormSchema>
|
||||
type TSignupClientForm = z.infer<typeof signupClientFormSchema>
|
||||
|
||||
export const useSignup = () => {
|
||||
const navigate = useNavigate()
|
||||
const signup = useMutation({
|
||||
const signupMutation = useMutation({
|
||||
mutationKey: ["signup"],
|
||||
mutationFn: async (data: TSignupForm) => user.signup({ data }),
|
||||
onSuccess: () => {
|
||||
navigate({
|
||||
to: "/access/login"
|
||||
})
|
||||
mutationFn: async (data: TSignupClientForm) => {
|
||||
const { confirmPassword: _, ...serverData } = data
|
||||
const response = await user.signup({ data: serverData })
|
||||
|
||||
if (response && "error" in response && response.error) {
|
||||
throw new Error(
|
||||
"message" in response
|
||||
? (response.message as string)
|
||||
: "Error desconocido"
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const validateSignup = (formData: TSignupForm) => {
|
||||
if (!signupFormSchema.safeParse(formData).success) {
|
||||
toast.danger("Signup failed. Please check your input.")
|
||||
const validateSignup = (formData: TSignupClientForm) => {
|
||||
if (formData.password !== formData.confirmPassword) {
|
||||
toast.danger("Las contraseñas no coinciden")
|
||||
return
|
||||
}
|
||||
const promise = signup.mutateAsync(formData)
|
||||
|
||||
const promise = signupMutation.mutateAsync(formData)
|
||||
toast.promise(promise, {
|
||||
loading: "Signing up...",
|
||||
success: "Signup successful! Redirecting to login...",
|
||||
error: "Signup failed!"
|
||||
loading: "Creando tu cuenta...",
|
||||
success: "¡Cuenta creada! Revisa tu correo para confirmarla.",
|
||||
error: (error: Error) => error.message
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
signup: validateSignup,
|
||||
isPending: signup.isPending
|
||||
isPending: signupMutation.isPending
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
import * as z from "zod"
|
||||
|
||||
export const loginFormSchema = z.object({
|
||||
email: z.email("Invalid email address"),
|
||||
password: z.string().min(1, "Password must be at least 1 character long")
|
||||
email: z.email("Introduce un correo válido"),
|
||||
password: z.string().min(1, "La contraseña es obligatoria")
|
||||
})
|
||||
|
||||
export const signupFormSchema = z.object({
|
||||
email: z.email("Invalid email address"),
|
||||
password: z.string().min(6, "Password must be at least 6 characters long"),
|
||||
name: z.string().min(1, "The field is required"),
|
||||
location: z.string().min(1, "The field is required"),
|
||||
email: z.email("Introduce un correo válido"),
|
||||
password: z.string().min(6, "La contraseña debe tener al menos 6 caracteres"),
|
||||
name: z.string().min(1, "El nombre es obligatorio"),
|
||||
location: z.string().min(1, "La ubicación es obligatoria"),
|
||||
redirectUrl: z.string().optional()
|
||||
})
|
||||
|
||||
// Schema extendido para el formulario cliente (incluye confirmación de contraseña)
|
||||
export const signupClientFormSchema = signupFormSchema
|
||||
.extend({
|
||||
confirmPassword: z.string().min(6, "Confirma tu contraseña")
|
||||
})
|
||||
.refine((data) => data.password === data.confirmPassword, {
|
||||
message: "Las contraseñas no coinciden",
|
||||
path: ["confirmPassword"]
|
||||
})
|
||||
|
||||
export const profileFormSchema = z.object({
|
||||
id: z.uuid(),
|
||||
firstName: z.string().min(1, "First name is required"),
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
FieldError,
|
||||
Fieldset,
|
||||
Form,
|
||||
@@ -30,108 +29,105 @@ function RouteComponent() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card.Content>
|
||||
<Form onSubmit={handleFormSubmit} className="flex flex-col gap-4">
|
||||
<Fieldset>
|
||||
<Fieldset.Group>
|
||||
<TextField
|
||||
type="email"
|
||||
name="email"
|
||||
variant="secondary"
|
||||
className="py-4 text-lg"
|
||||
isRequired
|
||||
defaultValue={import.meta.env.VITE_LOGIN_USER}
|
||||
>
|
||||
<Label isRequired className="ml-4 text-lg">
|
||||
Correo
|
||||
</Label>
|
||||
<Input placeholder="Introduce tu correo" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
<TextField
|
||||
type="password"
|
||||
name="password"
|
||||
variant="secondary"
|
||||
className="py-4 text-lg"
|
||||
isRequired
|
||||
defaultValue={import.meta.env.VITE_PASSWORD_USER}
|
||||
>
|
||||
<Label isRequired className="ml-4 text-lg">
|
||||
Contraseña
|
||||
</Label>
|
||||
<Input placeholder="Introduce tu contraseña" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
</Fieldset.Group>
|
||||
</Fieldset>
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
type="submit"
|
||||
className="py-6 px-8 w-full text-white text-lg"
|
||||
size="lg"
|
||||
isPending={isPending}
|
||||
<>
|
||||
<Form onSubmit={handleFormSubmit} className="flex flex-col gap-4">
|
||||
<Fieldset>
|
||||
<Fieldset.Group>
|
||||
<TextField
|
||||
type="email"
|
||||
name="email"
|
||||
variant="secondary"
|
||||
className="py-4 text-lg"
|
||||
isRequired
|
||||
defaultValue={import.meta.env.VITE_LOGIN_USER}
|
||||
>
|
||||
{isPending ? <Spinner /> : <LogIn size={18} />}
|
||||
Entrar
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</Card.Content>
|
||||
<Card.Footer>
|
||||
<div className="flex justify-evenly w-full gap-4">
|
||||
<Button size="lg" className="w-full" variant="secondary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd" clipRule="evenodd">
|
||||
<path
|
||||
fill="#f44336"
|
||||
d="M7.209 1.061c.725-.081 1.154-.081 1.933 0a6.57 6.57 0 0 1 3.65 1.82a100 100 0 0 0-1.986 1.93q-1.876-1.59-4.188-.734q-1.696.78-2.362 2.528a78 78 0 0 1-2.148-1.658a.26.26 0 0 0-.16-.027q1.683-3.245 5.26-3.86"
|
||||
opacity="0.987"
|
||||
/>
|
||||
<path
|
||||
fill="#ffc107"
|
||||
d="M1.946 4.92q.085-.013.161.027a78 78 0 0 0 2.148 1.658A7.6 7.6 0 0 0 4.04 7.99q.037.678.215 1.331L2 11.116Q.527 8.038 1.946 4.92"
|
||||
opacity="0.997"
|
||||
/>
|
||||
<path
|
||||
fill="#448aff"
|
||||
d="M12.685 13.29a26 26 0 0 0-2.202-1.74q1.15-.812 1.396-2.228H8.122V6.713q3.25-.027 6.497.055q.616 3.345-1.423 6.032a7 7 0 0 1-.51.49"
|
||||
opacity="0.999"
|
||||
/>
|
||||
<path
|
||||
fill="#43a047"
|
||||
d="M4.255 9.322q1.23 3.057 4.51 2.854a3.94 3.94 0 0 0 1.718-.626q1.148.812 2.202 1.74a6.62 6.62 0 0 1-4.027 1.684a6.4 6.4 0 0 1-1.02 0Q3.82 14.524 2 11.116z"
|
||||
opacity="0.993"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
Google
|
||||
</Button>
|
||||
<Button size="lg" className="w-full" variant="secondary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="256"
|
||||
height="256"
|
||||
viewBox="0 0 256 256"
|
||||
<Label isRequired className="ml-4 text-lg">
|
||||
Correo
|
||||
</Label>
|
||||
<Input placeholder="Introduce tu correo" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
<TextField
|
||||
type="password"
|
||||
name="password"
|
||||
variant="secondary"
|
||||
className="py-4 text-lg"
|
||||
isRequired
|
||||
defaultValue={import.meta.env.VITE_PASSWORD_USER}
|
||||
>
|
||||
<Label isRequired className="ml-4 text-lg">
|
||||
Contraseña
|
||||
</Label>
|
||||
<Input placeholder="Introduce tu contraseña" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
</Fieldset.Group>
|
||||
</Fieldset>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
className="py-6 px-8 w-full text-white text-lg"
|
||||
size="lg"
|
||||
isPending={isPending}
|
||||
>
|
||||
{isPending ? <Spinner /> : <LogIn size={18} />}
|
||||
Entrar
|
||||
</Button>
|
||||
</Form>
|
||||
<div className="flex justify-evenly w-full gap-4 mt-2">
|
||||
<Button size="lg" className="w-full" variant="secondary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd" clipRule="evenodd">
|
||||
<path
|
||||
fill="#1877f2"
|
||||
d="M256 128C256 57.308 198.692 0 128 0S0 57.308 0 128c0 63.888 46.808 116.843 108 126.445V165H75.5v-37H108V99.8c0-32.08 19.11-49.8 48.348-49.8C170.352 50 185 52.5 185 52.5V84h-16.14C152.959 84 148 93.867 148 103.99V128h35.5l-5.675 37H148v89.445c61.192-9.602 108-62.556 108-126.445"
|
||||
fill="#f44336"
|
||||
d="M7.209 1.061c.725-.081 1.154-.081 1.933 0a6.57 6.57 0 0 1 3.65 1.82a100 100 0 0 0-1.986 1.93q-1.876-1.59-4.188-.734q-1.696.78-2.362 2.528a78 78 0 0 1-2.148-1.658a.26.26 0 0 0-.16-.027q1.683-3.245 5.26-3.86"
|
||||
opacity="0.987"
|
||||
/>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="m177.825 165l5.675-37H148v-24.01C148 93.866 152.959 84 168.86 84H185V52.5S170.352 50 156.347 50C127.11 50 108 67.72 108 99.8V128H75.5v37H108v89.445A129 129 0 0 0 128 256a129 129 0 0 0 20-1.555V165z"
|
||||
fill="#ffc107"
|
||||
d="M1.946 4.92q.085-.013.161.027a78 78 0 0 0 2.148 1.658A7.6 7.6 0 0 0 4.04 7.99q.037.678.215 1.331L2 11.116Q.527 8.038 1.946 4.92"
|
||||
opacity="0.997"
|
||||
/>
|
||||
</svg>
|
||||
Facebook
|
||||
</Button>
|
||||
</div>
|
||||
</Card.Footer>
|
||||
</div>
|
||||
<path
|
||||
fill="#448aff"
|
||||
d="M12.685 13.29a26 26 0 0 0-2.202-1.74q1.15-.812 1.396-2.228H8.122V6.713q3.25-.027 6.497.055q.616 3.345-1.423 6.032a7 7 0 0 1-.51.49"
|
||||
opacity="0.999"
|
||||
/>
|
||||
<path
|
||||
fill="#43a047"
|
||||
d="M4.255 9.322q1.23 3.057 4.51 2.854a3.94 3.94 0 0 0 1.718-.626q1.148.812 2.202 1.74a6.62 6.62 0 0 1-4.027 1.684a6.4 6.4 0 0 1-1.02 0Q3.82 14.524 2 11.116z"
|
||||
opacity="0.993"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
Google
|
||||
</Button>
|
||||
<Button size="lg" className="w-full" variant="secondary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 256 256"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill="#1877f2"
|
||||
d="M256 128C256 57.308 198.692 0 128 0S0 57.308 0 128c0 63.888 46.808 116.843 108 126.445V165H75.5v-37H108V99.8c0-32.08 19.11-49.8 48.348-49.8C170.352 50 185 52.5 185 52.5V84h-16.14C152.959 84 148 93.867 148 103.99V128h35.5l-5.675 37H148v89.445c61.192-9.602 108-62.556 108-126.445"
|
||||
/>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="m177.825 165l5.675-37H148v-24.01C148 93.866 152.959 84 168.86 84H185V52.5S170.352 50 156.347 50C127.11 50 108 67.72 108 99.8V128H75.5v37H108v89.445A129 129 0 0 0 128 256a129 129 0 0 0 20-1.555V165z"
|
||||
/>
|
||||
</svg>
|
||||
Facebook
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
TextField
|
||||
} from "@heroui/react"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { LogIn } from "lucide-react"
|
||||
import { UserPlus } from "lucide-react"
|
||||
import { useSignup } from "@/lib/hooks/useSignup"
|
||||
|
||||
export const Route = createFileRoute("/access/register")({
|
||||
@@ -22,67 +22,105 @@ function RouteComponent() {
|
||||
const handleFormSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault()
|
||||
const formData = new FormData(e.currentTarget)
|
||||
const email = formData.get("email") as string
|
||||
const password = formData.get("password") as string
|
||||
const location = formData.get("location") as string
|
||||
const name = formData.get("name") as string
|
||||
|
||||
signup({
|
||||
email,
|
||||
password,
|
||||
location,
|
||||
name
|
||||
email: formData.get("email") as string,
|
||||
password: formData.get("password") as string,
|
||||
confirmPassword: formData.get("confirmPassword") as string,
|
||||
location: formData.get("location") as string,
|
||||
name: formData.get("name") as string
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<Form onSubmit={handleFormSubmit} className="flex flex-col gap-4">
|
||||
<Fieldset>
|
||||
<Fieldset.Group>
|
||||
<TextField
|
||||
type="text"
|
||||
name="name"
|
||||
variant="secondary"
|
||||
className="py-2 text-lg"
|
||||
isRequired
|
||||
>
|
||||
<Label isRequired className="ml-4 text-lg">
|
||||
Nombre completo
|
||||
</Label>
|
||||
<Input placeholder="Tu nombre y apellidos" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
<TextField
|
||||
type="email"
|
||||
name="email"
|
||||
variant="secondary"
|
||||
className="py-4 text-lg"
|
||||
className="py-2 text-lg"
|
||||
isRequired
|
||||
>
|
||||
<Label>Correo</Label>
|
||||
<Input placeholder="Introduce tu correo" />
|
||||
<Label isRequired className="ml-4 text-lg">
|
||||
Correo electrónico
|
||||
</Label>
|
||||
<Input placeholder="tu@correo.com" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
<TextField
|
||||
type="text"
|
||||
name="location"
|
||||
variant="secondary"
|
||||
className="py-2 text-lg"
|
||||
isRequired
|
||||
>
|
||||
<Label isRequired className="ml-4 text-lg">
|
||||
Ubicación
|
||||
</Label>
|
||||
<Input placeholder="Ciudad, País" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
<TextField
|
||||
type="password"
|
||||
name="password"
|
||||
variant="secondary"
|
||||
className="py-2 text-lg"
|
||||
isRequired
|
||||
>
|
||||
<Label isRequired className="ml-4 text-lg">
|
||||
Contraseña
|
||||
</Label>
|
||||
<Input placeholder="Mínimo 6 caracteres" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
<TextField
|
||||
type="password"
|
||||
name="confirmPassword"
|
||||
variant="secondary"
|
||||
className="py-2 text-lg"
|
||||
isRequired
|
||||
>
|
||||
<Label isRequired className="ml-4 text-lg">
|
||||
Confirmar contraseña
|
||||
</Label>
|
||||
<Input placeholder="Repite tu contraseña" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
</Fieldset.Group>
|
||||
</Fieldset>
|
||||
<TextField
|
||||
type="password"
|
||||
name="password"
|
||||
variant="secondary"
|
||||
className="py-4 text-lg"
|
||||
isRequired
|
||||
<Button
|
||||
type="submit"
|
||||
className="py-6 px-8 w-full text-white text-lg"
|
||||
size="lg"
|
||||
isPending={isPending}
|
||||
>
|
||||
<Label>Contraseña</Label>
|
||||
<Input placeholder="Introduce tu contraseña" />
|
||||
<FieldError />
|
||||
</TextField>
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
type="submit"
|
||||
className="py-6 px-8 w-full text-white text-lg"
|
||||
size="lg"
|
||||
isPending={isPending}
|
||||
>
|
||||
{isPending ? <Spinner /> : <LogIn size={18} />}
|
||||
Entrar
|
||||
</Button>
|
||||
</div>
|
||||
{isPending ? <Spinner /> : <UserPlus size={18} />}
|
||||
Crear cuenta
|
||||
</Button>
|
||||
</Form>
|
||||
<div className="flex justify-evenly w-full gap-4">
|
||||
<div className="flex justify-evenly w-full gap-4 mt-2">
|
||||
<Button size="lg" className="w-full" variant="secondary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd" clipRule="evenodd">
|
||||
<path
|
||||
@@ -112,9 +150,10 @@ function RouteComponent() {
|
||||
<Button size="lg" className="w-full" variant="secondary">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="256"
|
||||
height="256"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 256 256"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill="#1877f2"
|
||||
@@ -128,6 +167,6 @@ function RouteComponent() {
|
||||
Facebook
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user