264 lines
8.2 KiB
TypeScript
264 lines
8.2 KiB
TypeScript
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()
|
|
|
|
const localeString = locale;
|
|
const { t, resources } = await initTranslations(localeString, ['translation']);
|
|
|
|
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
|
|
|
|
console.log("[login page]Login session:", 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("[login page]======>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(`[login page]==================> ${localeString}/login?message=${error.message}`);
|
|
// return redirect(`/${localeString}/login?message=${error.message}`)
|
|
return redirect(`/${localeString}/login?message=signupNotAllowed&email=${encodeURIComponent(email)}`)
|
|
}
|
|
|
|
const { data: homeWorkspace, error: homeWorkspaceError } = await supabase
|
|
.from("workspaces")
|
|
.select("*")
|
|
.eq("user_id", data.user.id)
|
|
.eq("is_home", true)
|
|
.single()
|
|
|
|
if (!homeWorkspace) {
|
|
//const fallbackMessage = String(t("login.unexpectedError"))
|
|
throw new Error(
|
|
// homeWorkspaceError?.message || "An unexpected error occurred"
|
|
homeWorkspaceError?.message || t("login.unexpectedError")
|
|
)
|
|
}
|
|
|
|
console.log("[login page] SignIn======>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) {
|
|
const errorMessage = String(t("login.signupNotAllowed", { email })) // ← 这是字符串
|
|
console.log(`[login page] SignUp======>Redirecting to workspace:, ${errorMessage}`)
|
|
return redirect(
|
|
// `/${localeString}/login?message=Email ${email} is not allowed to sign up.`
|
|
`/${localeString}/login?message=signupNotAllowed&email=${encodeURIComponent(email)}`
|
|
|
|
)
|
|
}
|
|
}
|
|
|
|
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=${localeString}/login/password`
|
|
})
|
|
|
|
if (error) {
|
|
return redirect(`/${localeString}/login?message=${error.message}`)
|
|
}
|
|
|
|
// const emailtoResetMessage = String(t("login.checkEmailToReset")) // ← 这是字符串
|
|
// return redirect(`/${localeString}/login?message=${emailtoResetMessage}`)
|
|
return redirect(`/${localeString}/login?message=Check email to reset password`)
|
|
}
|
|
|
|
|
|
let translatedMessage: string | null = null;
|
|
|
|
if (searchParams.message === "signupNotAllowed") {
|
|
translatedMessage = t("login.signupNotAllowed", { email: searchParams.email });
|
|
} else if (searchParams.message) {
|
|
translatedMessage = t(`login.${searchParams.message}`);
|
|
}
|
|
|
|
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>
|
|
)} */}
|
|
|
|
{translatedMessage && (
|
|
<p className="bg-foreground/10 text-foreground mt-4 p-4 text-center">
|
|
{translatedMessage}
|
|
</p>
|
|
)}
|
|
|
|
</form>
|
|
</div>
|
|
)
|
|
}
|