Компонент кода авторизации

Храните шесть символов в состоянии, нормализуйте допустимый ввод и отправляйте код только после заполнения всех полей. Проверка действительности кода остаётся на сервере.

Короткий ответ

Что ответить на собеседовании

Храните шесть символов в состоянии, нормализуйте допустимый ввод и отправляйте код только после заполнения всех полей. Проверка действительности кода остаётся на сервере.

Подробный разбор

Ответ с пояснениями

Условие

Компонент кода авторизации

Резюме AuthCodeInput — это поле для ввода 6-значного кода авторизации, используемое для потоков в стиле 2FA. Оно отображает шесть однобуквенных полей и интегрируется с бэкендом для проверки введенного кода.

История пользователя Как пользователь, я хочу ввести 6-значный код авторизации и отправить его, чтобы подтвердить свою личность в знакомом потоке 2FA.

Анатомия

  • 6 полей ввода, расположенных в ряд (по одному символу в каждом)
  • В центре полей отображается дефис (-)

Основное поведение Вводы

  • Каждое из 6 полей принимает один символ.
  • Разрешены только цифры 0–9 и буквы A-Z.
  • При вводе допустимого символа: o символ сохраняется в текущем поле. o если введенный символ в нижнем регистре, он автоматически преобразуется в верхний. o автоматически фокусируется на следующее поле.
  • Полная OTP: o компонент считает значение "завершенным" только когда все 6 полей заполнены.

Ответ

Храните шесть символов в состоянии, нормализуйте допустимый ввод и отправляйте код только после заполнения всех полей. Проверка действительности кода остаётся на сервере.

Минимальный React-пример использует переданный async-callback onVerify для интеграции с API. Дефис отображается после третьего поля.

import { Fragment, useRef, useState } from 'react';

function AuthCodeInput({ onVerify }) {
  const [digits, setDigits] = useState(Array(6).fill(''));
  const [pending, setPending] = useState(false);
  const [error, setError] = useState('');
  const inputs = useRef([]);
  const busy = useRef(false);
  const complete = digits.every(value => /^[A-Z0-9]$/.test(value));
  function change(index, raw) {
    if (raw !== '' && !/^[a-z0-9]$/i.test(raw)) return;
    setDigits(old => old.map((value, i) => i === index ? raw.toUpperCase() : value));
    setError('');
    if (raw && index < 5) inputs.current[index + 1]?.focus();
  }
  async function submit(event) {
    event.preventDefault();
    if (!complete || busy.current) return;
    busy.current = true; setPending(true); setError('');
    try { await onVerify(digits.join('')); }
    catch { setError('Не удалось подтвердить код. Попробуйте ещё раз.'); }
    finally { busy.current = false; setPending(false); }
  }
  return <form onSubmit={submit}>
    <fieldset disabled={pending} style={{ display: 'flex', gap: 8 }}>
      <legend>Код авторизации</legend>
      {digits.map((value, index) => <Fragment key={index}>
        {index === 3 && <span aria-hidden='true'>-</span>}
        <input value={value} maxLength={1} autoCapitalize='characters'
          style={{ width: '2em' }} aria-label={`Символ ${index + 1} из 6`}
          ref={element => { inputs.current[index] = element; }}
          onChange={event => change(index, event.target.value)}
          onKeyDown={event => {
            if (event.key === 'Backspace' && !value && index > 0) {
              event.preventDefault(); inputs.current[index - 1]?.focus();
            }
          }} />
      </Fragment>)}
    </fieldset>
    <button disabled={!complete || pending}>Подтвердить</button>
    {error && <p role='alert'>{error}</p>}
  </form>;
}

Backend проверяет срок, одноразовость и число попыток; заполненные поля не доказывают успешную авторизацию. Полная вставка OTP и платформенное автозаполнение требуют отдельной доработки сверх базового условия.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее