[WEB-4197] chore: auth forms semantics and accessibility #7128

This commit is contained in:
Aaryan Khandelwal 2025-05-30 18:22:20 +05:30 committed by GitHub
parent 01b685ea57
commit cb92108bf4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 252 additions and 75 deletions

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Sbalit postranní panel", "collapse_sidebar": "Sbalit postranní panel",
"expand_sidebar": "Rozbalit postranní panel", "expand_sidebar": "Rozbalit postranní panel",
"edition_badge": "Otevřít modal placených plánů" "edition_badge": "Otevřít modal placených plánů"
},
"auth_forms": {
"clear_email": "Vymazat e-mail",
"show_password": "Zobrazit heslo",
"hide_password": "Skrýt heslo",
"close_alert": "Zavřít upozornění",
"close_popover": "Zavřít vyskakovací okno"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Seitenleiste einklappen", "collapse_sidebar": "Seitenleiste einklappen",
"expand_sidebar": "Seitenleiste ausklappen", "expand_sidebar": "Seitenleiste ausklappen",
"edition_badge": "Modal für kostenpflichtige Pläne öffnen" "edition_badge": "Modal für kostenpflichtige Pläne öffnen"
},
"auth_forms": {
"clear_email": "E-Mail löschen",
"show_password": "Passwort anzeigen",
"hide_password": "Passwort verbergen",
"close_alert": "Warnung schließen",
"close_popover": "Popover schließen"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Collapse sidebar", "collapse_sidebar": "Collapse sidebar",
"expand_sidebar": "Expand sidebar", "expand_sidebar": "Expand sidebar",
"edition_badge": "Open paid plans' modal" "edition_badge": "Open paid plans' modal"
},
"auth_forms": {
"clear_email": "Clear email",
"show_password": "Show password",
"hide_password": "Hide password",
"close_alert": "Close alert",
"close_popover": "Close popover"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Colapsar barra lateral", "collapse_sidebar": "Colapsar barra lateral",
"expand_sidebar": "Expandir barra lateral", "expand_sidebar": "Expandir barra lateral",
"edition_badge": "Abrir modal de planes de pago" "edition_badge": "Abrir modal de planes de pago"
},
"auth_forms": {
"clear_email": "Limpiar correo electrónico",
"show_password": "Mostrar contraseña",
"hide_password": "Ocultar contraseña",
"close_alert": "Cerrar alerta",
"close_popover": "Cerrar ventana emergente"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Réduire la barre latérale", "collapse_sidebar": "Réduire la barre latérale",
"expand_sidebar": "Étendre la barre latérale", "expand_sidebar": "Étendre la barre latérale",
"edition_badge": "Ouvrir le modal des plans payants" "edition_badge": "Ouvrir le modal des plans payants"
},
"auth_forms": {
"clear_email": "Effacer l'e-mail",
"show_password": "Afficher le mot de passe",
"hide_password": "Masquer le mot de passe",
"close_alert": "Fermer l'alerte",
"close_popover": "Fermer la fenêtre contextuelle"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Tutup sidebar", "collapse_sidebar": "Tutup sidebar",
"expand_sidebar": "Perluas sidebar", "expand_sidebar": "Perluas sidebar",
"edition_badge": "Buka modal paket berbayar" "edition_badge": "Buka modal paket berbayar"
},
"auth_forms": {
"clear_email": "Hapus email",
"show_password": "Tampilkan kata sandi",
"hide_password": "Sembunyikan kata sandi",
"close_alert": "Tutup peringatan",
"close_popover": "Tutup popover"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Comprimi barra laterale", "collapse_sidebar": "Comprimi barra laterale",
"expand_sidebar": "Espandi barra laterale", "expand_sidebar": "Espandi barra laterale",
"edition_badge": "Apri modal piani a pagamento" "edition_badge": "Apri modal piani a pagamento"
},
"auth_forms": {
"clear_email": "Cancella email",
"show_password": "Mostra password",
"hide_password": "Nascondi password",
"close_alert": "Chiudi avviso",
"close_popover": "Chiudi popover"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "サイドバーを折りたたむ", "collapse_sidebar": "サイドバーを折りたたむ",
"expand_sidebar": "サイドバーを展開", "expand_sidebar": "サイドバーを展開",
"edition_badge": "有料プランのモーダルを開く" "edition_badge": "有料プランのモーダルを開く"
},
"auth_forms": {
"clear_email": "メールをクリア",
"show_password": "パスワードを表示",
"hide_password": "パスワードを非表示",
"close_alert": "アラートを閉じる",
"close_popover": "ポップオーバーを閉じる"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "사이드바 축소", "collapse_sidebar": "사이드바 축소",
"expand_sidebar": "사이드바 확장", "expand_sidebar": "사이드바 확장",
"edition_badge": "유료 플랜 모달 열기" "edition_badge": "유료 플랜 모달 열기"
},
"auth_forms": {
"clear_email": "이메일 지우기",
"show_password": "비밀번호 표시",
"hide_password": "비밀번호 숨기기",
"close_alert": "알림 닫기",
"close_popover": "팝오버 닫기"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Zwiń pasek boczny", "collapse_sidebar": "Zwiń pasek boczny",
"expand_sidebar": "Rozwiń pasek boczny", "expand_sidebar": "Rozwiń pasek boczny",
"edition_badge": "Otwórz modal płatnych planów" "edition_badge": "Otwórz modal płatnych planów"
},
"auth_forms": {
"clear_email": "Wyczyść e-mail",
"show_password": "Pokaż hasło",
"hide_password": "Ukryj hasło",
"close_alert": "Zamknij alert",
"close_popover": "Zamknij popover"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Recolher barra lateral", "collapse_sidebar": "Recolher barra lateral",
"expand_sidebar": "Expandir barra lateral", "expand_sidebar": "Expandir barra lateral",
"edition_badge": "Abrir modal de planos pagos" "edition_badge": "Abrir modal de planos pagos"
},
"auth_forms": {
"clear_email": "Limpar e-mail",
"show_password": "Mostrar senha",
"hide_password": "Ocultar senha",
"close_alert": "Fechar alerta",
"close_popover": "Fechar popover"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Restrânge bara laterală", "collapse_sidebar": "Restrânge bara laterală",
"expand_sidebar": "Extinde bara laterală", "expand_sidebar": "Extinde bara laterală",
"edition_badge": "Deschide modalul planurilor plătite" "edition_badge": "Deschide modalul planurilor plătite"
},
"auth_forms": {
"clear_email": "Șterge e-mailul",
"show_password": "Afișează parola",
"hide_password": "Ascunde parola",
"close_alert": "Închide alerta",
"close_popover": "Închide popover-ul"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Свернуть боковую панель", "collapse_sidebar": "Свернуть боковую панель",
"expand_sidebar": "Развернуть боковую панель", "expand_sidebar": "Развернуть боковую панель",
"edition_badge": "Открыть модал платных планов" "edition_badge": "Открыть модал платных планов"
},
"auth_forms": {
"clear_email": "Очистить email",
"show_password": "Показать пароль",
"hide_password": "Скрыть пароль",
"close_alert": "Закрыть уведомление",
"close_popover": "Закрыть всплывающее окно"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Zbaliť bočný panel", "collapse_sidebar": "Zbaliť bočný panel",
"expand_sidebar": "Rozbaliť bočný panel", "expand_sidebar": "Rozbaliť bočný panel",
"edition_badge": "Otvoriť modal platených plánov" "edition_badge": "Otvoriť modal platených plánov"
},
"auth_forms": {
"clear_email": "Vymazať e-mail",
"show_password": "Zobraziť heslo",
"hide_password": "Skryť heslo",
"close_alert": "Zavrieť upozornenie",
"close_popover": "Zavrieť vyskakovacie okno"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Kenar çubuğunu daralt", "collapse_sidebar": "Kenar çubuğunu daralt",
"expand_sidebar": "Kenar çubuğunu genişlet", "expand_sidebar": "Kenar çubuğunu genişlet",
"edition_badge": "Ücretli planlar modalını aç" "edition_badge": "Ücretli planlar modalını aç"
},
"auth_forms": {
"clear_email": "E-postayı temizle",
"show_password": "Şifreyi göster",
"hide_password": "Şifreyi gizle",
"close_alert": "Uyarıyı kapat",
"close_popover": "Açılır pencereyi kapat"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Згорнути бічну панель", "collapse_sidebar": "Згорнути бічну панель",
"expand_sidebar": "Розгорнути бічну панель", "expand_sidebar": "Розгорнути бічну панель",
"edition_badge": "Відкрити модал платних планів" "edition_badge": "Відкрити модал платних планів"
},
"auth_forms": {
"clear_email": "Очистити email",
"show_password": "Показати пароль",
"hide_password": "Приховати пароль",
"close_alert": "Закрити сповіщення",
"close_popover": "Закрити спливаюче вікно"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "Thu gọn thanh bên", "collapse_sidebar": "Thu gọn thanh bên",
"expand_sidebar": "Mở rộng thanh bên", "expand_sidebar": "Mở rộng thanh bên",
"edition_badge": "Mở modal gói trả phí" "edition_badge": "Mở modal gói trả phí"
},
"auth_forms": {
"clear_email": "Xóa email",
"show_password": "Hiển thị mật khẩu",
"hide_password": "Ẩn mật khẩu",
"close_alert": "Đóng cảnh báo",
"close_popover": "Đóng popover"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "折叠侧边栏", "collapse_sidebar": "折叠侧边栏",
"expand_sidebar": "展开侧边栏", "expand_sidebar": "展开侧边栏",
"edition_badge": "打开付费计划模态框" "edition_badge": "打开付费计划模态框"
},
"auth_forms": {
"clear_email": "清除邮箱",
"show_password": "显示密码",
"hide_password": "隐藏密码",
"close_alert": "关闭警告",
"close_popover": "关闭弹出框"
} }
} }
} }

View file

@ -22,6 +22,13 @@
"collapse_sidebar": "摺疊側邊欄", "collapse_sidebar": "摺疊側邊欄",
"expand_sidebar": "展開側邊欄", "expand_sidebar": "展開側邊欄",
"edition_badge": "打開付費計劃模態框" "edition_badge": "打開付費計劃模態框"
},
"auth_forms": {
"clear_email": "清除電子郵件",
"show_password": "顯示密碼",
"hide_password": "隱藏密碼",
"close_alert": "關閉警告",
"close_popover": "關閉彈出框"
} }
} }
} }

View file

@ -69,7 +69,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
"app-container" "app-container"
)} )}
> >
<div className="w-full h-full overflow-hidden relative">{children}</div> <main className="w-full h-full overflow-hidden relative">{children}</main>
</div> </div>
</AppProvider> </AppProvider>
</body> </body>

View file

@ -1,5 +1,7 @@
import { FC } from "react"; import { FC } from "react";
import { Info, X } from "lucide-react"; import { Info, X } from "lucide-react";
// plane imports
import { useTranslation } from "@plane/i18n";
// helpers // helpers
import { TAuthErrorInfo } from "@/helpers/authentication.helper"; import { TAuthErrorInfo } from "@/helpers/authentication.helper";
@ -10,20 +12,28 @@ type TAuthBanner = {
export const AuthBanner: FC<TAuthBanner> = (props) => { export const AuthBanner: FC<TAuthBanner> = (props) => {
const { bannerData, handleBannerData } = props; const { bannerData, handleBannerData } = props;
// translation
const { t } = useTranslation();
if (!bannerData) return <></>; if (!bannerData) return <></>;
return ( return (
<div className="relative flex items-center p-2 rounded-md gap-2 border border-custom-primary-100/50 bg-custom-primary-100/10"> <div
<div className="w-4 h-4 flex-shrink-0 relative flex justify-center items-center"> role="alert"
className="relative flex items-center p-2 rounded-md gap-2 border border-custom-primary-100/50 bg-custom-primary-100/10"
>
<div className="size-4 flex-shrink-0 grid place-items-center">
<Info size={16} className="text-custom-primary-100" /> <Info size={16} className="text-custom-primary-100" />
</div> </div>
<div className="w-full text-sm font-medium text-custom-primary-100">{bannerData?.message}</div> <p className="w-full text-sm font-medium text-custom-primary-100">{bannerData?.message}</p>
<div <button
className="relative ml-auto w-6 h-6 rounded-sm flex justify-center items-center transition-all cursor-pointer hover:bg-custom-primary-100/20 text-custom-primary-100/80" type="button"
onClick={() => handleBannerData && handleBannerData(undefined)} className="relative ml-auto size-6 rounded-sm grid place-items-center transition-all hover:bg-custom-primary-100/20 text-custom-primary-100/80"
onClick={() => handleBannerData?.(undefined)}
aria-label={t("aria_labels.auth_forms.close_alert")}
> >
<X className="w-4 h-4 flex-shrink-0" /> <X className="size-4" />
</div> </button>
</div> </div>
); );
}; };

View file

@ -102,9 +102,9 @@ export const AuthHeader: FC<TAuthHeader> = observer((props) => {
return ( return (
<> <>
<div className="space-y-1 text-center"> <div className="space-y-1 text-center">
<h3 className="text-3xl font-bold text-onboarding-text-100"> <h1 className="text-3xl font-bold text-onboarding-text-100">
{typeof header === "string" ? t(header) : header} {typeof header === "string" ? t(header) : header}
</h3> </h1>
<p className="font-medium text-onboarding-text-400">{t(subHeader)}</p> <p className="font-medium text-onboarding-text-400">{t(subHeader)}</p>
</div> </div>
{children} {children}

View file

@ -47,7 +47,7 @@ export const AuthEmailForm: FC<TAuthEmailForm> = observer((props) => {
return ( return (
<form onSubmit={handleFormSubmit} className="mt-5 space-y-4"> <form onSubmit={handleFormSubmit} className="mt-5 space-y-4">
<div className="space-y-1"> <div className="space-y-1">
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="email"> <label htmlFor="email" className="text-sm text-onboarding-text-300 font-medium">
{t("auth.common.email.label")} {t("auth.common.email.label")}
</label> </label>
<div <div
@ -76,13 +76,17 @@ export const AuthEmailForm: FC<TAuthEmailForm> = observer((props) => {
ref={inputRef} ref={inputRef}
/> />
{email.length > 0 && ( {email.length > 0 && (
<XCircle <button
className="h-[46px] w-11 px-3 stroke-custom-text-400 hover:cursor-pointer text-xs" type="button"
onClick={() => { onClick={() => {
setEmail(""); setEmail("");
inputRef.current?.focus(); inputRef.current?.focus();
}} }}
/> className="absolute right-3 size-5 grid place-items-center"
aria-label={t("aria_labels.auth_forms.clear_email")}
>
<XCircle className="size-5 stroke-custom-text-400" />
</button>
)} )}
</div> </div>
{emailError?.email && !isFocused && ( {emailError?.email && !isFocused && (

View file

@ -45,8 +45,13 @@ export const ForgotPasswordPopover = () => {
> >
<span className="flex-shrink-0">🤥</span> <span className="flex-shrink-0">🤥</span>
<p className="text-xs">{t("auth.forgot_password.errors.smtp_not_enabled")}</p> <p className="text-xs">{t("auth.forgot_password.errors.smtp_not_enabled")}</p>
<button type="button" className="flex-shrink-0" onClick={() => close()}> <button
<X className="h-3 w-3 text-onboarding-text-200" /> type="button"
className="flex-shrink-0 size-3 grid place-items-center"
onClick={() => close()}
aria-label={t("aria_labels.auth_forms.close_popover")}
>
<X className="size-3 text-onboarding-text-200" />
</button> </button>
</div> </div>
)} )}

View file

@ -167,7 +167,7 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
<input type="hidden" value={passwordFormData.email} name="email" /> <input type="hidden" value={passwordFormData.email} name="email" />
{nextPath && <input type="hidden" value={nextPath} name="next_path" />} {nextPath && <input type="hidden" value={nextPath} name="next_path" />}
<div className="space-y-1"> <div className="space-y-1">
<label className="text-sm font-medium text-onboarding-text-300" htmlFor="email"> <label htmlFor="email" className="text-sm font-medium text-onboarding-text-300">
{t("auth.common.email.label")} {t("auth.common.email.label")}
</label> </label>
<div <div
@ -184,21 +184,26 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
disabled disabled
/> />
{passwordFormData.email.length > 0 && ( {passwordFormData.email.length > 0 && (
<XCircle <button
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer" type="button"
className="absolute right-3 size-5"
onClick={handleEmailClear} onClick={handleEmailClear}
/> aria-label={t("aria_labels.auth_forms.clear_email")}
>
<XCircle className="size-5 stroke-custom-text-400" />
</button>
)} )}
</div> </div>
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="password"> <label htmlFor="password" className="text-sm text-onboarding-text-300 font-medium">
{mode === EAuthModes.SIGN_IN ? t("auth.common.password.label") : t("auth.common.password.set_password")} {mode === EAuthModes.SIGN_IN ? t("auth.common.password.label") : t("auth.common.password.set_password")}
</label> </label>
<div className="relative flex items-center rounded-md bg-onboarding-background-200"> <div className="relative flex items-center rounded-md bg-onboarding-background-200">
<Input <Input
type={showPassword?.password ? "text" : "password"} type={showPassword?.password ? "text" : "password"}
id="password"
name="password" name="password"
value={passwordFormData.password} value={passwordFormData.password}
onChange={(e) => handleFormChange("password", e.target.value)} onChange={(e) => handleFormChange("password", e.target.value)}
@ -209,29 +214,33 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
autoComplete="on" autoComplete="on"
autoFocus autoFocus
/> />
{showPassword?.password ? ( <button
<EyeOff type="button"
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
onClick={() => handleShowPassword("password")} onClick={() => handleShowPassword("password")}
/> className="absolute right-3 size-5 grid place-items-center"
) : ( aria-label={t(
<Eye showPassword?.password ? "aria_labels.auth_forms.hide_password" : "aria_labels.auth_forms.show_password"
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
onClick={() => handleShowPassword("password")}
/>
)} )}
>
{showPassword?.password ? (
<EyeOff className="size-5 stroke-custom-text-400" />
) : (
<Eye className="size-5 stroke-custom-text-400" />
)}
</button>
</div> </div>
{passwordSupport} {passwordSupport}
</div> </div>
{mode === EAuthModes.SIGN_UP && ( {mode === EAuthModes.SIGN_UP && (
<div className="space-y-1"> <div className="space-y-1">
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="confirm_password"> <label htmlFor="confirm-password" className="text-sm text-onboarding-text-300 font-medium">
{t("auth.common.password.confirm_password.label")} {t("auth.common.password.confirm_password.label")}
</label> </label>
<div className="relative flex items-center rounded-md bg-onboarding-background-200"> <div className="relative flex items-center rounded-md bg-onboarding-background-200">
<Input <Input
type={showPassword?.retypePassword ? "text" : "password"} type={showPassword?.retypePassword ? "text" : "password"}
id="confirm-password"
name="confirm_password" name="confirm_password"
value={passwordFormData.confirm_password} value={passwordFormData.confirm_password}
onChange={(e) => handleFormChange("confirm_password", e.target.value)} onChange={(e) => handleFormChange("confirm_password", e.target.value)}
@ -240,17 +249,22 @@ export const AuthPasswordForm: React.FC<Props> = observer((props: Props) => {
onFocus={() => setIsRetryPasswordInputFocused(true)} onFocus={() => setIsRetryPasswordInputFocused(true)}
onBlur={() => setIsRetryPasswordInputFocused(false)} onBlur={() => setIsRetryPasswordInputFocused(false)}
/> />
{showPassword?.retypePassword ? ( <button
<EyeOff type="button"
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer" className="absolute right-3 size-5 grid place-items-center"
onClick={() => handleShowPassword("retypePassword")} aria-label={t(
/> showPassword?.retypePassword
) : ( ? "aria_labels.auth_forms.hide_password"
<Eye : "aria_labels.auth_forms.show_password"
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer"
onClick={() => handleShowPassword("retypePassword")}
/>
)} )}
onClick={() => handleShowPassword("retypePassword")}
>
{showPassword?.retypePassword ? (
<EyeOff className="size-5 stroke-custom-text-400" />
) : (
<Eye className="size-5 stroke-custom-text-400" />
)}
</button>
</div> </div>
{!!passwordFormData.confirm_password && {!!passwordFormData.confirm_password &&
passwordFormData.password !== passwordFormData.confirm_password && passwordFormData.password !== passwordFormData.confirm_password &&

View file

@ -96,7 +96,7 @@ export const AuthUniqueCodeForm: React.FC<TAuthUniqueCodeForm> = (props) => {
<input type="hidden" value={uniqueCodeFormData.email} name="email" /> <input type="hidden" value={uniqueCodeFormData.email} name="email" />
{nextPath && <input type="hidden" value={nextPath} name="next_path" />} {nextPath && <input type="hidden" value={nextPath} name="next_path" />}
<div className="space-y-1"> <div className="space-y-1">
<label className="text-sm font-medium text-onboarding-text-300" htmlFor="email"> <label htmlFor="email" className="text-sm font-medium text-onboarding-text-300">
{t("auth.common.email.label")} {t("auth.common.email.label")}
</label> </label>
<div <div
@ -109,25 +109,30 @@ export const AuthUniqueCodeForm: React.FC<TAuthUniqueCodeForm> = (props) => {
value={uniqueCodeFormData.email} value={uniqueCodeFormData.email}
onChange={(e) => handleFormChange("email", e.target.value)} onChange={(e) => handleFormChange("email", e.target.value)}
placeholder={t("auth.common.email.placeholder")} placeholder={t("auth.common.email.placeholder")}
className={`disable-autofill-style h-[46px] w-full placeholder:text-onboarding-text-400 border-0`} className="disable-autofill-style h-[46px] w-full placeholder:text-onboarding-text-400 border-0"
autoComplete="on" autoComplete="on"
disabled disabled
/> />
{uniqueCodeFormData.email.length > 0 && ( {uniqueCodeFormData.email.length > 0 && (
<XCircle <button
className="absolute right-3 h-5 w-5 stroke-custom-text-400 hover:cursor-pointer" type="button"
className="absolute right-3 size-5 grid place-items-center"
aria-label={t("aria_labels.auth_forms.clear_email")}
onClick={handleEmailClear} onClick={handleEmailClear}
/> >
<XCircle className="size-5 stroke-custom-text-400" />
</button>
)} )}
</div> </div>
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<label className="text-sm font-medium text-onboarding-text-300" htmlFor="code"> <label htmlFor="unique-code" className="text-sm font-medium text-onboarding-text-300">
{t("auth.common.unique_code.label")} {t("auth.common.unique_code.label")}
</label> </label>
<Input <Input
name="code" name="code"
id="unique-code"
value={uniqueCodeFormData.code} value={uniqueCodeFormData.code}
onChange={(e) => handleFormChange("code", e.target.value)} onChange={(e) => handleFormChange("code", e.target.value)}
placeholder={t("auth.common.unique_code.placeholder")} placeholder={t("auth.common.unique_code.placeholder")}
@ -142,11 +147,11 @@ export const AuthUniqueCodeForm: React.FC<TAuthUniqueCodeForm> = (props) => {
<button <button
type="button" type="button"
onClick={() => generateNewCode(uniqueCodeFormData.email)} onClick={() => generateNewCode(uniqueCodeFormData.email)}
className={`${ className={
isRequestNewCodeDisabled isRequestNewCodeDisabled
? "text-onboarding-text-400" ? "text-onboarding-text-400"
: "font-medium text-custom-primary-300 hover:text-custom-primary-200" : "font-medium text-custom-primary-300 hover:text-custom-primary-200"
}`} }
disabled={isRequestNewCodeDisabled} disabled={isRequestNewCodeDisabled}
> >
{resendTimerCode > 0 {resendTimerCode > 0
@ -160,7 +165,13 @@ export const AuthUniqueCodeForm: React.FC<TAuthUniqueCodeForm> = (props) => {
<div className="space-y-2.5"> <div className="space-y-2.5">
<Button type="submit" variant="primary" className="w-full" size="lg" disabled={isButtonDisabled}> <Button type="submit" variant="primary" className="w-full" size="lg" disabled={isButtonDisabled}>
{isRequestingNewCode ? t("auth.common.unique_code.sending_code") : isSubmitting ? <Spinner height="20px" width="20px" /> : t("common.continue")} {isRequestingNewCode ? (
t("auth.common.unique_code.sending_code")
) : isSubmitting ? (
<Spinner height="20px" width="20px" />
) : (
t("common.continue")
)}
</Button> </Button>
</div> </div>
</form> </form>

View file

@ -8,7 +8,7 @@ type Props = {
export const TermsAndConditions: FC<Props> = (props) => { export const TermsAndConditions: FC<Props> = (props) => {
const { isSignUp = false } = props; const { isSignUp = false } = props;
return ( return (
<span className="flex items-center justify-center py-6"> <div className="flex items-center justify-center py-6">
<p className="text-center text-sm text-onboarding-text-200 whitespace-pre-line"> <p className="text-center text-sm text-onboarding-text-200 whitespace-pre-line">
{isSignUp ? "By creating an account" : "By signing in"}, you agree to our{" \n"} {isSignUp ? "By creating an account" : "By signing in"}, you agree to our{" \n"}
<Link href="https://plane.so/legals/terms-and-conditions" target="_blank" rel="noopener noreferrer"> <Link href="https://plane.so/legals/terms-and-conditions" target="_blank" rel="noopener noreferrer">
@ -20,6 +20,6 @@ export const TermsAndConditions: FC<Props> = (props) => {
</Link> </Link>
{"."} {"."}
</p> </p>
</span> </div>
); );
}; };