mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
Add runtime selection feature between Bun and Node.js
This commit is contained in:
@@ -31,10 +31,10 @@ export default function SignInForm({
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success("Sign in successful");
|
||||
navigate({
|
||||
to: "/dashboard",
|
||||
});
|
||||
toast.success("Sign in successful");
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.error.message);
|
||||
|
||||
@@ -9,156 +9,156 @@ import { Input } from "./ui/input";
|
||||
import { Label } from "./ui/label";
|
||||
|
||||
export default function SignUpForm({
|
||||
onSwitchToSignIn,
|
||||
onSwitchToSignIn,
|
||||
}: {
|
||||
onSwitchToSignIn: () => void;
|
||||
onSwitchToSignIn: () => void;
|
||||
}) {
|
||||
const navigate = useNavigate({
|
||||
from: "/",
|
||||
});
|
||||
const { isPending } = authClient.useSession();
|
||||
const navigate = useNavigate({
|
||||
from: "/",
|
||||
});
|
||||
const { isPending } = authClient.useSession();
|
||||
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
email: "",
|
||||
password: "",
|
||||
name: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
await authClient.signUp.email(
|
||||
{
|
||||
email: value.email,
|
||||
password: value.password,
|
||||
name: value.name,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success("Sign up successful");
|
||||
navigate({
|
||||
to: "/dashboard",
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.error.message);
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
validators: {
|
||||
onSubmit: z.object({
|
||||
name: z.string().min(2, "Name must be at least 2 characters"),
|
||||
email: z.string().email("Invalid email address"),
|
||||
password: z.string().min(6, "Password must be at least 6 characters"),
|
||||
}),
|
||||
},
|
||||
});
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
email: "",
|
||||
password: "",
|
||||
name: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
await authClient.signUp.email(
|
||||
{
|
||||
email: value.email,
|
||||
password: value.password,
|
||||
name: value.name,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
navigate({
|
||||
to: "/dashboard",
|
||||
});
|
||||
toast.success("Sign up successful");
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.error.message);
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
validators: {
|
||||
onSubmit: z.object({
|
||||
name: z.string().min(2, "Name must be at least 2 characters"),
|
||||
email: z.string().email("Invalid email address"),
|
||||
password: z.string().min(6, "Password must be at least 6 characters"),
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
if (isPending) {
|
||||
return <Loader />;
|
||||
}
|
||||
if (isPending) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx-auto mt-10 max-w-md p-6">
|
||||
<h1 className="mb-6 text-center text-3xl font-bold">Create Account</h1>
|
||||
return (
|
||||
<div className="mx-auto mt-10 max-w-md p-6">
|
||||
<h1 className="mb-6 text-center text-3xl font-bold">Create Account</h1>
|
||||
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
void form.handleSubmit();
|
||||
}}
|
||||
className="space-y-4"
|
||||
>
|
||||
<div>
|
||||
<form.Field name="name">
|
||||
{(field) => (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor={field.name}>Name</Label>
|
||||
<Input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
/>
|
||||
{field.state.meta.errors.map((error) => (
|
||||
<p key={error?.message} className="text-red-500">
|
||||
{error?.message}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</form.Field>
|
||||
</div>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
void form.handleSubmit();
|
||||
}}
|
||||
className="space-y-4"
|
||||
>
|
||||
<div>
|
||||
<form.Field name="name">
|
||||
{(field) => (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor={field.name}>Name</Label>
|
||||
<Input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
/>
|
||||
{field.state.meta.errors.map((error) => (
|
||||
<p key={error?.message} className="text-red-500">
|
||||
{error?.message}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</form.Field>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<form.Field name="email">
|
||||
{(field) => (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor={field.name}>Email</Label>
|
||||
<Input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
type="email"
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
/>
|
||||
{field.state.meta.errors.map((error) => (
|
||||
<p key={error?.message} className="text-red-500">
|
||||
{error?.message}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</form.Field>
|
||||
</div>
|
||||
<div>
|
||||
<form.Field name="email">
|
||||
{(field) => (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor={field.name}>Email</Label>
|
||||
<Input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
type="email"
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
/>
|
||||
{field.state.meta.errors.map((error) => (
|
||||
<p key={error?.message} className="text-red-500">
|
||||
{error?.message}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</form.Field>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<form.Field name="password">
|
||||
{(field) => (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor={field.name}>Password</Label>
|
||||
<Input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
type="password"
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
/>
|
||||
{field.state.meta.errors.map((error) => (
|
||||
<p key={error?.message} className="text-red-500">
|
||||
{error?.message}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</form.Field>
|
||||
</div>
|
||||
<div>
|
||||
<form.Field name="password">
|
||||
{(field) => (
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor={field.name}>Password</Label>
|
||||
<Input
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
type="password"
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
/>
|
||||
{field.state.meta.errors.map((error) => (
|
||||
<p key={error?.message} className="text-red-500">
|
||||
{error?.message}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</form.Field>
|
||||
</div>
|
||||
|
||||
<form.Subscribe>
|
||||
{(state) => (
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full"
|
||||
disabled={!state.canSubmit || state.isSubmitting}
|
||||
>
|
||||
{state.isSubmitting ? "Submitting..." : "Sign Up"}
|
||||
</Button>
|
||||
)}
|
||||
</form.Subscribe>
|
||||
</form>
|
||||
<form.Subscribe>
|
||||
{(state) => (
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full"
|
||||
disabled={!state.canSubmit || state.isSubmitting}
|
||||
>
|
||||
{state.isSubmitting ? "Submitting..." : "Sign Up"}
|
||||
</Button>
|
||||
)}
|
||||
</form.Subscribe>
|
||||
</form>
|
||||
|
||||
<div className="mt-4 text-center">
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={onSwitchToSignIn}
|
||||
className="text-indigo-600 hover:text-indigo-800"
|
||||
>
|
||||
Already have an account? Sign In
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
<div className="mt-4 text-center">
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={onSwitchToSignIn}
|
||||
className="text-indigo-600 hover:text-indigo-800"
|
||||
>
|
||||
Already have an account? Sign In
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { serve } from "@hono/node-server";
|
||||
import { trpcServer } from "@hono/trpc-server";
|
||||
import "dotenv/config";
|
||||
import { Hono } from "hono";
|
||||
@@ -13,34 +12,27 @@ const app = new Hono();
|
||||
app.use(logger());
|
||||
|
||||
app.use(
|
||||
"/*",
|
||||
cors({
|
||||
origin: process.env.CORS_ORIGIN || "",
|
||||
allowMethods: ["GET", "POST", "OPTIONS"],
|
||||
allowHeaders: ["Content-Type", "Authorization"],
|
||||
credentials: true,
|
||||
}),
|
||||
"/*",
|
||||
cors({
|
||||
origin: process.env.CORS_ORIGIN || "",
|
||||
allowMethods: ["GET", "POST", "OPTIONS"],
|
||||
allowHeaders: ["Content-Type", "Authorization"],
|
||||
credentials: true,
|
||||
}),
|
||||
);
|
||||
|
||||
app.on(["POST", "GET"], "/api/auth/**", (c) => auth.handler(c.req.raw));
|
||||
|
||||
app.use(
|
||||
"/trpc/*",
|
||||
trpcServer({
|
||||
router: appRouter,
|
||||
createContext: (_opts, hono) => {
|
||||
return createContext({ hono });
|
||||
},
|
||||
}),
|
||||
"/trpc/*",
|
||||
trpcServer({
|
||||
router: appRouter,
|
||||
createContext: (_opts, hono) => {
|
||||
return createContext({ hono });
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
app.get("/", (c) => {
|
||||
return c.text("OK");
|
||||
});
|
||||
|
||||
serve({
|
||||
fetch: app.fetch,
|
||||
port: 3000,
|
||||
}, (info) => {
|
||||
console.log(`Server is running on http://localhost:${info.port}`)
|
||||
return c.text("OK");
|
||||
});
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
|
||||
import { router, publicProcedure, protectedProcedure } from "../lib/trpc";
|
||||
import { protectedProcedure, publicProcedure, router } from "../lib/trpc";
|
||||
import { todoRouter } from "./todo";
|
||||
|
||||
|
||||
export const appRouter = router({
|
||||
healthCheck: publicProcedure.query(() => {
|
||||
return "OK";
|
||||
}),
|
||||
privateData: protectedProcedure.query(({ ctx }) => {
|
||||
return {
|
||||
message: "This is private",
|
||||
user: ctx.session.user,
|
||||
};
|
||||
}),
|
||||
todo: todoRouter,
|
||||
healthCheck: publicProcedure.query(() => {
|
||||
return "OK";
|
||||
}),
|
||||
privateData: protectedProcedure.query(({ ctx }) => {
|
||||
return {
|
||||
message: "This is private",
|
||||
user: ctx.session.user,
|
||||
};
|
||||
}),
|
||||
todo: todoRouter,
|
||||
});
|
||||
|
||||
export type AppRouter = typeof appRouter;
|
||||
|
||||
Reference in New Issue
Block a user