Files
cozsweet-frontend-nextjs/src/app/auth/components/auth-email-panel.tsx
T

122 lines
3.6 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.
"use client";
/**
* Email 面板(login/register 内部切换)
*
* 原始 Dart: lib/ui/auth/widgets/auth_email_panel.dart
*
* 视觉规格(与 Dart 对齐):
* - login 模式:顶部 24px spacer + logo120h + 24px gap
* - register 模式:48px spacer(两个 24px,无 logo
* - 表单(EmailLoginForm / EmailRegisterForm
* - 12px gap + 切换链接("Don't have an account? Sign up" / "Already have an account? Log in"
* - 16px gap + "Other Sign In Options" 链接(打开底部弹层)
* - Spacer + AuthLegalText
* - 顶部 "← Back" 按钮由父级 AuthPanel 渲染(悬浮 40×40 圆形)
*/
import Image from "next/image";
import { useState } from "react";
import { useAuthState } from "@/stores/auth/auth-context";
import { AuthErrorMessage } from "./auth-error-message";
import { AuthLegalText } from "./auth-legal-text";
import { AuthOtherOptionsDialog } from "./auth-other-options-dialog";
import { EmailLoginForm } from "./email-login-form";
import { EmailRegisterForm } from "./email-register-form";
import styles from "./auth-email-panel.module.css";
export interface AuthEmailPanelProps {
/** "Other Sign-in Options" 弹层中 Facebook 按钮回调(派发回 facebook 模式) */
onSwitchToFacebook: () => void;
/** "Other Sign-in Options" 弹层中 Google 按钮回调(可空;空时不渲染 Google 行) */
onGoogle?: () => void;
/** 弹层 Google 自定义子节点 */
googleSlot?: React.ReactNode;
}
export function AuthEmailPanel({
onSwitchToFacebook,
onGoogle,
googleSlot,
}: AuthEmailPanelProps) {
const state = useAuthState();
const [mode, setMode] = useState<"login" | "register">("login");
const [showOptions, setShowOptions] = useState(false);
return (
<div className={styles.panel}>
<div className={styles.topSection}>
{mode === "login" ? (
<>
<div className={styles.spacer24} />
<Image
src="/images/auth/ic-logo-login.png"
alt="Cozsweet"
width={120}
height={120}
className={styles.logo}
priority
/>
</>
) : (
<>
<div className={styles.spacer24} />
<div className={styles.spacer24} />
</>
)}
<div className={styles.spacer24} />
</div>
{mode === "login" ? (
<EmailLoginForm
globalError={state.errorMessage}
isLoading={state.isLoading}
/>
) : (
<EmailRegisterForm
globalError={state.errorMessage}
isLoading={state.isLoading}
/>
)}
<AuthErrorMessage message={state.errorMessage} />
<button
type="button"
className={styles.toggleButton}
onClick={() => setMode((m) => (m === "login" ? "register" : "login"))}
>
{mode === "login"
? "Don't have an account? Sign up"
: "Already have an account? Log in"}
</button>
<button
type="button"
className={styles.linkButton}
onClick={() => setShowOptions(true)}
>
Other Sign In Options
</button>
<div className={styles.spacer} />
<AuthLegalText />
<AuthOtherOptionsDialog
open={showOptions}
onClose={() => setShowOptions(false)}
mode="email"
onFacebook={onSwitchToFacebook}
onGoogle={() => {
setShowOptions(false);
onGoogle?.();
}}
onEmail={() => {
// 在 email 模式下不再显示 Email 入口
}}
googleSlot={googleSlot}
/>
</div>
);
}