mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-25 01:15:26 +10:00
fixes #2552, implement FLAG_DISABLE_SIGNUPS and FLAG_DISABLE_EMAIL_AUTH
This commit is contained in:
+10
-3
@@ -16,7 +16,8 @@ import { ConfirmDialogProvider } from "@/hooks/use-confirm";
|
||||
import { PromptDialogProvider } from "@/hooks/use-prompt";
|
||||
import { getSession } from "@/integrations/auth/functions";
|
||||
import type { AuthSession } from "@/integrations/auth/types";
|
||||
import type { orpc } from "@/integrations/orpc/client";
|
||||
import { client, type orpc } from "@/integrations/orpc/client";
|
||||
import type { FeatureFlags } from "@/integrations/orpc/services/flags";
|
||||
import { getLocale, isRTL, type Locale, loadLocale } from "@/utils/locale";
|
||||
import { getTheme, type Theme } from "@/utils/theme";
|
||||
import appCss from "../styles/globals.css?url";
|
||||
@@ -27,6 +28,7 @@ type RouterContext = {
|
||||
orpc: typeof orpc;
|
||||
queryClient: QueryClient;
|
||||
session: AuthSession | null;
|
||||
flags: FeatureFlags;
|
||||
};
|
||||
|
||||
const appName = "Reactive Resume";
|
||||
@@ -70,9 +72,14 @@ export const Route = createRootRouteWithContext<RouterContext>()({
|
||||
};
|
||||
},
|
||||
beforeLoad: async () => {
|
||||
const [theme, locale, session] = await Promise.all([getTheme(), getLocale(), getSession()]);
|
||||
const [theme, locale, session, flags] = await Promise.all([
|
||||
getTheme(),
|
||||
getLocale(),
|
||||
getSession(),
|
||||
client.flags.get(),
|
||||
]);
|
||||
|
||||
return { theme, locale, session };
|
||||
return { theme, locale, session, flags };
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { ArrowRightIcon } from "@phosphor-icons/react";
|
||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
||||
import { createFileRoute, Link, redirect } from "@tanstack/react-router";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
@@ -14,6 +14,9 @@ import { authClient } from "@/integrations/auth/client";
|
||||
|
||||
export const Route = createFileRoute("/auth/forgot-password")({
|
||||
component: RouteComponent,
|
||||
beforeLoad: async ({ context }) => {
|
||||
if (context.flags.disableEmailAuth) throw redirect({ to: "/auth/login", replace: true });
|
||||
},
|
||||
});
|
||||
|
||||
const formSchema = z.object({
|
||||
|
||||
+71
-66
@@ -33,6 +33,7 @@ function RouteComponent() {
|
||||
const router = useRouter();
|
||||
const navigate = useNavigate();
|
||||
const [showPassword, toggleShowPassword] = useToggle(false);
|
||||
const { flags } = Route.useRouteContext();
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
@@ -86,80 +87,84 @@ function RouteComponent() {
|
||||
<Trans>Sign in to your account</Trans>
|
||||
</h1>
|
||||
|
||||
<div className="text-muted-foreground">
|
||||
<Trans>
|
||||
Don't have an account?{" "}
|
||||
<Button asChild variant="link" className="h-auto gap-1.5 px-1! py-0">
|
||||
<Link to="/auth/register">
|
||||
Create one now <ArrowRightIcon />
|
||||
</Link>
|
||||
</Button>
|
||||
</Trans>
|
||||
</div>
|
||||
{!flags.disableSignups && (
|
||||
<div className="text-muted-foreground">
|
||||
<Trans>
|
||||
Don't have an account?{" "}
|
||||
<Button asChild variant="link" className="h-auto gap-1.5 px-1! py-0">
|
||||
<Link to="/auth/register">
|
||||
Create one now <ArrowRightIcon />
|
||||
</Link>
|
||||
</Button>
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Form {...form}>
|
||||
<form className="space-y-6" onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="identifier"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Email Address</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input autoComplete="email" placeholder="john.doe@example.com" className="lowercase" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
<Trans>You can also use your username to login.</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<div className="flex items-center justify-between">
|
||||
{!flags.disableEmailAuth && (
|
||||
<Form {...form}>
|
||||
<form className="space-y-6" onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="identifier"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Password</Trans>
|
||||
<Trans>Email Address</Trans>
|
||||
</FormLabel>
|
||||
|
||||
<Button asChild tabIndex={-1} variant="link" className="h-auto p-0 text-xs leading-none">
|
||||
<Link to="/auth/forgot-password">
|
||||
<Trans>Forgot Password?</Trans>
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<FormControl>
|
||||
<Input
|
||||
min={6}
|
||||
max={64}
|
||||
type={showPassword ? "text" : "password"}
|
||||
autoComplete="current-password"
|
||||
{...field}
|
||||
/>
|
||||
<Input autoComplete="email" placeholder="john.doe@example.com" className="lowercase" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
<Trans>You can also use your username to login.</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button size="icon" variant="ghost" onClick={toggleShowPassword}>
|
||||
{showPassword ? <EyeIcon /> : <EyeSlashIcon />}
|
||||
</Button>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<div className="flex items-center justify-between">
|
||||
<FormLabel>
|
||||
<Trans>Password</Trans>
|
||||
</FormLabel>
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
<Trans>Sign in</Trans>
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
<Button asChild tabIndex={-1} variant="link" className="h-auto p-0 text-xs leading-none">
|
||||
<Link to="/auth/forgot-password">
|
||||
<Trans>Forgot Password?</Trans>
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<FormControl>
|
||||
<Input
|
||||
min={6}
|
||||
max={64}
|
||||
type={showPassword ? "text" : "password"}
|
||||
autoComplete="current-password"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<Button size="icon" variant="ghost" onClick={toggleShowPassword}>
|
||||
{showPassword ? <EyeIcon /> : <EyeSlashIcon />}
|
||||
</Button>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
<Trans>Sign in</Trans>
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
)}
|
||||
|
||||
<SocialAuth />
|
||||
</>
|
||||
|
||||
@@ -19,6 +19,7 @@ export const Route = createFileRoute("/auth/register")({
|
||||
component: RouteComponent,
|
||||
beforeLoad: async ({ context }) => {
|
||||
if (context.session) throw redirect({ to: "/dashboard", replace: true });
|
||||
if (context.flags.disableSignups) throw redirect({ to: "/auth/login", replace: true });
|
||||
return { session: null };
|
||||
},
|
||||
});
|
||||
@@ -43,6 +44,7 @@ type FormValues = z.infer<typeof formSchema>;
|
||||
function RouteComponent() {
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
const [showPassword, toggleShowPassword] = useToggle(false);
|
||||
const { flags } = Route.useRouteContext();
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
@@ -96,102 +98,104 @@ function RouteComponent() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Form {...form}>
|
||||
<form className="space-y-6" onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Name</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input min={3} max={64} autoComplete="name" placeholder="John Doe" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{!flags.disableEmailAuth && (
|
||||
<Form {...form}>
|
||||
<form className="space-y-6" onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Name</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input min={3} max={64} autoComplete="name" placeholder="John Doe" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Username</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
min={3}
|
||||
max={64}
|
||||
autoComplete="username"
|
||||
placeholder="john.doe"
|
||||
className="lowercase"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Email Address</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
placeholder="john.doe@example.com"
|
||||
className="lowercase"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Password</Trans>
|
||||
</FormLabel>
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Username</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
min={6}
|
||||
min={3}
|
||||
max={64}
|
||||
type={showPassword ? "text" : "password"}
|
||||
autoComplete="new-password"
|
||||
autoComplete="username"
|
||||
placeholder="john.doe"
|
||||
className="lowercase"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button size="icon" variant="ghost" onClick={toggleShowPassword}>
|
||||
{showPassword ? <EyeIcon /> : <EyeSlashIcon />}
|
||||
</Button>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Email Address</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
placeholder="john.doe@example.com"
|
||||
className="lowercase"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
<Trans>Sign up</Trans>
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<Trans>Password</Trans>
|
||||
</FormLabel>
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<FormControl>
|
||||
<Input
|
||||
min={6}
|
||||
max={64}
|
||||
type={showPassword ? "text" : "password"}
|
||||
autoComplete="new-password"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<Button size="icon" variant="ghost" onClick={toggleShowPassword}>
|
||||
{showPassword ? <EyeIcon /> : <EyeSlashIcon />}
|
||||
</Button>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
<Trans>Sign up</Trans>
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
)}
|
||||
|
||||
<SocialAuth />
|
||||
</>
|
||||
|
||||
@@ -18,6 +18,9 @@ const searchSchema = z.object({ token: z.string().min(1) });
|
||||
export const Route = createFileRoute("/auth/reset-password")({
|
||||
component: RouteComponent,
|
||||
validateSearch: zodValidator(searchSchema),
|
||||
beforeLoad: async ({ context }) => {
|
||||
if (context.flags.disableEmailAuth) throw redirect({ to: "/auth/login", replace: true });
|
||||
},
|
||||
onError: (error) => {
|
||||
if (error instanceof SearchParamError) {
|
||||
throw redirect({ to: "/auth/login" });
|
||||
|
||||
Reference in New Issue
Block a user