"use client" import Image from "next/image" import Link from "next/link" import { useRouter, useSearchParams } from "next/navigation" import { startTransition, useEffect, useState } from "react" import { toast } from "sonner" import { useAuth } from "@/components/auth-provider" import { fetchAuthOptions, loginWithPassword, type AuthOptions } from "@/lib/api/auth" import { useI18n } from "@/i18n/provider" import { cn } from "@/lib/utils" import { Button } from "@/components/ui/button" import { Card, CardContent } from "@/components/ui/card" import { Field, FieldDescription, FieldGroup, FieldLabel, FieldSeparator, } from "@/components/ui/field" import { Input } from "@/components/ui/input" import { KeyRoundIcon } from "lucide-react" function detectWxWorkEnvironment() { if (typeof navigator === "undefined") { return false } const userAgent = navigator.userAgent.toLowerCase() return userAgent.includes("wxwork") } export function LoginForm({ className, ...props }: React.ComponentProps<"div">) { const t = useI18n() const router = useRouter() const searchParams = useSearchParams() const { session } = useAuth() const [isPending, setIsPending] = useState(false) const [isWxWorkEnv, setIsWxWorkEnv] = useState(false) const [authOptions, setAuthOptions] = useState({ wxworkEnabled: false, oidcEnabled: false, }) const nextPath = searchParams.get("next") const wxworkError = searchParams.get("wxworkError") const oidcError = searchParams.get("oidcError") const redirectPath = nextPath && nextPath.startsWith("/") ? nextPath : "/dashboard" const enabledProviderCount = Number(authOptions.wxworkEnabled) + Number(authOptions.oidcEnabled) useEffect(() => { if (session) { router.replace(redirectPath) } }, [redirectPath, router, session]) useEffect(() => { if (wxworkError) { toast.error(wxworkError) } }, [wxworkError]) useEffect(() => { if (oidcError) { toast.error(oidcError) } }, [oidcError]) useEffect(() => { setIsWxWorkEnv(detectWxWorkEnvironment()) }, []) useEffect(() => { let cancelled = false void fetchAuthOptions() .then((options) => { if (!cancelled) { setAuthOptions(options) } }) .catch(() => { if (!cancelled) { setAuthOptions({ wxworkEnabled: false, oidcEnabled: false }) } }) return () => { cancelled = true } }, []) async function handleSubmit(event: React.FormEvent) { event.preventDefault() const formData = new FormData(event.currentTarget) const username = formData.get("username")?.toString().trim() ?? "" const password = formData.get("password")?.toString() ?? "" setIsPending(true) try { await loginWithPassword({ username, password }) toast.success(t("auth.loginSuccess")) startTransition(() => { router.push(redirectPath) }) } catch (error) { toast.error(error instanceof Error ? error.message : t("auth.loginFailed")) } finally { setIsPending(false) } } return (

{t("auth.welcome")}

{t("auth.loginDescription", { brand: t("app.brand") })}

{t("auth.username")}
{t("auth.password")} {t("auth.forgotPassword")}
{enabledProviderCount > 0 ? ( <> {t("auth.continueWith")} {authOptions.wxworkEnabled ? ( ) : null} {authOptions.oidcEnabled ? ( ) : null} ) : null} {/* {t("auth.noAccount")} {t("auth.signUp")} */}
{/* shadcn login-04 uses a plain img for the decorative side panel. */} {/* eslint-disable-next-line @next/next/no-img-element */} {t("auth.imageAlt")}
{t("auth.termsPrefix")}{" "} {t("auth.termsOfService")} {" "} {t("auth.termsJoiner")}{" "} {t("auth.privacyPolicy")} .
) }