mirror of
https://github.com/massbug/judge4c.git
synced 2025-05-17 23:12:23 +00:00
refactor(i18n): replace hardcoded texts with i18n message keys for auth
This commit is contained in:
parent
0b3086f333
commit
1d0b74136f
@ -25,6 +25,27 @@
|
|||||||
"open": "Open Bot",
|
"open": "Open Bot",
|
||||||
"close": "Close Bot"
|
"close": "Close Bot"
|
||||||
},
|
},
|
||||||
|
"CredentialsSignInForm": {
|
||||||
|
"email": "Email",
|
||||||
|
"password": "Password",
|
||||||
|
"signIn": "Sign In",
|
||||||
|
"signingIn": "Signing In...",
|
||||||
|
"signInSuccess": "Signed In Successfully",
|
||||||
|
"signInFailed": "Sign In Failed",
|
||||||
|
"showPassword": "Show password",
|
||||||
|
"hidePassword": "Hide password"
|
||||||
|
},
|
||||||
|
"CredentialsSignUpForm": {
|
||||||
|
"email": "Email",
|
||||||
|
"password": "Password",
|
||||||
|
"signUp": "Sign Up",
|
||||||
|
"creatingAccount": "Creating Account...",
|
||||||
|
"signUpSuccess": "Account Created",
|
||||||
|
"signUpSuccessDescription": "You can now sign in with your credentials",
|
||||||
|
"signUpFailed": "Registration Failed",
|
||||||
|
"showPassword": "Show password",
|
||||||
|
"hidePassword": "Hide password"
|
||||||
|
},
|
||||||
"DetailsPage": {
|
"DetailsPage": {
|
||||||
"BackButton": "All Submissions",
|
"BackButton": "All Submissions",
|
||||||
"Time": "Submitted on",
|
"Time": "Submitted on",
|
||||||
@ -38,6 +59,7 @@
|
|||||||
"MEDIUM": "MEDIUM",
|
"MEDIUM": "MEDIUM",
|
||||||
"HARD": "HARD"
|
"HARD": "HARD"
|
||||||
},
|
},
|
||||||
|
"GithubSignInForm": "Continue with GitHub",
|
||||||
"LanguageSettings": {
|
"LanguageSettings": {
|
||||||
"en": {
|
"en": {
|
||||||
"flag": "🇺🇸",
|
"flag": "🇺🇸",
|
||||||
@ -82,6 +104,30 @@
|
|||||||
"Advanced": "Advanced"
|
"Advanced": "Advanced"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"SignInForm": {
|
||||||
|
"title": "Sign in to your account",
|
||||||
|
"description": "Enter your email below to sign in to your account",
|
||||||
|
"or": "Or",
|
||||||
|
"noAccount": "Don't have an account?",
|
||||||
|
"signUp": "Sign up"
|
||||||
|
},
|
||||||
|
"signInWithCredentials": {
|
||||||
|
"userNotFound": "User not found.",
|
||||||
|
"invalidCredentials": "Invalid credentials.",
|
||||||
|
"incorrectPassword": "Incorrect password.",
|
||||||
|
"signInFailedFallback": "Failed to sign in. Please try again."
|
||||||
|
},
|
||||||
|
"signUpWithCredentials": {
|
||||||
|
"userAlreadyExists": "User already exists.",
|
||||||
|
"registrationFailedFallback": "Registration failed. Please try again."
|
||||||
|
},
|
||||||
|
"SignUpForm": {
|
||||||
|
"title": "Sign up to your account",
|
||||||
|
"description": "Enter your email below to sign up to your account",
|
||||||
|
"or": "Or",
|
||||||
|
"haveAccount": "Already have an account?",
|
||||||
|
"signIn": "Sign in"
|
||||||
|
},
|
||||||
"StatusMessage": {
|
"StatusMessage": {
|
||||||
"PD": "Pending",
|
"PD": "Pending",
|
||||||
"QD": "Queued",
|
"QD": "Queued",
|
||||||
|
@ -25,6 +25,27 @@
|
|||||||
"open": "打开AI助手",
|
"open": "打开AI助手",
|
||||||
"close": "关闭AI助手"
|
"close": "关闭AI助手"
|
||||||
},
|
},
|
||||||
|
"CredentialsSignInForm": {
|
||||||
|
"email": "邮箱",
|
||||||
|
"password": "密码",
|
||||||
|
"signIn": "登录",
|
||||||
|
"signingIn": "正在登录...",
|
||||||
|
"signInSuccess": "登录成功",
|
||||||
|
"signInFailed": "登录失败",
|
||||||
|
"showPassword": "显示密码",
|
||||||
|
"hidePassword": "隐藏密码"
|
||||||
|
},
|
||||||
|
"CredentialsSignUpForm": {
|
||||||
|
"email": "邮箱",
|
||||||
|
"password": "密码",
|
||||||
|
"signUp": "注册",
|
||||||
|
"creatingAccount": "正在创建账户...",
|
||||||
|
"signUpSuccess": "账户创建成功",
|
||||||
|
"signUpSuccessDescription": "你现在可以使用凭据登录",
|
||||||
|
"signUpFailed": "注册失败",
|
||||||
|
"showPassword": "显示密码",
|
||||||
|
"hidePassword": "隐藏密码"
|
||||||
|
},
|
||||||
"DetailsPage": {
|
"DetailsPage": {
|
||||||
"BackButton": "所有提交记录",
|
"BackButton": "所有提交记录",
|
||||||
"Time": "提交于",
|
"Time": "提交于",
|
||||||
@ -38,6 +59,7 @@
|
|||||||
"MEDIUM": "中等",
|
"MEDIUM": "中等",
|
||||||
"HARD": "困难"
|
"HARD": "困难"
|
||||||
},
|
},
|
||||||
|
"GithubSignInForm": "使用 GitHub 登录",
|
||||||
"LanguageSettings": {
|
"LanguageSettings": {
|
||||||
"en": {
|
"en": {
|
||||||
"flag": "🇺🇸",
|
"flag": "🇺🇸",
|
||||||
@ -82,6 +104,30 @@
|
|||||||
"Advanced": "高级设置"
|
"Advanced": "高级设置"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"SignInForm": {
|
||||||
|
"title": "登录到你的账户",
|
||||||
|
"description": "请输入你的邮箱以登录账户",
|
||||||
|
"or": "或者",
|
||||||
|
"noAccount": "还没有账户?",
|
||||||
|
"signUp": "注册"
|
||||||
|
},
|
||||||
|
"signInWithCredentials": {
|
||||||
|
"userNotFound": "未找到用户。",
|
||||||
|
"invalidCredentials": "凭据无效。",
|
||||||
|
"incorrectPassword": "密码错误。",
|
||||||
|
"signInFailedFallback": "登录失败,请重试。"
|
||||||
|
},
|
||||||
|
"signUpWithCredentials": {
|
||||||
|
"userAlreadyExists": "用户已存在。",
|
||||||
|
"registrationFailedFallback": "注册失败,请重试。"
|
||||||
|
},
|
||||||
|
"SignUpForm": {
|
||||||
|
"title": "注册你的账户",
|
||||||
|
"description": "请输入你的邮箱以注册账户",
|
||||||
|
"or": "或者",
|
||||||
|
"haveAccount": "已经有账户了?",
|
||||||
|
"signIn": "登录"
|
||||||
|
},
|
||||||
"StatusMessage": {
|
"StatusMessage": {
|
||||||
"PD": "待处理",
|
"PD": "待处理",
|
||||||
"QD": "排队中",
|
"QD": "排队中",
|
||||||
|
@ -4,12 +4,15 @@ import bcrypt from "bcrypt";
|
|||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
import { signIn } from "@/lib/auth";
|
import { signIn } from "@/lib/auth";
|
||||||
import { authSchema } from "@/lib/zod";
|
import { authSchema } from "@/lib/zod";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { CredentialsSignInFormValues } from "@/components/credentials-sign-in-form";
|
import { CredentialsSignInFormValues } from "@/components/credentials-sign-in-form";
|
||||||
import { CredentialsSignUpFormValues } from "@/components/credentials-sign-up-form";
|
import { CredentialsSignUpFormValues } from "@/components/credentials-sign-up-form";
|
||||||
|
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
|
|
||||||
export async function signInWithCredentials(formData: CredentialsSignInFormValues, redirectTo?: string) {
|
export async function signInWithCredentials(formData: CredentialsSignInFormValues, redirectTo?: string) {
|
||||||
|
const t = await getTranslations("signInWithCredentials");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Parse credentials using authSchema for validation
|
// Parse credentials using authSchema for validation
|
||||||
const { email, password } = await authSchema.parseAsync(formData);
|
const { email, password } = await authSchema.parseAsync(formData);
|
||||||
@ -19,35 +22,37 @@ export async function signInWithCredentials(formData: CredentialsSignInFormValue
|
|||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error("User not found.");
|
throw new Error(t("userNotFound"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user has a password
|
// Check if the user has a password
|
||||||
if (!user.password) {
|
if (!user.password) {
|
||||||
throw new Error("Invalid credentials.");
|
throw new Error(t("invalidCredentials"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the password matches
|
// Check if the password matches
|
||||||
const passwordMatch = await bcrypt.compare(password, user.password);
|
const passwordMatch = await bcrypt.compare(password, user.password);
|
||||||
if (!passwordMatch) {
|
if (!passwordMatch) {
|
||||||
throw new Error("Incorrect password.");
|
throw new Error(t("incorrectPassword"));
|
||||||
}
|
}
|
||||||
|
|
||||||
await signIn("credentials", { ...formData, redirectTo, redirect: !!redirectTo });
|
await signIn("credentials", { ...formData, redirectTo, redirect: !!redirectTo });
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error instanceof Error ? error.message : "Failed to sign in. Please try again." };
|
return { error: error instanceof Error ? error.message : t("signInFailedFallback") };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function signUpWithCredentials(formData: CredentialsSignUpFormValues) {
|
export async function signUpWithCredentials(formData: CredentialsSignUpFormValues) {
|
||||||
|
const t = await getTranslations("signUpWithCredentials");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const validatedData = await authSchema.parseAsync(formData);
|
const validatedData = await authSchema.parseAsync(formData);
|
||||||
|
|
||||||
// Check if user already exists
|
// Check if user already exists
|
||||||
const existingUser = await prisma.user.findUnique({ where: { email: validatedData.email } });
|
const existingUser = await prisma.user.findUnique({ where: { email: validatedData.email } });
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
throw new Error("User already exists");
|
throw new Error(t("userAlreadyExists"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash password and create user
|
// Hash password and create user
|
||||||
@ -64,7 +69,7 @@ export async function signUpWithCredentials(formData: CredentialsSignUpFormValue
|
|||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error instanceof Error ? error.message : "Registration failed. Please try again." };
|
return { error: error instanceof Error ? error.message : t("registrationFailedFallback") };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { LogOut } from "lucide-react";
|
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@ -8,6 +7,7 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { LogOutIcon } from "lucide-react";
|
||||||
import { auth, signOut } from "@/lib/auth";
|
import { auth, signOut } from "@/lib/auth";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
@ -65,7 +65,7 @@ export async function AvatarButton() {
|
|||||||
<DropdownMenuGroup>
|
<DropdownMenuGroup>
|
||||||
<SettingsButton />
|
<SettingsButton />
|
||||||
<DropdownMenuItem onClick={handleLogOut}>
|
<DropdownMenuItem onClick={handleLogOut}>
|
||||||
<LogOut />
|
<LogOutIcon />
|
||||||
{t("LogOut")}
|
{t("LogOut")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuGroup>
|
</DropdownMenuGroup>
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { authSchema } from "@/lib/zod";
|
import { authSchema } from "@/lib/zod";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { useState, useTransition } from "react";
|
import { useState, useTransition } from "react";
|
||||||
@ -26,6 +27,7 @@ export function CredentialsSignInForm() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const redirectTo = searchParams.get("redirectTo");
|
const redirectTo = searchParams.get("redirectTo");
|
||||||
|
const t = useTranslations("CredentialsSignInForm");
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
|
||||||
@ -44,11 +46,11 @@ export function CredentialsSignInForm() {
|
|||||||
const result = await signInWithCredentials(data);
|
const result = await signInWithCredentials(data);
|
||||||
|
|
||||||
if (result?.error) {
|
if (result?.error) {
|
||||||
toast.error("Sign In Failed", {
|
toast.error(t("signInFailed"), {
|
||||||
description: result.error,
|
description: result.error,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast.success("Signed In Successfully");
|
toast.success(t("signInSuccess"));
|
||||||
router.push(redirectTo || "/");
|
router.push(redirectTo || "/");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -62,7 +64,7 @@ export function CredentialsSignInForm() {
|
|||||||
name="email"
|
name="email"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Email</FormLabel>
|
<FormLabel>{t("email")}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Input className="peer pe-9" {...field} />
|
<Input className="peer pe-9" {...field} />
|
||||||
@ -81,7 +83,7 @@ export function CredentialsSignInForm() {
|
|||||||
name="password"
|
name="password"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Password</FormLabel>
|
<FormLabel>{t("password")}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Input
|
<Input
|
||||||
@ -93,7 +95,7 @@ export function CredentialsSignInForm() {
|
|||||||
className="text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md transition-[color,box-shadow] outline-none focus:z-10 focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
|
className="text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md transition-[color,box-shadow] outline-none focus:z-10 focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={toggleVisibility}
|
onClick={toggleVisibility}
|
||||||
aria-label={isVisible ? "Hide password" : "Show password"}
|
aria-label={isVisible ? t("hidePassword") : t("showPassword")}
|
||||||
aria-pressed={isVisible}
|
aria-pressed={isVisible}
|
||||||
aria-controls="password"
|
aria-controls="password"
|
||||||
>
|
>
|
||||||
@ -111,7 +113,7 @@ export function CredentialsSignInForm() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Button type="submit" disabled={isPending} className="w-full">
|
<Button type="submit" disabled={isPending} className="w-full">
|
||||||
{isPending ? "Signing In..." : "Sign In"}
|
{isPending ? t("signingIn") : t("signIn")}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { authSchema } from "@/lib/zod";
|
import { authSchema } from "@/lib/zod";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { useState, useTransition } from "react";
|
import { useState, useTransition } from "react";
|
||||||
@ -26,6 +27,7 @@ export function CredentialsSignUpForm() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const redirectTo = searchParams.get("redirectTo");
|
const redirectTo = searchParams.get("redirectTo");
|
||||||
|
const t = useTranslations("CredentialsSignUpForm");
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
|
||||||
@ -44,12 +46,12 @@ export function CredentialsSignUpForm() {
|
|||||||
const result = await signUpWithCredentials(data);
|
const result = await signUpWithCredentials(data);
|
||||||
|
|
||||||
if (result?.error) {
|
if (result?.error) {
|
||||||
toast.error("Registration Failed", {
|
toast.error(t("signUpFailed"), {
|
||||||
description: result.error,
|
description: result.error,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast.success("Account Created", {
|
toast.success(t("signUpSuccess"), {
|
||||||
description: "You can now sign in with your credentials",
|
description: t("signUpSuccessDescription"),
|
||||||
});
|
});
|
||||||
router.push(`/sign-in?${redirectTo}`)
|
router.push(`/sign-in?${redirectTo}`)
|
||||||
}
|
}
|
||||||
@ -64,7 +66,7 @@ export function CredentialsSignUpForm() {
|
|||||||
name="email"
|
name="email"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Email</FormLabel>
|
<FormLabel>{t("email")}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Input className="peer pe-9" {...field} />
|
<Input className="peer pe-9" {...field} />
|
||||||
@ -83,7 +85,7 @@ export function CredentialsSignUpForm() {
|
|||||||
name="password"
|
name="password"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Password</FormLabel>
|
<FormLabel>{t("password")}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Input
|
<Input
|
||||||
@ -95,7 +97,7 @@ export function CredentialsSignUpForm() {
|
|||||||
className="text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md transition-[color,box-shadow] outline-none focus:z-10 focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
|
className="text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md transition-[color,box-shadow] outline-none focus:z-10 focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={toggleVisibility}
|
onClick={toggleVisibility}
|
||||||
aria-label={isVisible ? "Hide password" : "Show password"}
|
aria-label={isVisible ? t("hidePassword") : t("showPassword")}
|
||||||
aria-pressed={isVisible}
|
aria-pressed={isVisible}
|
||||||
aria-controls="password"
|
aria-controls="password"
|
||||||
>
|
>
|
||||||
@ -113,7 +115,7 @@ export function CredentialsSignUpForm() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Button type="submit" disabled={isPending} className="w-full">
|
<Button type="submit" disabled={isPending} className="w-full">
|
||||||
{isPending ? "Creating Account..." : "Sign Up"}
|
{isPending ? t("creatingAccount") : t("signUp")}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { signInWithGithub } from "@/actions/auth";
|
import { signInWithGithub } from "@/actions/auth";
|
||||||
import { useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
export function GithubSignInForm() {
|
export function GithubSignInForm() {
|
||||||
|
const t = useTranslations();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const redirectTo = searchParams.get("redirectTo");
|
const redirectTo = searchParams.get("redirectTo");
|
||||||
const signInAction = signInWithGithub.bind(null, redirectTo || "/");
|
const signInAction = signInWithGithub.bind(null, redirectTo || "/");
|
||||||
@ -18,7 +20,7 @@ export function GithubSignInForm() {
|
|||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Continue with GitHub
|
{t("GithubSignInForm")}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Settings } from "lucide-react";
|
import { SettingsIcon } from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useSettingsStore } from "@/stores/useSettingsStore";
|
import { useSettingsStore } from "@/stores/useSettingsStore";
|
||||||
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
|
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
|
||||||
@ -11,7 +11,7 @@ export function SettingsButton() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenuItem onClick={() => setDialogOpen(true)}>
|
<DropdownMenuItem onClick={() => setDialogOpen(true)}>
|
||||||
<Settings />
|
<SettingsIcon />
|
||||||
{t("Settings")}
|
{t("Settings")}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { GithubSignInForm } from "@/components/github-sign-in-form";
|
import { GithubSignInForm } from "@/components/github-sign-in-form";
|
||||||
import { CredentialsSignInForm } from "@/components/credentials-sign-in-form";
|
import { CredentialsSignInForm } from "@/components/credentials-sign-in-form";
|
||||||
@ -7,6 +8,7 @@ import { CredentialsSignInForm } from "@/components/credentials-sign-in-form";
|
|||||||
export function SignInForm() {
|
export function SignInForm() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
const t = useTranslations("SignInForm");
|
||||||
|
|
||||||
const handleSignUp = () => {
|
const handleSignUp = () => {
|
||||||
const params = new URLSearchParams(searchParams.toString());
|
const params = new URLSearchParams(searchParams.toString());
|
||||||
@ -16,25 +18,25 @@ export function SignInForm() {
|
|||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
<div className="flex flex-col items-center gap-2 text-center">
|
<div className="flex flex-col items-center gap-2 text-center">
|
||||||
<h1 className="text-2xl font-bold">Sign in to your account</h1>
|
<h1 className="text-2xl font-bold">{t("title")}</h1>
|
||||||
<p className="text-balance text-sm text-muted-foreground">
|
<p className="text-balance text-sm text-muted-foreground">
|
||||||
Enter your email below to sign in to your account
|
{t("description")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<CredentialsSignInForm />
|
<CredentialsSignInForm />
|
||||||
<div className="relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t after:border-border">
|
<div className="relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t after:border-border">
|
||||||
<span className="relative z-10 bg-background px-2 text-muted-foreground">
|
<span className="relative z-10 bg-background px-2 text-muted-foreground">
|
||||||
Or
|
{t("or")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<GithubSignInForm />
|
<GithubSignInForm />
|
||||||
<div className="text-center text-sm">
|
<div className="text-center text-sm">
|
||||||
Don't have an account?{" "}
|
{t("noAccount")}{" "}
|
||||||
<button
|
<button
|
||||||
onClick={handleSignUp}
|
onClick={handleSignUp}
|
||||||
className="underline underline-offset-4"
|
className="underline underline-offset-4"
|
||||||
>
|
>
|
||||||
Sign up
|
{t("signUp")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { GithubSignInForm } from "@/components/github-sign-in-form";
|
import { GithubSignInForm } from "@/components/github-sign-in-form";
|
||||||
import { CredentialsSignUpForm } from "@/components/credentials-sign-up-form";
|
import { CredentialsSignUpForm } from "@/components/credentials-sign-up-form";
|
||||||
@ -7,6 +8,7 @@ import { CredentialsSignUpForm } from "@/components/credentials-sign-up-form";
|
|||||||
export function SignUpForm() {
|
export function SignUpForm() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
const t = useTranslations("SignUpForm");
|
||||||
|
|
||||||
const handleSignIn = () => {
|
const handleSignIn = () => {
|
||||||
const params = new URLSearchParams(searchParams.toString());
|
const params = new URLSearchParams(searchParams.toString());
|
||||||
@ -16,25 +18,25 @@ export function SignUpForm() {
|
|||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
<div className="flex flex-col items-center gap-2 text-center">
|
<div className="flex flex-col items-center gap-2 text-center">
|
||||||
<h1 className="text-2xl font-bold">Sign up to your account</h1>
|
<h1 className="text-2xl font-bold">{t("title")}</h1>
|
||||||
<p className="text-balance text-sm text-muted-foreground">
|
<p className="text-balance text-sm text-muted-foreground">
|
||||||
Enter your email below to sign up to your account
|
{t("description")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<CredentialsSignUpForm />
|
<CredentialsSignUpForm />
|
||||||
<div className="relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t after:border-border">
|
<div className="relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t after:border-border">
|
||||||
<span className="relative z-10 bg-background px-2 text-muted-foreground">
|
<span className="relative z-10 bg-background px-2 text-muted-foreground">
|
||||||
Or
|
{t("or")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<GithubSignInForm />
|
<GithubSignInForm />
|
||||||
<div className="text-center text-sm">
|
<div className="text-center text-sm">
|
||||||
Already have an account?{" "}
|
{t("haveAccount")}{" "}
|
||||||
<button
|
<button
|
||||||
onClick={handleSignIn}
|
onClick={handleSignIn}
|
||||||
className="underline underline-offset-4"
|
className="underline underline-offset-4"
|
||||||
>
|
>
|
||||||
Sign in
|
{t("signIn")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user