fix and update
This commit is contained in:
@@ -404,8 +404,6 @@ export default function LoginPage() {
|
||||
|
||||
setOtpBackupChannels(result.otpBackupChannels ?? []);
|
||||
|
||||
|
||||
|
||||
if (result.isTotpEnabled) {
|
||||
|
||||
const challengeToken = await beginTotpLogin(identifier);
|
||||
@@ -416,13 +414,17 @@ export default function LoginPage() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
const channels = result.otpChannels ?? [];
|
||||
|
||||
const backupChannels = result.otpBackupChannels ?? [];
|
||||
|
||||
if (channels.length > 1) {
|
||||
const hasPassword = result.hasPassword;
|
||||
|
||||
const primaryChoiceCount = channels.length + (hasPassword ? 1 : 0);
|
||||
|
||||
if (primaryChoiceCount > 1) {
|
||||
|
||||
setPassword('');
|
||||
|
||||
setStep('otpChannel');
|
||||
|
||||
@@ -430,6 +432,16 @@ export default function LoginPage() {
|
||||
|
||||
}
|
||||
|
||||
if (hasPassword) {
|
||||
|
||||
setPassword('');
|
||||
|
||||
setStep('password');
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (channels.length === 1) {
|
||||
|
||||
await requestLoginOtp(channels[0].channel, identifier);
|
||||
@@ -438,8 +450,6 @@ export default function LoginPage() {
|
||||
|
||||
}
|
||||
|
||||
// Нет основных каналов, но есть резервные — даём выбрать резервную доставку.
|
||||
|
||||
if (backupChannels.length > 1) {
|
||||
|
||||
setStep('otpChannel');
|
||||
@@ -456,14 +466,6 @@ export default function LoginPage() {
|
||||
|
||||
}
|
||||
|
||||
if (result.hasPassword) {
|
||||
|
||||
setStep('password');
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
showToast('Для этого аккаунта не настроены каналы для SMS или email-кода');
|
||||
|
||||
} catch (error) {
|
||||
@@ -683,9 +685,17 @@ export default function LoginPage() {
|
||||
|
||||
|
||||
|
||||
function renderAlternativeMethods(includeOtpRequest: boolean) {
|
||||
function renderAlternativeMethods(context: 'select' | 'password' | 'otp' | 'totp') {
|
||||
|
||||
const hasAlternatives = includeOtpRequest || methods.length > 0 || otpBackupChannels.length > 0;
|
||||
const passwordMethod = methods.find((method) => method.kind === 'password');
|
||||
|
||||
const showPassword = context !== 'password' && context !== 'select' && Boolean(passwordMethod);
|
||||
|
||||
const showPrimaryOtp = context !== 'otp' && context !== 'select' && otpChannels.length > 0;
|
||||
|
||||
const showBackupOtp = otpBackupChannels.length > 0;
|
||||
|
||||
const hasAlternatives = showPassword || showPrimaryOtp || showBackupOtp;
|
||||
|
||||
if (!hasAlternatives) return null;
|
||||
|
||||
@@ -707,7 +717,7 @@ export default function LoginPage() {
|
||||
|
||||
<div className="mt-3 space-y-2">
|
||||
|
||||
{includeOtpRequest && otpChannels.length ? (
|
||||
{showPrimaryOtp ? (
|
||||
|
||||
<button
|
||||
|
||||
@@ -723,47 +733,43 @@ export default function LoginPage() {
|
||||
|
||||
<Mail className="h-5 w-5 text-[#b9bdc9]" />
|
||||
|
||||
<span className="text-sm">Получить код на {otpChannels.length > 1 ? 'почту или телефон' : otpChannels[0]?.masked}</span>
|
||||
<span className="text-sm">
|
||||
|
||||
Получить код на {otpChannels.length > 1 ? 'почту или телефон' : otpChannels[0]?.masked}
|
||||
|
||||
</span>
|
||||
|
||||
</button>
|
||||
|
||||
) : null}
|
||||
|
||||
{methods.map((method) => {
|
||||
{showPassword ? (
|
||||
|
||||
const Icon = channelIcon[method.channel] ?? KeyRound;
|
||||
<button
|
||||
|
||||
return (
|
||||
type="button"
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
|
||||
key={`${method.kind}-${method.channel}`}
|
||||
if (passwordMethod) void chooseMethod(passwordMethod);
|
||||
|
||||
type="button"
|
||||
}}
|
||||
|
||||
onClick={() => void chooseMethod(method)}
|
||||
disabled={isSubmitting}
|
||||
|
||||
disabled={isSubmitting}
|
||||
className="flex w-full items-center gap-3 rounded-[16px] bg-[#2a2c36] p-3 text-left hover:bg-[#33353f] disabled:opacity-50"
|
||||
|
||||
className="flex w-full items-center gap-3 rounded-[16px] bg-[#2a2c36] p-3 text-left hover:bg-[#33353f] disabled:opacity-50"
|
||||
>
|
||||
|
||||
>
|
||||
<KeyRound className="h-5 w-5 text-[#b9bdc9]" />
|
||||
|
||||
<Icon className="h-5 w-5 text-[#b9bdc9]" />
|
||||
<span className="text-sm">Войти с паролем</span>
|
||||
|
||||
<span className="text-sm">
|
||||
</button>
|
||||
|
||||
{method.kind === 'password' ? 'Войти с паролем' : `Код на ${method.masked}`}
|
||||
) : null}
|
||||
|
||||
</span>
|
||||
|
||||
</button>
|
||||
|
||||
);
|
||||
|
||||
})}
|
||||
|
||||
{otpBackupChannels.length ? (
|
||||
{showBackupOtp ? (
|
||||
|
||||
<>
|
||||
|
||||
@@ -1083,13 +1089,37 @@ export default function LoginPage() {
|
||||
|
||||
})}
|
||||
|
||||
{otpBackupChannels.length ? (
|
||||
{methods.some((method) => method.kind === 'password') ? (
|
||||
|
||||
<>
|
||||
<button
|
||||
|
||||
<p className="px-1 pt-2 text-xs uppercase tracking-wide text-[#7d818d]">Резервные контакты</p>
|
||||
type="button"
|
||||
|
||||
{otpBackupChannels.map((channel) => {
|
||||
disabled={isSubmitting}
|
||||
|
||||
onClick={() => {
|
||||
|
||||
setPassword('');
|
||||
|
||||
setStep('password');
|
||||
|
||||
}}
|
||||
|
||||
className="flex w-full items-center gap-3 rounded-[16px] bg-[#2a2c36] p-3 text-left hover:bg-[#33353f] disabled:opacity-50"
|
||||
|
||||
>
|
||||
|
||||
<KeyRound className="h-5 w-5 text-[#b9bdc9]" />
|
||||
|
||||
<span className="text-sm">Пароль</span>
|
||||
|
||||
</button>
|
||||
|
||||
) : null}
|
||||
|
||||
{otpChannels.length === 0 && !methods.some((method) => method.kind === 'password')
|
||||
|
||||
? otpBackupChannels.map((channel) => {
|
||||
|
||||
const Icon = channelIcon[channel.channel] ?? Mail;
|
||||
|
||||
@@ -1121,45 +1151,14 @@ export default function LoginPage() {
|
||||
|
||||
);
|
||||
|
||||
})}
|
||||
})
|
||||
|
||||
</>
|
||||
|
||||
) : null}
|
||||
|
||||
{methods.some((method) => method.kind === 'password') ? (
|
||||
|
||||
<>
|
||||
|
||||
<p className="px-1 pt-2 text-xs uppercase tracking-wide text-[#7d818d]">или</p>
|
||||
|
||||
<button
|
||||
|
||||
type="button"
|
||||
|
||||
disabled={isSubmitting}
|
||||
|
||||
onClick={() => {
|
||||
const passwordMethod = methods.find((method) => method.kind === 'password');
|
||||
if (passwordMethod) void chooseMethod(passwordMethod);
|
||||
}}
|
||||
|
||||
className="flex w-full items-center gap-3 rounded-[16px] bg-[#2a2c36] p-3 text-left hover:bg-[#33353f] disabled:opacity-50"
|
||||
|
||||
>
|
||||
|
||||
<KeyRound className="h-5 w-5 text-[#b9bdc9]" />
|
||||
|
||||
<span className="text-sm">Войти с паролем</span>
|
||||
|
||||
</button>
|
||||
|
||||
</>
|
||||
|
||||
) : null}
|
||||
: null}
|
||||
|
||||
</div>
|
||||
|
||||
{renderAlternativeMethods('select')}
|
||||
|
||||
{totpChallengeToken ? (
|
||||
|
||||
<Button type="button" variant="outline" size="lg" className="mt-6 w-full rounded-[18px] border-[#424550] text-white hover:bg-[#2a2c36]" onClick={() => setStep('totp')}>
|
||||
@@ -1218,7 +1217,7 @@ export default function LoginPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{renderAlternativeMethods(false)}
|
||||
{renderAlternativeMethods('otp')}
|
||||
|
||||
{totpChallengeToken ? (
|
||||
|
||||
@@ -1262,7 +1261,7 @@ export default function LoginPage() {
|
||||
|
||||
{isSubmitting ? <p className="mt-3 text-center text-sm text-[#b9bdc9]">Проверяем код...</p> : null}
|
||||
|
||||
{renderAlternativeMethods(true)}
|
||||
{renderAlternativeMethods('totp')}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1324,6 +1323,8 @@ export default function LoginPage() {
|
||||
|
||||
) : null}
|
||||
|
||||
{renderAlternativeMethods('password')}
|
||||
|
||||
</form>
|
||||
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user