Форма бронирования
В выборе мест теперь есть форма, под итогом: поля «Имя» и «Email» и кнопка «Забронировать», переписанные на JSX (где for стал htmlFor, а novalidate — noValidate). Оживите её, как в уроке «Формы»: поля управляемые, с состояниями name и email, а форма вызывает handleSubmit, которая начинается с event.preventDefault().
Проверка. Затем handleSubmit проверяет форму, шаг за шагом, как в упражнении «Сообщения об ошибках»: пустое имя, email без @, не выбрано ни одного места. Первая найденная проблема попадает в состояние error, которое показывает форма, а return завершает обработчик, так что ничего не бронируется. Посетитель исправляет ошибку и снова нажимает «Забронировать». Старая страница показывала все три сообщения сразу. Здесь сообщение одно, под кнопкой, и код короче.
Бронирование. Когда всё верно, выбор мест создаёт билет: объект с id из Date.now(), сеансом, местами, именем и email. Но куда он попадёт? Билеты нужны выбору мест, чтобы показывать забронированные места занятыми, и списку «Ваши билеты» в Showtimes. Поэтому это состояние Showtimes, tickets, а выбор мест получает билеты в пропсах вместе с функцией, которая добавляет билет, как форма для ваших слов в итоговом проекте курса React:
onBook({
id: Date.now(),
showtime: showtime,
seats: selected,
name: name.trim(),
email: email.trim(),
});Билет хранит сеанс целиком, чтобы список мог показать его день, время и фильм. Затем выбор мест очищает selected и оба поля. С этого момента забронированные места заняты: isTaken() тоже проверяет через some(), есть ли это место в одном из билетов на этот сеанс, как делал старый скрипт:
return tickets.some(
(ticket) =>
ticket.showtime.id === showtime.id && ticket.seats.includes(seat),
);Наконец, выбор мест сообщает, какие места забронированы, — Забронировано! Ваши места: A3, A4, — ещё одним состоянием, confirmation. Его текст можно составить из selected даже после setSelected([]): как вы знаете из урока «Состояние», новое значение появляется только при следующей отрисовке.
Задание
- 1
В
SeatPickerдобавьте состоянияname,emailиerror, сначала все"", и сделайте оба поля управляемыми. Дайте формеonSubmit={handleSubmit}.handleSubmit(event)вызываетevent.preventDefault(), а затем записывает сообщение вerrorи завершается, когда имя пустое (name.trim() === ""):Введите имя., когда в email нет@:Введите корректный адрес электронной почты., и когда не выбрано ни одного места:Выберите хотя бы одно место.Если ошибка есть, показывайте её под кнопкой в<p className="mt-4 text-sm text-red-700">. Нажмите «Забронировать» при пустых полях. - 2
В
Showtimesдобавьте состояниеtickets, пустой массив, и обработчикhandleBook(ticket), который добавляет билет в конецtickets. Передайте выбору мест пропсыtickets={tickets}иonBook={handleBook}. ВSeatPicker, когда всё верно, верните вerrorзначение"", вызовитеonBook(), как выше, и очиститеselectedи оба поля. ПустьisTaken()проверяет и билеты, как выше. Забронируйте место: оно станет серым. - 3
После бронирования запишите
Забронировано! Ваши места: A3, A4в новое состояниеconfirmation, с местами изselected.join(", "), и покажите его под формой в<p className="mt-4 font-semibold text-green-700">. В списке «Ваши билеты» (раздел с заголовком уже готов вShowtimes) покажитеliдля каждого билета, с ключом, классамиrounded-lg border border-stone-200 bg-white px-4 py-2и текстомПятница 17:30, Роботы в отпуске: A3, A4, составленным изticket.showtimeиticket.seats.join(", ").