function PaperCheckoutForm()

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 ----- //