chatbot-ui/app/[locale]/login/page.tsx

245 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Brand } from "@/components/ui/brand"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { SubmitButton } from "@/components/ui/submit-button"
import { createClient } from "@/lib/supabase/server"
import { Database } from "@/supabase/types"
import { createServerClient } from "@supabase/ssr"
import { get } from "@vercel/edge-config"
import { Metadata } from "next"
import { cookies, headers } from "next/headers"
import { redirect } from "next/navigation"
import initTranslations from "@/lib/i18n";
export const metadata: Metadata = {
title: "Login"
}
export default async function Login({
searchParams,
params: { locale },
}: {
searchParams: { message: string };
params: { locale: string };
}) {
const cookieStore = cookies()
// 优先从 cookie 获取 locale否则使用 URL 参数中的 locale
//const localeString = cookieStore.get('locale')?.value || locale;
const localeString = locale;
const { t, resources } = await initTranslations(localeString, ['translation']);
// 打印翻译内容确认是否正常加载
// console.log("...............localeString: ", {localeString});
// console.log("Translation for login.email: ", t("login.email"));
const supabase = createServerClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return cookieStore.get(name)?.value
}
}
}
)
const session = (await supabase.auth.getSession()).data.session
if (session) {
const { data: homeWorkspace, error } = await supabase
.from("workspaces")
.select("*")
.eq("user_id", session.user.id)
.eq("is_home", true)
.single()
if (!homeWorkspace) {
throw new Error(error.message)
}
console.log("1======>Redirecting to workspace:", homeWorkspace.id)
return redirect(`/${localeString}/${homeWorkspace.id}/chat`)
}
const signIn = async (formData: FormData) => {
"use server"
const email = formData.get("email") as string
const password = formData.get("password") as string
const cookieStore = cookies()
const supabase = createClient(cookieStore)
const { data, error } = await supabase.auth.signInWithPassword({
email,
password
})
if (error) {
console.log(`==================> ${localeString}/login?message=${error.message}`);
return redirect(`/${localeString}/login?message=${error.message}`)
}
const { data: homeWorkspace, error: homeWorkspaceError } = await supabase
.from("workspaces")
.select("*")
.eq("user_id", data.user.id)
.eq("is_home", true)
.single()
if (!homeWorkspace) {
throw new Error(
homeWorkspaceError?.message || "An unexpected error occurred"
)
}
console.log("2======>Redirecting to workspace:", homeWorkspace.id)
return redirect(`/${localeString}/${homeWorkspace.id}/chat`)
}
const getEnvVarOrEdgeConfigValue = async (name: string) => {
"use server"
if (process.env.EDGE_CONFIG) {
return await get<string>(name)
}
return process.env[name]
}
const signUp = async (formData: FormData) => {
"use server"
const email = formData.get("email") as string
const password = formData.get("password") as string
const emailDomainWhitelistPatternsString = await getEnvVarOrEdgeConfigValue(
"EMAIL_DOMAIN_WHITELIST"
)
const emailDomainWhitelist = emailDomainWhitelistPatternsString?.trim()
? emailDomainWhitelistPatternsString?.split(",")
: []
const emailWhitelistPatternsString =
await getEnvVarOrEdgeConfigValue("EMAIL_WHITELIST")
const emailWhitelist = emailWhitelistPatternsString?.trim()
? emailWhitelistPatternsString?.split(",")
: []
// If there are whitelist patterns, check if the email is allowed to sign up
if (emailDomainWhitelist.length > 0 || emailWhitelist.length > 0) {
const domainMatch = emailDomainWhitelist?.includes(email.split("@")[1])
const emailMatch = emailWhitelist?.includes(email)
if (!domainMatch && !emailMatch) {
return redirect(
`/${localeString}/login?message=Email ${email} is not allowed to sign up.`
)
}
}
const cookieStore = cookies()
const supabase = createClient(cookieStore)
const { error } = await supabase.auth.signUp({
email,
password,
options: {
// USE IF YOU WANT TO SEND EMAIL VERIFICATION, ALSO CHANGE TOML FILE
// emailRedirectTo: `${origin}/auth/callback`
}
})
if (error) {
console.error(error)
return redirect(`/${localeString}/login?message=${error.message}`)
}
console.log("2..................Redirecting with locale:", localeString)
return redirect(`/${localeString}/setup`)
// USE IF YOU WANT TO SEND EMAIL VERIFICATION, ALSO CHANGE TOML FILE
// return redirect("/login?message=Check email to continue sign in process")
}
const handleResetPassword = async (formData: FormData) => {
"use server"
const origin = headers().get("origin")
const email = formData.get("email") as string
const cookieStore = cookies()
const supabase = createClient(cookieStore)
const { error } = await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${origin}/auth/callback?next=/login/password`
})
if (error) {
return redirect(`/${localeString}/login?message=${error.message}`)
}
return redirect(`/${localeString}/login?message=Check email to reset password`)
}
return (
<div className="flex w-full flex-1 flex-col justify-center gap-2 px-8 sm:max-w-md">
<form
className="animate-in text-foreground flex w-full flex-1 flex-col justify-center gap-2"
action={signIn}
>
<Brand />
<Label className="text-md mt-4" htmlFor="email">
{t("login.email")}
</Label>
<Input
className="mb-3 rounded-md border bg-inherit px-4 py-2"
name="email"
placeholder={t("login.emailPlaceholder")}
required
/>
<Label className="text-md" htmlFor="password">
{t("login.password")}
</Label>
<Input
className="mb-6 rounded-md border bg-inherit px-4 py-2"
type="password"
name="password"
placeholder={t("login.passwordPlaceholder")}
/>
<SubmitButton className="mb-2 rounded-md bg-blue-700 px-4 py-2 text-white">
{t("login.loginButton")}
</SubmitButton>
<SubmitButton
formAction={signUp}
className="border-foreground/20 mb-2 rounded-md border px-4 py-2"
>
{t("login.signUpButton")}
</SubmitButton>
<div className="text-muted-foreground mt-1 flex justify-center text-sm">
<span className="mr-1">{t("login.forgotPassword")}</span>
<button
formAction={handleResetPassword}
className="text-primary ml-1 underline hover:opacity-80"
>
{t("login.reset")}
</button>
</div>
{searchParams?.message && (
<p className="bg-foreground/10 text-foreground mt-4 p-4 text-center">
{searchParams.message}
</p>
)}
</form>
</div>
)
}