Compare commits
No commits in common. "5d178709ef83b25470fc20df3b690ca49f0d8d89" and "923c1ce427bd8c41dc4be550459ca387da0d8357" have entirely different histories.
5d178709ef
...
923c1ce427
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,11 +1 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.DS_Store
|
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
*.local
|
|
||||||
count.txt
|
|
||||||
.env
|
|
||||||
.nitro
|
|
||||||
.tanstack
|
|
||||||
.output
|
|
||||||
.vinxi
|
|
||||||
@ -13,8 +13,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroui/react": "^2.8.2",
|
"@heroui/react": "^2.8.2",
|
||||||
"@supabase/ssr": "^0.6.1",
|
|
||||||
"@supabase/supabase-js": "^2.53.1",
|
|
||||||
"@tailwindcss/vite": "^4.1.11",
|
"@tailwindcss/vite": "^4.1.11",
|
||||||
"@tanstack/react-query": "^5.84.1",
|
"@tanstack/react-query": "^5.84.1",
|
||||||
"@tanstack/react-query-devtools": "^5.84.1",
|
"@tanstack/react-query-devtools": "^5.84.1",
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import { parseCookies, setCookie } from '@tanstack/react-start/server'
|
|
||||||
import { createServerClient } from '@supabase/ssr'
|
|
||||||
|
|
||||||
export function getSupabaseServerClient() {
|
|
||||||
return createServerClient(
|
|
||||||
process.env.SUPABASE_URL!,
|
|
||||||
process.env.SUPABASE_ANON_KEY!,
|
|
||||||
{
|
|
||||||
cookies: {
|
|
||||||
getAll() {
|
|
||||||
return Object.entries(parseCookies()).map(([name, value]) => ({
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
setAll(cookies) {
|
|
||||||
cookies.forEach((cookie) => {
|
|
||||||
setCookie(cookie.name, cookie.value)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -9,119 +9,38 @@
|
|||||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||||
|
|
||||||
import { Route as rootRouteImport } from './routes/__root'
|
import { Route as rootRouteImport } from './routes/__root'
|
||||||
import { Route as SignupRouteImport } from './routes/signup'
|
|
||||||
import { Route as LogoutRouteImport } from './routes/logout'
|
|
||||||
import { Route as LoginRouteImport } from './routes/login'
|
|
||||||
import { Route as AuthedRouteImport } from './routes/_authed'
|
|
||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
import { Route as AuthedPostRouteImport } from './routes/_authed/post'
|
|
||||||
|
|
||||||
const SignupRoute = SignupRouteImport.update({
|
|
||||||
id: '/signup',
|
|
||||||
path: '/signup',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const LogoutRoute = LogoutRouteImport.update({
|
|
||||||
id: '/logout',
|
|
||||||
path: '/logout',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const LoginRoute = LoginRouteImport.update({
|
|
||||||
id: '/login',
|
|
||||||
path: '/login',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const AuthedRoute = AuthedRouteImport.update({
|
|
||||||
id: '/_authed',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const IndexRoute = IndexRouteImport.update({
|
const IndexRoute = IndexRouteImport.update({
|
||||||
id: '/',
|
id: '/',
|
||||||
path: '/',
|
path: '/',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
const AuthedPostRoute = AuthedPostRouteImport.update({
|
|
||||||
id: '/post',
|
|
||||||
path: '/post',
|
|
||||||
getParentRoute: () => AuthedRoute,
|
|
||||||
} as any)
|
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/login': typeof LoginRoute
|
|
||||||
'/logout': typeof LogoutRoute
|
|
||||||
'/signup': typeof SignupRoute
|
|
||||||
'/post': typeof AuthedPostRoute
|
|
||||||
}
|
}
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/login': typeof LoginRoute
|
|
||||||
'/logout': typeof LogoutRoute
|
|
||||||
'/signup': typeof SignupRoute
|
|
||||||
'/post': typeof AuthedPostRoute
|
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRouteImport
|
__root__: typeof rootRouteImport
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/_authed': typeof AuthedRouteWithChildren
|
|
||||||
'/login': typeof LoginRoute
|
|
||||||
'/logout': typeof LogoutRoute
|
|
||||||
'/signup': typeof SignupRoute
|
|
||||||
'/_authed/post': typeof AuthedPostRoute
|
|
||||||
}
|
}
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
fullPaths: '/' | '/login' | '/logout' | '/signup' | '/post'
|
fullPaths: '/'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to: '/' | '/login' | '/logout' | '/signup' | '/post'
|
to: '/'
|
||||||
id:
|
id: '__root__' | '/'
|
||||||
| '__root__'
|
|
||||||
| '/'
|
|
||||||
| '/_authed'
|
|
||||||
| '/login'
|
|
||||||
| '/logout'
|
|
||||||
| '/signup'
|
|
||||||
| '/_authed/post'
|
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute
|
||||||
AuthedRoute: typeof AuthedRouteWithChildren
|
|
||||||
LoginRoute: typeof LoginRoute
|
|
||||||
LogoutRoute: typeof LogoutRoute
|
|
||||||
SignupRoute: typeof SignupRoute
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@tanstack/react-router' {
|
declare module '@tanstack/react-router' {
|
||||||
interface FileRoutesByPath {
|
interface FileRoutesByPath {
|
||||||
'/signup': {
|
|
||||||
id: '/signup'
|
|
||||||
path: '/signup'
|
|
||||||
fullPath: '/signup'
|
|
||||||
preLoaderRoute: typeof SignupRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/logout': {
|
|
||||||
id: '/logout'
|
|
||||||
path: '/logout'
|
|
||||||
fullPath: '/logout'
|
|
||||||
preLoaderRoute: typeof LogoutRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/login': {
|
|
||||||
id: '/login'
|
|
||||||
path: '/login'
|
|
||||||
fullPath: '/login'
|
|
||||||
preLoaderRoute: typeof LoginRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/_authed': {
|
|
||||||
id: '/_authed'
|
|
||||||
path: ''
|
|
||||||
fullPath: ''
|
|
||||||
preLoaderRoute: typeof AuthedRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/': {
|
'/': {
|
||||||
id: '/'
|
id: '/'
|
||||||
path: '/'
|
path: '/'
|
||||||
@ -129,33 +48,11 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof IndexRouteImport
|
preLoaderRoute: typeof IndexRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
'/_authed/post': {
|
|
||||||
id: '/_authed/post'
|
|
||||||
path: '/post'
|
|
||||||
fullPath: '/post'
|
|
||||||
preLoaderRoute: typeof AuthedPostRouteImport
|
|
||||||
parentRoute: typeof AuthedRoute
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AuthedRouteChildren {
|
|
||||||
AuthedPostRoute: typeof AuthedPostRoute
|
|
||||||
}
|
|
||||||
|
|
||||||
const AuthedRouteChildren: AuthedRouteChildren = {
|
|
||||||
AuthedPostRoute: AuthedPostRoute,
|
|
||||||
}
|
|
||||||
|
|
||||||
const AuthedRouteWithChildren =
|
|
||||||
AuthedRoute._addFileChildren(AuthedRouteChildren)
|
|
||||||
|
|
||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
IndexRoute: IndexRoute,
|
IndexRoute: IndexRoute,
|
||||||
AuthedRoute: AuthedRouteWithChildren,
|
|
||||||
LoginRoute: LoginRoute,
|
|
||||||
LogoutRoute: LogoutRoute,
|
|
||||||
SignupRoute: SignupRoute,
|
|
||||||
}
|
}
|
||||||
export const routeTree = rootRouteImport
|
export const routeTree = rootRouteImport
|
||||||
._addFileChildren(rootRouteChildren)
|
._addFileChildren(rootRouteChildren)
|
||||||
|
|||||||
@ -1,74 +1,53 @@
|
|||||||
import css from "@styles/globals.css?url";
|
import css from "@styles/globals.css?url"
|
||||||
import type { QueryClient } from "@tanstack/react-query";
|
import type { QueryClient } from "@tanstack/react-query"
|
||||||
import {
|
import {
|
||||||
createRootRouteWithContext,
|
createRootRouteWithContext,
|
||||||
HeadContent,
|
HeadContent,
|
||||||
Scripts,
|
Scripts
|
||||||
} from "@tanstack/react-router";
|
} from "@tanstack/react-router"
|
||||||
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"
|
||||||
import { HeroUIProvider } from "@/integrations/heroui/provider";
|
import { HeroUIProvider } from "@/integrations/heroui/provider"
|
||||||
import { createServerFn } from "@tanstack/react-start";
|
|
||||||
import { getSupabaseServerClient } from "@/integrations/supabase/supabase";
|
|
||||||
|
|
||||||
interface MyRouterContext {
|
interface MyRouterContext {
|
||||||
queryClient: QueryClient;
|
queryClient: QueryClient
|
||||||
user: null;
|
|
||||||
}
|
}
|
||||||
const fetchUser = createServerFn({ method: "GET" }).handler(async () => {
|
|
||||||
const supabase = getSupabaseServerClient();
|
|
||||||
const { data, error: _error } = await supabase.auth.getUser();
|
|
||||||
|
|
||||||
if (!data.user?.email) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
email: data.user.email,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Route = createRootRouteWithContext<MyRouterContext>()({
|
export const Route = createRootRouteWithContext<MyRouterContext>()({
|
||||||
beforeLoad: async () => {
|
head: () => ({
|
||||||
const user = await fetchUser();
|
meta: [
|
||||||
return {
|
{
|
||||||
user,
|
charSet: "utf-8"
|
||||||
};
|
},
|
||||||
},
|
{
|
||||||
head: () => ({
|
name: "viewport",
|
||||||
meta: [
|
content: "width=device-width, initial-scale=1"
|
||||||
{
|
},
|
||||||
charSet: "utf-8",
|
{
|
||||||
},
|
title: "TanStack Start Starter"
|
||||||
{
|
}
|
||||||
name: "viewport",
|
],
|
||||||
content: "width=device-width, initial-scale=1",
|
links: [
|
||||||
},
|
{
|
||||||
{
|
rel: "stylesheet",
|
||||||
title: "TanStack Start Starter",
|
href: css
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
links: [
|
}),
|
||||||
{
|
|
||||||
rel: "stylesheet",
|
|
||||||
href: css,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
|
|
||||||
shellComponent: RootDocument,
|
shellComponent: RootDocument
|
||||||
});
|
})
|
||||||
|
|
||||||
function RootDocument({ children }: { children: React.ReactNode }) {
|
function RootDocument({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<html lang="es">
|
<html lang="es">
|
||||||
<head>
|
<head>
|
||||||
<HeadContent />
|
<HeadContent />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<HeroUIProvider>{children}</HeroUIProvider>
|
<HeroUIProvider>{children}</HeroUIProvider>
|
||||||
<TanStackRouterDevtools />
|
<TanStackRouterDevtools />
|
||||||
<Scripts />
|
<Scripts />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
import { createFileRoute } from "@tanstack/react-router";
|
|
||||||
import { createServerFn } from "@tanstack/react-start";
|
|
||||||
// import { Login } from "../components/Login";
|
|
||||||
import { getSupabaseServerClient } from "@/integrations/supabase/supabase";
|
|
||||||
|
|
||||||
export const loginFn = createServerFn({ method: "POST" })
|
|
||||||
.validator((d: { email: string; password: string }) => d)
|
|
||||||
.handler(async ({ data }) => {
|
|
||||||
const supabase = getSupabaseServerClient();
|
|
||||||
const response = await supabase.auth.signInWithPassword({
|
|
||||||
email: data.email,
|
|
||||||
password: data.password,
|
|
||||||
});
|
|
||||||
console.log(response);
|
|
||||||
if (response.error) {
|
|
||||||
return {
|
|
||||||
error: true,
|
|
||||||
message: response.error.message,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/_authed")({
|
|
||||||
beforeLoad: ({ context }) => {
|
|
||||||
console.log("contextw", context);
|
|
||||||
if (!context?.user) {
|
|
||||||
throw new Error("Not authenticated");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
errorComponent: ({ error }) => {
|
|
||||||
if (error.message === "Not authenticated") {
|
|
||||||
<p>
|
|
||||||
Not authenticated. Please <a href="/login">login</a>.
|
|
||||||
</p>;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
import { Button } from "@heroui/react";
|
|
||||||
import { createFileRoute } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/_authed/post")({
|
|
||||||
component: RouteComponent,
|
|
||||||
});
|
|
||||||
|
|
||||||
function RouteComponent() {
|
|
||||||
const navigate = Route.useNavigate();
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
Hello "/_authed/post"!{" "}
|
|
||||||
<div>
|
|
||||||
{" "}
|
|
||||||
<Button
|
|
||||||
onPress={() =>
|
|
||||||
navigate({
|
|
||||||
to: "/logout",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Logout
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,45 +1,39 @@
|
|||||||
import logo from "@assets/logo.svg";
|
import logo from "@assets/logo.svg"
|
||||||
import { Button } from "@heroui/react";
|
import { createFileRoute } from "@tanstack/react-router"
|
||||||
import { createFileRoute, getRouteApi } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/")({
|
export const Route = createFileRoute("/")({
|
||||||
component: App,
|
component: App
|
||||||
});
|
})
|
||||||
const apiRouter = getRouteApi("/");
|
|
||||||
function App() {
|
function App() {
|
||||||
const navigate = apiRouter.useNavigate();
|
return (
|
||||||
return (
|
<div className="text-center">
|
||||||
<div className="text-center">
|
<header className="min-h-screen flex flex-col items-center justify-center bg-[#282c34] text-white text-[calc(10px+2vmin)]">
|
||||||
<header className="min-h-screen flex flex-col items-center justify-center bg-[#282c34] text-white text-[calc(10px+2vmin)]">
|
<img
|
||||||
<img
|
src={logo}
|
||||||
src={logo}
|
className="h-[40vmin] pointer-events-none animate-[spin_20s_linear_infinite]"
|
||||||
className="h-[40vmin] pointer-events-none animate-[spin_20s_linear_infinite]"
|
alt="logo"
|
||||||
alt="logo"
|
/>
|
||||||
/>
|
<p>
|
||||||
<p>
|
Edit <code>src/routes/index.tsx</code> and save to reload.
|
||||||
Edit <code>src/routes/index.tsx</code> and save to reload.
|
</p>
|
||||||
</p>
|
<a
|
||||||
<div className="grid grid-cols-2 gap-4 mt-4">
|
className="text-[#61dafb] hover:underline"
|
||||||
<Button
|
href="https://reactjs.org"
|
||||||
onPress={() =>
|
target="_blank"
|
||||||
navigate({
|
rel="noopener noreferrer"
|
||||||
to: "/login",
|
>
|
||||||
})
|
Learn React
|
||||||
}
|
</a>
|
||||||
>
|
<a
|
||||||
Login
|
className="text-[#61dafb] hover:underline"
|
||||||
</Button>
|
href="https://tanstack.com"
|
||||||
<Button
|
target="_blank"
|
||||||
onPress={() => {
|
rel="noopener noreferrer"
|
||||||
navigate({
|
>
|
||||||
to: "/signup",
|
Learn TanStack
|
||||||
});
|
</a>
|
||||||
}}
|
</header>
|
||||||
>
|
</div>
|
||||||
Signup
|
)
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,59 +0,0 @@
|
|||||||
import { useMutation } from "@tanstack/react-query";
|
|
||||||
import { createFileRoute, getRouteApi } from "@tanstack/react-router";
|
|
||||||
import { useServerFn } from "@tanstack/react-start";
|
|
||||||
import { loginFn } from "./_authed";
|
|
||||||
import { Button, Form, Input } from "@heroui/react";
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/login")({
|
|
||||||
component: LoginComp,
|
|
||||||
});
|
|
||||||
const apiRouter = getRouteApi("/login");
|
|
||||||
function LoginComp() {
|
|
||||||
const navigate = apiRouter.useNavigate();
|
|
||||||
const loginFunction = useServerFn(loginFn);
|
|
||||||
const loginMutation = useMutation({
|
|
||||||
mutationKey: ["login"],
|
|
||||||
mutationFn: async (data: { email: string; password: string }) => {
|
|
||||||
return loginFunction({
|
|
||||||
data: {
|
|
||||||
email: data.email,
|
|
||||||
password: data.password,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSuccess: (data, ctx) => {
|
|
||||||
console.log("Login successful", data);
|
|
||||||
console.log("ctx", ctx);
|
|
||||||
|
|
||||||
if (data?.error) {
|
|
||||||
alert(data.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
navigate({
|
|
||||||
to: "/post",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
console.log("No se ha podido procesar el login", error);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<div className="flex justify-center items-center flex-col h-screen">
|
|
||||||
<p className="font-semibold mb-3">Login</p>
|
|
||||||
<Form
|
|
||||||
className="grid gap-2 max-w-sm w-full"
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const formData = new FormData(e.currentTarget);
|
|
||||||
const email = formData.get("email") as string;
|
|
||||||
const password = formData.get("password") as string;
|
|
||||||
loginMutation.mutate({ email, password });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Input name="email" type="email" placeholder="Email" />
|
|
||||||
<Input name="password" type="password" placeholder="Password" />
|
|
||||||
<Button type="submit">Enviar</Button>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { getSupabaseServerClient } from "@/integrations/supabase/supabase";
|
|
||||||
import { redirect, createFileRoute } from "@tanstack/react-router";
|
|
||||||
import { createServerFn } from "@tanstack/react-start";
|
|
||||||
|
|
||||||
const logoutFn = createServerFn().handler(async () => {
|
|
||||||
const supabase = getSupabaseServerClient();
|
|
||||||
const { error } = await supabase.auth.signOut();
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return {
|
|
||||||
error: true,
|
|
||||||
message: error.message,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
throw redirect({
|
|
||||||
href: "/",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/logout")({
|
|
||||||
preload: false,
|
|
||||||
loader: () => logoutFn(),
|
|
||||||
});
|
|
||||||
@ -1,75 +0,0 @@
|
|||||||
import { redirect, createFileRoute } from "@tanstack/react-router";
|
|
||||||
import { createServerFn, useServerFn } from "@tanstack/react-start";
|
|
||||||
import { getSupabaseServerClient } from "@/integrations/supabase/supabase";
|
|
||||||
import { Button, Form, Input } from "@heroui/react";
|
|
||||||
import { useMutation } from "@tanstack/react-query";
|
|
||||||
|
|
||||||
export const signupFn = createServerFn({ method: "POST" })
|
|
||||||
.validator(
|
|
||||||
(d: { email: string; password: string; redirectUrl?: string }) => d
|
|
||||||
)
|
|
||||||
.handler(async ({ data }) => {
|
|
||||||
const supabase = getSupabaseServerClient();
|
|
||||||
const { error } = await supabase.auth.signUp({
|
|
||||||
email: data.email,
|
|
||||||
password: data.password,
|
|
||||||
});
|
|
||||||
if (error) {
|
|
||||||
return {
|
|
||||||
error: true,
|
|
||||||
message: error.message,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
throw redirect({
|
|
||||||
href: data.redirectUrl || "/",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/signup")({
|
|
||||||
component: SignupComp,
|
|
||||||
});
|
|
||||||
|
|
||||||
function SignupComp() {
|
|
||||||
const signup = useServerFn(signupFn);
|
|
||||||
const signupMutation = useMutation({
|
|
||||||
mutationKey: ["signup"],
|
|
||||||
mutationFn: async (data: {
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
redirectUrl?: string;
|
|
||||||
}) => {
|
|
||||||
return signup({
|
|
||||||
data: {
|
|
||||||
email: data.email,
|
|
||||||
password: data.password,
|
|
||||||
redirectUrl: data.redirectUrl,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<div className="flex justify-center items-center flex-col h-screen">
|
|
||||||
<p className="font-semibold mb-3">Signup</p>
|
|
||||||
<Form
|
|
||||||
className="grid gap-2 max-w-5xl w-full"
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const formData = new FormData(e.currentTarget);
|
|
||||||
const email = formData.get("email") as string;
|
|
||||||
const password = formData.get("password") as string;
|
|
||||||
signupMutation.mutate({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Input name="email" type="email" placeholder="Email" />
|
|
||||||
<Input name="password" type="password" placeholder="Password" />
|
|
||||||
<Button type="submit" isLoading={signupMutation.isPending}>
|
|
||||||
Enviar
|
|
||||||
</Button>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user