feat: add dashboard route and update user registration and login flows
This commit is contained in:
parent
974337af2b
commit
e1c0866cdf
28
package-lock.json
generated
28
package-lock.json
generated
@ -17,6 +17,7 @@
|
|||||||
"@tanstack/react-router-with-query": "^1.130.12",
|
"@tanstack/react-router-with-query": "^1.130.12",
|
||||||
"@tanstack/react-start": "^1.130.15",
|
"@tanstack/react-start": "^1.130.15",
|
||||||
"@tanstack/router-plugin": "^1.130.15",
|
"@tanstack/router-plugin": "^1.130.15",
|
||||||
|
"@vis.gl/react-google-maps": "^1.5.5",
|
||||||
"drizzle-orm": "^0.44.4",
|
"drizzle-orm": "^0.44.4",
|
||||||
"framer-motion": "^12.23.12",
|
"framer-motion": "^12.23.12",
|
||||||
"postgres": "^3.4.7",
|
"postgres": "^3.4.7",
|
||||||
@ -30,6 +31,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.1.3",
|
"@biomejs/biome": "2.1.3",
|
||||||
"@tanstack/react-router-ssr-query": "^1.131.5",
|
"@tanstack/react-router-ssr-query": "^1.131.5",
|
||||||
|
"@types/google.maps": "^3.58.1",
|
||||||
"@types/react": "^19.1.9",
|
"@types/react": "^19.1.9",
|
||||||
"@types/react-dom": "^19.1.7",
|
"@types/react-dom": "^19.1.7",
|
||||||
"@vitejs/plugin-react": "^4.7.0",
|
"@vitejs/plugin-react": "^4.7.0",
|
||||||
@ -7650,6 +7652,12 @@
|
|||||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/google.maps": {
|
||||||
|
"version": "3.58.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.58.1.tgz",
|
||||||
|
"integrity": "sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "24.2.0",
|
"version": "24.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.0.tgz",
|
||||||
@ -7867,6 +7875,20 @@
|
|||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vis.gl/react-google-maps": {
|
||||||
|
"version": "1.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vis.gl/react-google-maps/-/react-google-maps-1.5.5.tgz",
|
||||||
|
"integrity": "sha512-LgHtK1AtE2/BN4dPoK05oWu0jWmeDdyX0Ffqi+mZc+M4apaHn2sUxxKXAxhPF90O9vcsiou/ntm6/XBWX+gpqw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/google.maps": "^3.54.10",
|
||||||
|
"fast-deep-equal": "^3.1.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": ">=16.8.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vitejs/plugin-react": {
|
"node_modules/@vitejs/plugin-react": {
|
||||||
"version": "4.7.0",
|
"version": "4.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
|
||||||
@ -9929,6 +9951,12 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-deep-equal": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fast-fifo": {
|
"node_modules/fast-fifo": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
"@tanstack/react-router-with-query": "^1.130.12",
|
"@tanstack/react-router-with-query": "^1.130.12",
|
||||||
"@tanstack/react-start": "^1.130.15",
|
"@tanstack/react-start": "^1.130.15",
|
||||||
"@tanstack/router-plugin": "^1.130.15",
|
"@tanstack/router-plugin": "^1.130.15",
|
||||||
|
"@vis.gl/react-google-maps": "^1.5.5",
|
||||||
"drizzle-orm": "^0.44.4",
|
"drizzle-orm": "^0.44.4",
|
||||||
"framer-motion": "^12.23.12",
|
"framer-motion": "^12.23.12",
|
||||||
"postgres": "^3.4.7",
|
"postgres": "^3.4.7",
|
||||||
@ -36,6 +37,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.1.3",
|
"@biomejs/biome": "2.1.3",
|
||||||
"@tanstack/react-router-ssr-query": "^1.131.5",
|
"@tanstack/react-router-ssr-query": "^1.131.5",
|
||||||
|
"@types/google.maps": "^3.58.1",
|
||||||
"@types/react": "^19.1.9",
|
"@types/react": "^19.1.9",
|
||||||
"@types/react-dom": "^19.1.7",
|
"@types/react-dom": "^19.1.7",
|
||||||
"@vitejs/plugin-react": "^4.7.0",
|
"@vitejs/plugin-react": "^4.7.0",
|
||||||
|
|||||||
@ -1,15 +1,10 @@
|
|||||||
|
|
||||||
import { drizzle } from 'drizzle-orm/postgres-js'
|
import { drizzle } from 'drizzle-orm/postgres-js'
|
||||||
import postgres from 'postgres'
|
import postgres from 'postgres'
|
||||||
import { users } from './db/schema'
|
|
||||||
|
|
||||||
const connectionString = process.env.DATABASE_URL!
|
const connectionString = process.env.DATABASE_URL!
|
||||||
|
|
||||||
// Disable prefetch as it is not supported for "Transaction" pool mode
|
// Disable prefetch as it is not supported for "Transaction" pool mode
|
||||||
const client = postgres(connectionString, { prepare: false })
|
const client = postgres(connectionString, { prepare: false })
|
||||||
export const db = drizzle(client);
|
export const db = drizzle(client);
|
||||||
|
|
||||||
const allUsers = await db.select().from(users);
|
|
||||||
|
|
||||||
console.log(allUsers);
|
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ export const useLogin = () => {
|
|||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success("Login successful! Redirecting to posts..", { id: "login" })
|
toast.success("Login successful! Redirecting to posts..", { id: "login" })
|
||||||
navigate({
|
navigate({
|
||||||
to: "/post"
|
to: "/dashboard"
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
|
|||||||
@ -19,12 +19,13 @@ export const getUser = createServerFn().handler(async () => {
|
|||||||
message: error?.message ?? "Unknown error"
|
message: error?.message ?? "Unknown error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log(data)
|
||||||
return {
|
return {
|
||||||
user: {
|
user: {
|
||||||
id: data.user.id,
|
id: data.user.id,
|
||||||
email: data.user.email,
|
email: data.user.email,
|
||||||
name: data.user.user_metadata.name || ""
|
name: data.user.user_metadata.name || "",
|
||||||
|
location: data.user.user_metadata.location || ""
|
||||||
},
|
},
|
||||||
error: false
|
error: false
|
||||||
}
|
}
|
||||||
@ -76,7 +77,13 @@ export const signupUser = createServerFn({ method: "POST" })
|
|||||||
const supabase = getSupabaseServerClient()
|
const supabase = getSupabaseServerClient()
|
||||||
const { error } = await supabase.auth.signUp({
|
const { error } = await supabase.auth.signUp({
|
||||||
email: data.email,
|
email: data.email,
|
||||||
password: data.password
|
password: data.password,
|
||||||
|
options: {
|
||||||
|
data: {
|
||||||
|
name: data.name,
|
||||||
|
location: data.location
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if (error) {
|
if (error) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -8,6 +8,8 @@ export const loginFormSchema = z.object({
|
|||||||
export const signupFormSchema = z.object({
|
export const signupFormSchema = z.object({
|
||||||
email: z.email("Invalid email address"),
|
email: z.email("Invalid email address"),
|
||||||
password: z.string().min(6, "Password must be at least 6 characters long"),
|
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"),
|
||||||
redirectUrl: z.string().optional()
|
redirectUrl: z.string().optional()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import { Route as LoginRouteImport } from './routes/login'
|
|||||||
import { Route as AuthedRouteImport } from './routes/_authed'
|
import { Route as AuthedRouteImport } from './routes/_authed'
|
||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
import { Route as AuthedRegisterRouteImport } from './routes/_authed/register'
|
import { Route as AuthedRegisterRouteImport } from './routes/_authed/register'
|
||||||
import { Route as AuthedPostRouteImport } from './routes/_authed/post'
|
import { Route as AuthedDashboardRouteImport } from './routes/_authed/dashboard'
|
||||||
|
|
||||||
const SignupRoute = SignupRouteImport.update({
|
const SignupRoute = SignupRouteImport.update({
|
||||||
id: '/signup',
|
id: '/signup',
|
||||||
@ -46,9 +46,9 @@ const AuthedRegisterRoute = AuthedRegisterRouteImport.update({
|
|||||||
path: '/register',
|
path: '/register',
|
||||||
getParentRoute: () => AuthedRoute,
|
getParentRoute: () => AuthedRoute,
|
||||||
} as any)
|
} as any)
|
||||||
const AuthedPostRoute = AuthedPostRouteImport.update({
|
const AuthedDashboardRoute = AuthedDashboardRouteImport.update({
|
||||||
id: '/post',
|
id: '/dashboard',
|
||||||
path: '/post',
|
path: '/dashboard',
|
||||||
getParentRoute: () => AuthedRoute,
|
getParentRoute: () => AuthedRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ export interface FileRoutesByFullPath {
|
|||||||
'/login': typeof LoginRoute
|
'/login': typeof LoginRoute
|
||||||
'/logout': typeof LogoutRoute
|
'/logout': typeof LogoutRoute
|
||||||
'/signup': typeof SignupRoute
|
'/signup': typeof SignupRoute
|
||||||
'/post': typeof AuthedPostRoute
|
'/dashboard': typeof AuthedDashboardRoute
|
||||||
'/register': typeof AuthedRegisterRoute
|
'/register': typeof AuthedRegisterRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
@ -65,7 +65,7 @@ export interface FileRoutesByTo {
|
|||||||
'/login': typeof LoginRoute
|
'/login': typeof LoginRoute
|
||||||
'/logout': typeof LogoutRoute
|
'/logout': typeof LogoutRoute
|
||||||
'/signup': typeof SignupRoute
|
'/signup': typeof SignupRoute
|
||||||
'/post': typeof AuthedPostRoute
|
'/dashboard': typeof AuthedDashboardRoute
|
||||||
'/register': typeof AuthedRegisterRoute
|
'/register': typeof AuthedRegisterRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
@ -75,14 +75,14 @@ export interface FileRoutesById {
|
|||||||
'/login': typeof LoginRoute
|
'/login': typeof LoginRoute
|
||||||
'/logout': typeof LogoutRoute
|
'/logout': typeof LogoutRoute
|
||||||
'/signup': typeof SignupRoute
|
'/signup': typeof SignupRoute
|
||||||
'/_authed/post': typeof AuthedPostRoute
|
'/_authed/dashboard': typeof AuthedDashboardRoute
|
||||||
'/_authed/register': typeof AuthedRegisterRoute
|
'/_authed/register': typeof AuthedRegisterRoute
|
||||||
}
|
}
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
fullPaths: '/' | '/login' | '/logout' | '/signup' | '/post' | '/register'
|
fullPaths: '/' | '/login' | '/logout' | '/signup' | '/dashboard' | '/register'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to: '/' | '/login' | '/logout' | '/signup' | '/post' | '/register'
|
to: '/' | '/login' | '/logout' | '/signup' | '/dashboard' | '/register'
|
||||||
id:
|
id:
|
||||||
| '__root__'
|
| '__root__'
|
||||||
| '/'
|
| '/'
|
||||||
@ -90,7 +90,7 @@ export interface FileRouteTypes {
|
|||||||
| '/login'
|
| '/login'
|
||||||
| '/logout'
|
| '/logout'
|
||||||
| '/signup'
|
| '/signup'
|
||||||
| '/_authed/post'
|
| '/_authed/dashboard'
|
||||||
| '/_authed/register'
|
| '/_authed/register'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
@ -146,23 +146,23 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof AuthedRegisterRouteImport
|
preLoaderRoute: typeof AuthedRegisterRouteImport
|
||||||
parentRoute: typeof AuthedRoute
|
parentRoute: typeof AuthedRoute
|
||||||
}
|
}
|
||||||
'/_authed/post': {
|
'/_authed/dashboard': {
|
||||||
id: '/_authed/post'
|
id: '/_authed/dashboard'
|
||||||
path: '/post'
|
path: '/dashboard'
|
||||||
fullPath: '/post'
|
fullPath: '/dashboard'
|
||||||
preLoaderRoute: typeof AuthedPostRouteImport
|
preLoaderRoute: typeof AuthedDashboardRouteImport
|
||||||
parentRoute: typeof AuthedRoute
|
parentRoute: typeof AuthedRoute
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AuthedRouteChildren {
|
interface AuthedRouteChildren {
|
||||||
AuthedPostRoute: typeof AuthedPostRoute
|
AuthedDashboardRoute: typeof AuthedDashboardRoute
|
||||||
AuthedRegisterRoute: typeof AuthedRegisterRoute
|
AuthedRegisterRoute: typeof AuthedRegisterRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const AuthedRouteChildren: AuthedRouteChildren = {
|
const AuthedRouteChildren: AuthedRouteChildren = {
|
||||||
AuthedPostRoute: AuthedPostRoute,
|
AuthedDashboardRoute: AuthedDashboardRoute,
|
||||||
AuthedRegisterRoute: AuthedRegisterRoute,
|
AuthedRegisterRoute: AuthedRegisterRoute,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,13 +3,14 @@ import { useQuery } from "@tanstack/react-query"
|
|||||||
import { createFileRoute } from "@tanstack/react-router"
|
import { createFileRoute } from "@tanstack/react-router"
|
||||||
import { getAllUsers, getProfile } from "@/lib/server/user"
|
import { getAllUsers, getProfile } from "@/lib/server/user"
|
||||||
|
|
||||||
export const Route = createFileRoute("/_authed/post")({
|
export const Route = createFileRoute("/_authed/dashboard")({
|
||||||
component: RouteComponent
|
component: RouteComponent
|
||||||
})
|
})
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
const navigate = Route.useNavigate()
|
const navigate = Route.useNavigate()
|
||||||
const { user } = Route.useRouteContext()
|
const { user } = Route.useRouteContext()
|
||||||
|
console.log("User in dashboard:", user)
|
||||||
const { data } = useQuery({
|
const { data } = useQuery({
|
||||||
queryKey: ["users"],
|
queryKey: ["users"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@ -29,7 +30,7 @@ function RouteComponent() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
Hello "/_authed/post"!{" "}
|
Hello "/_authed/dashboard"!{" "}
|
||||||
<div>
|
<div>
|
||||||
{" "}
|
{" "}
|
||||||
<Button
|
<Button
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { Button, Form, Input, Textarea } from "@heroui/react"
|
import { Button, Form, Input, Slider, Textarea } from "@heroui/react"
|
||||||
import { createFileRoute } from "@tanstack/react-router"
|
import { createFileRoute } from "@tanstack/react-router"
|
||||||
import type { FormEvent } from "react"
|
import type { FormEvent } from "react"
|
||||||
import { useProfile } from "@/lib/hooks/user/useCreateUser"
|
import { useProfile } from "@/lib/hooks/user/useCreateUser"
|
||||||
@ -26,17 +26,16 @@ function RouteComponent() {
|
|||||||
validationErrors={errors}
|
validationErrors={errors}
|
||||||
>
|
>
|
||||||
<Input name="name" label="Nombre completo" isRequired />
|
<Input name="name" label="Nombre completo" isRequired />
|
||||||
<Input name="location" label="Lugar" />
|
|
||||||
<Input name="company" label="Empresa" />
|
<Input name="company" label="Empresa" />
|
||||||
<Input name="role" label="Cargo" />
|
<Input name="role" label="Cargo" />
|
||||||
<Textarea name="description" label="Descripción" />
|
<Textarea name="description" label="Descripción" />
|
||||||
<Textarea name="differentiator" label="¿Qué te hace diferente?" />
|
<Textarea name="differentiator" label="¿Qué te hace diferente?" />
|
||||||
<Input name="coverage_areas" label="Areas de cobertura" />
|
<Slider name="coverage_areas" label="Areas de cobertura" />
|
||||||
<Input name="services" label="Servicios" />
|
<Input name="services" label="Servicios" />{" "}
|
||||||
projects → text[] (proyectos destacados)
|
{/* Crear varios checkboxes */}
|
||||||
contact → text (número de teléfono u otro medio)
|
<Button isLoading={isPending} type="submit">
|
||||||
email → text
|
Crear usuario
|
||||||
<Button isLoading={isPending} type="submit">Crear usuario</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,7 +7,7 @@ export const Route = createFileRoute("/login")({
|
|||||||
beforeLoad: ({ context }) => {
|
beforeLoad: ({ context }) => {
|
||||||
if (!context?.error) {
|
if (!context?.error) {
|
||||||
throw redirect({
|
throw redirect({
|
||||||
to: "/post"
|
to: "/dashboard"
|
||||||
})
|
})
|
||||||
// TODO: Redirect to login page
|
// TODO: Redirect to login page
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,9 @@ function SignupComp() {
|
|||||||
|
|
||||||
signup({
|
signup({
|
||||||
email: formData.get("email") as string,
|
email: formData.get("email") as string,
|
||||||
password: formData.get("password") as string
|
password: formData.get("password") as string,
|
||||||
|
name: formData.get("nombre") as string,
|
||||||
|
location: formData.get("location") as string
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +33,8 @@ function SignupComp() {
|
|||||||
>
|
>
|
||||||
<Input name="email" type="email" label="Email" />
|
<Input name="email" type="email" label="Email" />
|
||||||
<Input name="password" type="password" label="Password" />
|
<Input name="password" type="password" label="Password" />
|
||||||
|
<Input name="nombre" label="Name" />
|
||||||
|
<Input name="location" label="Location" />
|
||||||
<Button type="submit" isLoading={isPending}>
|
<Button type="submit" isLoading={isPending}>
|
||||||
Enviar
|
Enviar
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user