in support-frontend/assets/pages/paper-subscription-checkout/components/paperCheckoutForm.tsx [194:582]
function PaperCheckoutForm(props: PropTypes) {
useCsrCustomerData(props.setCsrCustomerData);
const invalidDeliveryDates = ['-12-25', '-01-01'];
const days = getDays(props.fulfilmentOption, props.productOption).filter(
(day) => {
const date = formatMachineDate(day);
return !invalidDeliveryDates.some((dateSuffix) =>
date.endsWith(dateSuffix),
);
},
);
const isHomeDelivery = props.fulfilmentOption === HomeDelivery;
if (props.deliveryAgentsResponse?.type === 'PaperRoundError') {
logException(`Error fetching delivery providers`);
}
const fulfilmentOptionDescriptor = isHomeDelivery
? 'Newspaper'
: 'Subscription card';
const deliveryTitle = isHomeDelivery
? 'Where should we deliver your newspaper?'
: 'Where should we deliver your subscription card?';
const submissionErrorHeading =
props.submissionError === 'personal_details_incorrect'
? 'Sorry, there was a problem'
: 'Sorry, we could not process your payment';
const paymentMethods = supportedPaymentMethods(
props.currencyId,
props.billingAddressMatchesDelivery ? props.country : props.billingCountry,
);
const isSubscriptionCard = props.fulfilmentOption === Collection;
let formattedStartDate = '';
if (isSubscriptionCard) {
const timeNow = Date.now();
const startDate = getPaymentStartDate(
timeNow,
props.productOption as ActivePaperProductOptions,
);
formattedStartDate = getFormattedStartDate(startDate);
setSubsCardStartDateInState(props.setStartDate, startDate);
}
const [digiSubPriceString, setDigiSubPriceString] = useState<string>('');
const [includesDigiSub] = useState<boolean>(false);
const simplePrice = digiSubPriceString.replace(/\/(.*)/, ''); // removes anything after the /
const priceHasRedundantFloat = simplePrice.split('.')[1] === '00'; // checks whether price is something like '£10.00'
const cleanedPrice = priceHasRedundantFloat
? simplePrice.replace(/\.(.*)/, '')
: simplePrice; // removes decimal point if there are no pence
const expandedPricingText = `${cleanedPrice} per month`;
const deliveryInstructionsError = props.formErrors.find(
(error) => error.field === 'deliveryInstructions',
);
useEffect(() => {
// Price of the 'Plus' product that corresponds to the selected product option
const plusPrice = includesDigiSub
? props.discountedPrice
: props.correspondingProductOptionPrice;
// Price of the standard paper-only product that corresponds to the selected product option
const paperPrice = includesDigiSub
? props.correspondingProductOptionPrice
: props.discountedPrice;
const digitalCost = sensiblyGenerateDigiSubPrice(plusPrice, paperPrice);
setDigiSubPriceString(
getPriceSummary(showPrice(digitalCost, false), props.billingPeriod),
);
sendEventSubscriptionCheckoutStart(
props.product,
false,
props.price,
props.billingPeriod,
);
}, []);
const subsCardOrderSummary = (
<PaperOrderSummary
image={
<GridImage
gridId="printCampaignDigitalVoucher"
srcSizes={[500]}
sizes="(max-width: 740px) 50vw, 696"
imgType="png"
altText=""
/>
}
total={props.discountedPrice}
digiSubPrice={expandedPricingText}
startDate={formattedStartDate}
includesDigiSub={includesDigiSub}
changeSubscription={`${paperSubsUrl(
Collection,
getQueryParameter('promoCode'),
)}`}
/>
);
const homeDeliveryOrderSummary = (
<PaperOrderSummary
image={
<GridImage
gridId="printCampaignHDdigitalVoucher"
srcSizes={[500]}
sizes="(max-width: 740px) 50vw, 696"
imgType="png"
altText=""
/>
}
total={props.discountedPrice}
digiSubPrice={expandedPricingText}
includesDigiSub={includesDigiSub}
changeSubscription={`${paperSubsUrl(
HomeDelivery,
getQueryParameter('promoCode'),
)}`}
startDate={formattedStartDate}
/>
);
return (
<Content>
<Layout
aside={isHomeDelivery ? homeDeliveryOrderSummary : subsCardOrderSummary}
>
<Form
onSubmit={(ev) => {
ev.preventDefault();
props.submitForm();
}}
>
<FormSection title="Your details">
<Select
cssOverrides={marginBottom}
id="title"
data-qm-masking="blocklist"
label="Title"
optional
value={props.title ?? ''}
onChange={(e) => props.setTitle(e.target.value)}
>
<OptionForSelect>Select a title</OptionForSelect>
{options(titles)}
</Select>
<PersonalDetails
firstName={props.firstName}
setFirstName={props.setFirstName}
lastName={props.lastName}
setLastName={props.setLastName}
email={props.email}
setEmail={props.setEmail}
confirmEmail={props.confirmEmail}
setConfirmEmail={props.setConfirmEmail}
isSignedIn={props.isSignedIn}
telephone={props.telephone}
setTelephone={props.setTelephone}
formErrors={props.formErrors}
signOut={props.signOut}
/>
</FormSection>
<FormSection title={deliveryTitle}>
{isHomeDelivery ? (
<PaperAddress countries={newspaperCountries} />
) : (
<DeliveryAddress countries={newspaperCountries} />
)}
{isHomeDelivery && (
<DeliveryAgentsSelect
deliveryAgentsResponse={props.deliveryAgentsResponse}
chosenDeliveryAgent={props.chosenDeliveryAgent}
setDeliveryAgent={props.setDeliveryAgent}
formErrors={props.formErrors}
deliveryAddressErrors={props.deliveryAddressErrors}
/>
)}
{isHomeDelivery ? (
<TextArea
error={deliveryInstructionsError?.message}
cssOverrides={controlTextAreaResizing}
id="delivery-instructions"
data-qm-masking="blocklist"
label="Delivery instructions"
autoComplete="new-password" // Using "new-password" here because "off" isn't working in chrome
supporting="Please let us know any details to help us find your property (door colour, any access issues) and the best place to leave your newspaper. For example, 'Front door - red - on Crinan Street, put through letterbox'"
maxLength={250}
value={props.deliveryInstructions ?? ''}
onChange={(e) => props.setDeliveryInstructions(e.target.value)}
optional
/>
) : null}
</FormSection>
<FormSection title="Is the billing address the same as the delivery address?">
<Rows>
<RadioGroup
label="Is the billing address the same as the delivery address?"
hideLabel
id="billingAddressMatchesDelivery"
name="billingAddressMatchesDelivery"
orientation="vertical"
error={firstError(
'billingAddressMatchesDelivery',
props.formErrors,
)}
>
<Radio
id="qa-billing-address-same"
value="yes"
label="Yes"
name="billingAddressMatchesDelivery"
checked={props.billingAddressMatchesDelivery}
onChange={() => props.setBillingAddressMatchesDelivery(true)}
/>
<Radio
id="qa-billing-address-different"
label="No"
value="no"
name="billingAddressMatchesDelivery"
checked={!props.billingAddressMatchesDelivery}
onChange={() => props.setBillingAddressMatchesDelivery(false)}
/>
</RadioGroup>
</Rows>
</FormSection>
{!props.billingAddressMatchesDelivery ? (
<FormSection title="Your billing address">
<BillingAddress countries={newspaperCountries} />
</FormSection>
) : null}
{isHomeDelivery ? (
<FormSection title="When would you like your subscription to start?">
<Rows>
<RadioGroup
label="When would you like your subscription to start?"
hideLabel
name="startDate"
id="startDate"
error={firstError('startDate', props.formErrors)}
>
{days.map((day) => {
const [userDate, machineDate] = [
formatUserDate(day),
formatMachineDate(day),
];
return (
<Radio
label={userDate}
value={userDate}
name={machineDate}
checked={machineDate === props.startDate}
onChange={() => props.setStartDate(machineDate)}
/>
);
})}
</RadioGroup>
<Text className="component-text__paddingTop">
<p>
We will take the first payment on the date you receive your
first {fulfilmentOptionDescriptor.toLowerCase()}.
</p>
<p>
Subscription start dates are automatically selected to be
the earliest we can fulfil your order.
</p>
</Text>
</Rows>
</FormSection>
) : null}
{paymentMethods.length > 0 ? (
<FormSection
cssOverrides={removeTopBorder}
title={
paymentMethods.length > 1
? 'How would you like to pay?'
: 'Payment Method'
}
>
<PaymentMethodSelector
availablePaymentMethods={paymentMethods}
paymentMethod={props.paymentMethod}
setPaymentMethod={(paymentMethod) =>
props.setPaymentMethod({ paymentMethod })
}
validationError={firstError('paymentMethod', props.formErrors)}
/>
</FormSection>
) : (
<GeneralErrorMessage
classModifiers={['no-valid-payments']}
errorHeading="Payment methods are unavailable"
errorReason="all_payment_methods_unavailable"
/>
)}
<FormSectionHiddenUntilSelected
id="stripeForm"
show={props.paymentMethod === Stripe}
title="Your card details"
>
<StripeProviderForCountry
country={props.country}
currency={props.currencyId}
isTestUser={props.isTestUser}
submitForm={props.submitForm}
allErrors={
[
...props.billingAddressErrors,
...props.deliveryAddressErrors,
...props.formErrors,
] as Array<FormError<FormField>>
}
validateForm={props.validateForm}
buttonText="Pay now"
csrf={props.csrf}
setStripePublicKey={(key: string) =>
props.setStripePublicKey(key)
}
/>
<p css={DisclaimerOnSubscribeStyles}>
<StripeDisclaimer />
</p>
</FormSectionHiddenUntilSelected>
<FormSectionHiddenUntilSelected
id="directDebitForm"
show={props.paymentMethod === DirectDebit}
title="Your account details"
>
<DirectDebitForm
buttonText="Subscribe"
submitForm={props.submitForm}
allErrors={[
...props.billingAddressErrors,
...props.deliveryAddressErrors,
...props.formErrors,
]}
submissionError={props.submissionError}
submissionErrorHeading={submissionErrorHeading}
/>
</FormSectionHiddenUntilSelected>
{props.paymentMethod === PayPal ? (
<PayPalSubmitButton
paymentMethod={props.paymentMethod}
onPaymentAuthorised={props.onPaymentAuthorised}
csrf={props.csrf}
currencyId={props.currencyId}
payPalHasLoaded={props.payPalHasLoaded}
formIsValid={props.formIsValid}
validateForm={props.validateForm}
isTestUser={props.isTestUser}
setupRecurringPayPalPayment={props.setupRecurringPayPalPayment}
amount={props.discountedPrice.price}
billingPeriod={props.billingPeriod}
allErrors={
[
...props.billingAddressErrors,
...props.deliveryAddressErrors,
...props.formErrors,
] as Array<FormError<FormField>>
}
/>
) : null}
<GeneralErrorMessage
errorReason={props.submissionError ?? undefined}
errorHeading={submissionErrorHeading}
/>
<DirectDebitPaymentTerms paymentMethod={props.paymentMethod} />
</Form>
</Layout>
</Content>
);
} // ----- Exports ----- //