正在编写预订应用程序。我希望时间选项根据本地存储中保存的信息进行更新。提交表单后,应从当天的可用性数组中删除给定日期的选定时间选项。
下面是子表单组件:
import { Button } from '../../components/Button'
import silhouetteLogo from '../../images/silouhette_logo-removebg-preview.png'
import { useFormik } from 'formik';
import * as Yup from 'yup';
import { DateComponent } from '../../components/Date';
import 'bootstrap/dist/css/bootstrap.min.css';
export function BookingForm({ formSubmission }) {
const formik = useFormik({
initialValues: {
date: new Date().toLocaleDateString(),
time: 'Select Time',
firstName: '',
email: '',
confirmButton: false,
},
validationSchema: Yup.object().shape({
date: Yup.date()
.test(
'date',
'The date you selected has already passed.',
function (date) { return new Date(date) >= new Date(); }
)
.required('Required'),
time: Yup.string()
.notOneOf(['Select Time'], 'Please select one of our available time slots.')
.required('Please select one of our available time slots.'),
firstName: Yup.string().required('Required').trim(),
email: Yup.string().email('Please enter a valid email address').required('Required').trim(),
confirmButton: Yup.boolean().oneOf([true], 'You must confirm the information above is accurate to submit your booking'),
}),
onSubmit:
(values) => {
formSubmission(values);
}
});
const availability = window.fetchAPI(formik.values.date);
return (
<form data-testid='booking-form' onSubmit={formik.handleSubmit}>
<fieldset className='scheduleCheck'>
<h1 className="scheduleCheckTitle">Tell us about your Party!</h1>
<div id='scheduleChecker' className='scheduleCheckInputs'>
<div className="date">
<label htmlFor='date'>Date</label>
<input id='date' type='text' className='form-control visually-hidden' value={formik.values.date} onChange={formik.handleChange} onBlur={formik.handleBlur} />
<DateComponent
id='visible-date'
selected={formik.values.date}
className={formik.touched.date && formik.errors.date ? "form-control error date" : "form-control"}
onChange={(d) => formik.setFieldValue('date', d)}
onChangeRaw={(e) => formik.setFieldTouched('date', e.target.value)}
onBlur={formik.handleBlur}
ariaHidden
required
/>
</div>
<div className="dropdown time">
<label htmlFor='time'>Time</label>
<select
id='time'
name='time'
type="button"
className={formik.touched.time && formik.errors.time ? 'btn btn-secondary dropdown-toggle error' : "btn btn-secondary dropdown-toggle"}
aria-expanded="false"
value={formik.values.time}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
required
>
<option value='Select Time'>Select Time</option>
{availability.map((time, index) => <option data-testid='time-option' className="dropdown-item" value={time} key={index}>{time}</option>)}
</select>
</div>
</div >
<div>
{formik.touched.date && formik.errors.date ? <div data-testid='validation-field' className='schedule-check-error'>{formik.errors.date}</div> : null}
{formik.touched.time && formik.errors.time ? <div data-testid='validation-field' className='schedule-check-error'>{formik.errors.time}</div> : null}
</div>
</fieldset>
<div className='infoInput'>
<fieldset className='infoInput'>
<div className='bookingTitle'>
<h1>Complete Your Booking!</h1>
<img className='silhouetteLogo' src={silhouetteLogo} alt='little lemon logo' />
</div>
<div className='contactInfo'>
<div className="row name">
<div className="col firstName">
<label htmlFor="firstName">First Name</label>
<input
id='firstName'
name='firstName'
type="text"
className={formik.touched.firstName && formik.errors.firstName ? "form-control error" : "form-control name-input"}
value={formik.values.firstName}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
placeholder=' '
required
/>
{formik.touched.firstName && formik.errors.firstName ? <div data-testid='validation-field' className='error-message'>{formik.errors.firstName}</div> : null}
</div>
</div>
<div className="row phemail">
<div className="col email">
<label htmlFor="email" >Email Address</label>
<input
id='email'
name='email'
type="email"
className={formik.touched.email && formik.errors.email ? "form-control error" : "form-control email"}
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
required
/>
{formik.touched.email && formik.errors.email ? <div data-testid='validation-field' className='error-message'>{formik.errors.email}</div> : null}
</div>
</div>
</div>
</fieldset>
<fieldset className="align-items-center completeForm">
<div className='row'>
<div className="col form-check mb-2 confirm">
<input
className={formik.touched.confirmButton && formik.errors.confirmButton ? 'error form-check-input' : 'form-check-input'}
type="checkbox"
id="confirmButton"
onChange={formik.handleChange}
checked={formik.values.confirmButton}
onBlur={formik.handleBlur}
required />
<label className="form-check-label" htmlFor="confirmButton">
Check here to confirm the above information is accurate
</label>
{formik.touched.confirmButton && formik.errors.confirmButton ? <div data-testid='validation-field' className='error-message'>{formik.errors.confirmButton}</div> : null}
</div>
<div className="col bookButton">
<Button testId='submit' type='submit' onClick={formik.handleSubmit} textVariant=' Book My Table' />
</div>
</div>
</fieldset>
</div>
</form >
)
}
接下来是包含页面布局和formSubmission函数的父组件。您会注意到我故意只将日期和时间保存到本地存储中:
import { BookingForm } from "./BookingForm"
import { ConfirmedBooking } from "./ConfirmedBooking"
import restaurant from "../../images/restaurant-image.jpg"
import './Booking.css';
import { Routes, Route, useNavigate } from 'react-router-dom';
import { Hero } from "../Home/Hero";
export function Booking() {
const navigate = useNavigate();
const formSubmission = (values) => {
console.log('Form submitted:', values);
if (window.submitAPI(values)) {
alert('Your reservation has been submitted!');
localStorage.setItem('date', values.date);
localStorage.setItem('time', values.time);
navigate('/ConfirmedBooking');
} else {
alert('There was an error with your submission. Please try again.');
}
}
return (
<>
<Hero
title='Reservations'
text="Come enjoy a meal with us in our restaurant space. With our gorgeous Mediterranean decor, you will feel like you have been transported to Greece! Can’t make it in for your event? We also offer catering services!We are a family-owned Mediterranean restaurant, focused on traditional recipes served with a modern twist"
image={restaurant}
alt='restaurant-image'
textVariant='Catering Menu'
path='/Menu'
/>
<Routes>
<Route path="/BookingForm" element={<BookingForm formSubmission={formSubmission} />} />
<Route path="/ConfirmedBooking" element={<ConfirmedBooking />} />
</Routes>
<BookingForm formSubmission={formSubmission} />
</>
)
}
最后是正在调用的 api 的代码:
const seededRandom = function (seed) {
var m = 2 ** 35 - 31;
var a = 185852;
var s = seed % m;
return function () {
return (s = s * a % m) / m;
};
}
var fetchAPI = function (date) {
if (!(date instanceof Date)) {
date = new Date(date);
};
let result = [];
let random = seededRandom(date.getDate());
for (let i = 5; i <= 11; i++) {
if (random() < 0.5) {
result.push(i + ':00 PM');
}
if (random() < 0.5) {
result.push(i + ':30 PM');
}
}
return result;
};
var submitAPI = function (formData) {
return true;
};
我观看了许多有关如何使用本地存储的视频,并且对其工作原理有相当好的掌握,但我很难应用本地存储中保存的日期和时间数据来更新所需的组件。
使这种情况变得更复杂的是我当前没有使用 useState 挂钩。相反,我的状态由 useFormik 处理,因为我也需要表单验证方面的帮助。 formSubmission 函数应该保留在父组件中,但我似乎无法很好地维护表单的状态,并使用它来过滤每次提交的给定日期的时间数组。
如有任何帮助,我们将不胜感激。
我最终使用以下代码对 api.js 文件中的
fetchAPI
函数进行了调整:
export function fetchAPI(selectedDate) {
if (!(selectedDate instanceof Date)) {
selectedDate = new Date(selectedDate);
};
var submissionData = JSON.parse(localStorage.getItem('Date and Time'));
let bookedTimes = submissionData ? submissionData
.filter((data) => new Date(data.date).toDateString() === selectedDate.toDateString())
.map((data) => data.time) : [];
let result = [];
let random = seededRandom(selectedDate);
for (let i = 5; i <= 11; i++) {
var proposed1 = i + ':00 PM';
var proposed2 = i + ':30 PM';
if (random() < 0.5 && !bookedTimes.includes(proposed1)) {
result.push(proposed1);
}
if (random() < 0.5 && !bookedTimes.includes(proposed2)) {
result.push(proposed2);
}
}
return result;