@shopgate/engage
Version:
Shopgate's ENGAGE library.
210 lines (204 loc) • 7.69 kB
JavaScript
import 'react-phone-number-input/style.css';
import React, { useState, useContext, useMemo, useRef, useLayoutEffect, useCallback, Fragment } from 'react';
import { TextField, RippleButton, RadioGroup, RadioGroupItem, ProgressBar } from '@shopgate/engage/components';
import { i18n } from '@shopgate/engage/core/helpers';
import { useFormState } from "../../../core/hooks/useFormState";
import { FulfillmentContext } from "../../locations.context";
import { ReserveFormPhone } from "./ReserveFormPhone";
import { constraints } from "./ReserveForm.constraints";
import { form, fieldset, formField, formHeading, pickerSwitch, pickerItem, button, progressBar } from "./ReserveForm.style";
// eslint-disable-next-line max-len
/** @typedef {import('@shopgate/engage/locations/locations.types').ReservationFormValues} ReservationFormValues */
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
const PICKUP_PERSON_ME = 'me';
const PICKUP_PERSON_OTHER = 'someoneelse';
/**
* Determines the pick up person.
* @param {ReservationFormValues|null} userInput The current user input
* @return {string}
*/
const determinePickupPerson = userInput => {
if (!userInput) {
return PICKUP_PERSON_ME;
}
const meFields = ['firstName', 'lastName', 'email', 'cellPhone'];
const otherFields = ['firstName2', 'lastName2', 'email2', 'cellPhone2'];
const hasMeFields = meFields.every(field => typeof userInput[field] !== 'undefined');
const hasOtherFields = otherFields.every(field => typeof userInput[field] !== 'undefined');
if (!hasOtherFields || !hasMeFields) {
return PICKUP_PERSON_ME;
}
const valuesEqual = meFields.every((field, index) => userInput[field] === userInput[otherFields[index]]);
return valuesEqual ? PICKUP_PERSON_ME : PICKUP_PERSON_OTHER;
};
/**
* Renders the quick reservation form.
* @returns {JSX.Element}
*/
function ReserveFormUnwrapped() {
const {
sendReservation,
userInput
} = useContext(FulfillmentContext);
const [picker, setPicker] = useState(determinePickupPerson(userInput));
/** @type {ReservationFormValues} */
const defaultState = {
firstName: '',
lastName: '',
cellPhone: '',
email: '',
firstName2: '',
lastName2: '',
cellPhone2: '',
email2: ''
};
const validationConstraints = useMemo(() => ({
...constraints,
...(picker === PICKUP_PERSON_OTHER && {
firstName2: constraints.firstName,
lastName2: constraints.lastName,
cellPhone2: constraints.cellPhone,
email2: constraints.email
})
}), [picker]);
/** @type {ReservationFormValues} */
const initialState = userInput ? {
...defaultState,
...userInput
} : defaultState;
/**
* @param {Object} values The form values.
*/
/** @param {ReservationFormValues} values */
const complete = useCallback(async values => {
const response = values;
if (picker === PICKUP_PERSON_ME) {
response.firstName2 = response.firstName;
response.lastName2 = response.lastName;
response.cellPhone2 = response.cellPhone;
response.email2 = response.email;
} else {
response.firstName2 = response.firstName2 || response.firstName;
response.lastName2 = response.lastName2 || response.lastName;
response.cellPhone2 = response.cellPhone2 || response.cellPhone;
response.email2 = response.email2 || response.email;
}
await sendReservation(response);
}, [picker, sendReservation]);
const {
values,
handleChange,
handleSubmit,
changed,
valid,
validationErrors = {},
isSubmitting
} = useFormState(initialState, complete, validationConstraints);
const someoneElseRef = useRef(null);
useLayoutEffect(() => {
if (someoneElseRef.current && picker === PICKUP_PERSON_OTHER) {
someoneElseRef.current.scrollIntoView({
behavior: 'smooth'
});
}
}, [picker, someoneElseRef]);
return /*#__PURE__*/_jsxs(_Fragment, {
children: [/*#__PURE__*/_jsx("div", {
className: progressBar,
children: /*#__PURE__*/_jsx(ProgressBar, {
isVisible: isSubmitting
})
}), /*#__PURE__*/_jsxs("form", {
onSubmit: handleSubmit,
className: form,
children: [/*#__PURE__*/_jsxs("fieldset", {
className: fieldset,
children: [/*#__PURE__*/_jsx(TextField, {
name: "firstName",
value: values.firstName,
onChange: handleChange,
label: i18n.text('locations.firstName'),
className: formField,
errorText: i18n.text(validationErrors.firstName)
}), /*#__PURE__*/_jsx(TextField, {
name: "lastName",
value: values.lastName,
onChange: handleChange,
label: i18n.text('locations.lastName'),
className: formField,
errorText: i18n.text(validationErrors.lastName)
}), /*#__PURE__*/_jsx(ReserveFormPhone, {
name: "cellPhone",
value: values.cellPhone,
onChange: handleChange,
label: i18n.text('locations.cellPhone'),
errorText: i18n.text(validationErrors.cellPhone)
}), /*#__PURE__*/_jsx(TextField, {
name: "email",
value: values.email,
onChange: handleChange,
label: i18n.text('locations.emailAddress'),
className: formField,
errorText: i18n.text(validationErrors.email)
})]
}), /*#__PURE__*/_jsx("p", {
className: formHeading,
children: i18n.text('locations.who_will_pickup')
}), /*#__PURE__*/_jsx("div", {
className: pickerSwitch,
children: /*#__PURE__*/_jsxs(RadioGroup, {
name: "picker",
direction: "row",
value: picker,
onChange: setPicker,
children: [/*#__PURE__*/_jsx(RadioGroupItem, {
label: i18n.text('locations.me'),
name: PICKUP_PERSON_ME,
className: pickerItem
}), /*#__PURE__*/_jsx(RadioGroupItem, {
label: i18n.text('locations.someone_else'),
name: PICKUP_PERSON_OTHER,
className: pickerItem
})]
})
}), picker === PICKUP_PERSON_OTHER && /*#__PURE__*/_jsxs("fieldset", {
className: fieldset,
ref: someoneElseRef,
children: [/*#__PURE__*/_jsx(TextField, {
name: "firstName2",
value: values.firstName2,
onChange: handleChange,
label: i18n.text('locations.firstName'),
className: formField,
errorText: i18n.text(validationErrors.firstName2)
}), /*#__PURE__*/_jsx(TextField, {
name: "lastName2",
value: values.lastName2,
onChange: handleChange,
label: i18n.text('locations.lastName'),
className: formField,
errorText: i18n.text(validationErrors.lastName2)
}), /*#__PURE__*/_jsx(ReserveFormPhone, {
name: "cellPhone2",
value: values.cellPhone2,
onChange: handleChange,
label: i18n.text('locations.cellPhone'),
errorText: i18n.text(validationErrors.cellPhone2)
}), /*#__PURE__*/_jsx(TextField, {
name: "email2",
value: values.email2,
onChange: handleChange,
label: i18n.text('locations.emailAddress'),
className: formField,
errorText: i18n.text(validationErrors.email2)
})]
}), /*#__PURE__*/_jsx(RippleButton, {
type: "secondary",
disabled: changed || valid === false || isSubmitting,
className: button,
children: i18n.text('locations.place_reservation')
})]
})]
});
}
export const ReserveForm = ReserveFormUnwrapped;