@mychoice/mychoice-sdk-modules 2.2.23 → 2.2.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { ErrorBoundary } from 'react-error-boundary';
3
- import { AppTypes, isMyChoiceLike, TitleForm, TooltipForm, IconDelete, ColorVariablesTypes, InputTypes, InputForm, InputFormPhone, InputFormEmail, InputFormLicence, SelectForm, getFormattedDate, DateTypes, getDateOptions, ButtonForm, defaultBrokerPhone, DriverPriorityTypes, SizeTypes, ButtonBase, CategoryTypes, ColorTypes, defaultLocalIndex, liabilityOptions, accidentBenefitsOptionalOptions, coverageOptions, lossOfUseOptions, liabilityForDamageOptions, limitedWaiverOfDepreciationOptions, OfferDetail, CompanyRoleTypes, OperationHoursInfo, OfferHeader, OfferPrice, ButtonTypes, ButtonVariantTypes, IconDropdownArrow, InsuranceTypes, HeaderNavGroup, ButtonMenu, DeviceTypes, IconLoaderPrimary, getInsuranceType, RequestStatusTypes, formatPostalCode, IconLoaderSecondary, postalCodeFormat, useEffectOnce, carCondition, carStatus, carWinterTiresCheck, carKeepPlace, carUsagePurpose, firstDriveDistanceList, dailyDriveBusinessDistanceList, yearlyDriveDistanceList, numberWithCommas, VehiclePrimaryUseTypes, addDaysToDate, comprehensiveCoverage, collisionCoverage, maritalStatusOptions, subYearsFromDate, occupationOptions, genderOptions, applicantRelationshipOptions, addYearsToDate, checkDateIsSpecial, DriverLicenceTypes, getDifferenceInYears, getLicenceTypeOptions, getDisabledLicenceTypes, yesNoOptions, getMinDate, CheckboxForm, getMinDateByYears, compareDates, insuranceCancellationReasonOptions, DriverListTypes, licenceSuspensionsReasonOptions, trafficTicketsGroupOptions, ValidationStatusTypes, getPlaceholderEmail, QuoteEdit, homeOwnerTypeOptions, tenantBuildingStructureOptions, condoBuildingStructureOptions, homeBuildingStructureOptions, residentsOptions, insuredYearsOptions, getInsuranceYearsOptions, ApplicantListTypes, claimTypeOptions, exteriorFinishOptions, constructionTypeOptions, garageTypeOptions, getNumericOptions, fireHallDistanceOptions, fireHydrantDistanceOptions, primaryHeatingTypeOptions, auxHeatingTypeOptions, InfoMessage, ppOptions, homeCoverageOptions, homeLiabilityOptions, lifeInsuranceTypeOptions, lifeInsuranceOntarioTypeOptions, lifeCoverageOptions, smokerOptions, MychoiceStep, Step, IconClock, ButtonArrow, DirectionTypes, ButtonTabArrow, ButtonTab, ButtonTabMobile, NavigationCar, NavigationPerson, NavigationDiscount, NavigationQuotes, NavigationAddress, NavigationProperty, ModalTypes } from '@mychoice/mychoice-sdk-components';
4
- import { useStoreAppConfig, useStoreFormCarVehicle, useStoreFormCarDriverBase, useStoreFormCarDiscount, StoreFormCarDiscountActionTypes, useStoreFormCarQuote, CarQuoteDataHandler, useValidationCarDiscount, StoreFormCarVehicleActionTypes, useStoreFormHomeDiscount, useStorePartner, useStoreDeviceType, useStoreAppLoader, useStoreAppModal, StoreConfigAppModalActionTypes, useHandlerPostal, useHandlerCarMake, useHandlerCarModel, useProvince, useAbReform, useValidationVehicle, useAutofillCarForm, StoreFormCarDriverBaseActionTypes, useStoreFormCarConfig, useStoreFormCarDriverInfo, StoreFormCarDriverInfoActionTypes, useStoreFormCarDriverLicence, addDayToDate, StoreFormCarDriverLicenceActionTypes, useStoreFormCarDriverInsurance, StoreFormCarDriverInsuranceActionTypes, useStoreFormCarDriverCancellation, StoreFormCarDriverCancellationActionTypes, useStoreFormCarDriverSuspension, StoreFormCarDriverSuspensionActionTypes, useStoreFormCarDriverAccident, StoreFormCarDriverAccidentActionTypes, useStoreFormCarDriverTicket, StoreFormCarDriverTicketActionTypes, useValidationDriver, useHandlerCarQuoterEmail, useStoreFormHomeDwelling, useStoreFormHomePostal, useStoreFormHomeApplicantBase, StoreFormHomePostalActionTypes, StoreFormHomeDwellingActionTypes, StoreConfigAppConfigActionTypes, StoreFormHomeApplicantBaseActionTypes, useValidationAddress, useStoreFormHomeApplicantInfo, StoreFormHomeDiscountActionTypes, StoreFormHomeApplicantInfoActionTypes, useStoreFormHomeApplicantInsurance, StoreFormHomeApplicantInsuranceActionTypes, useStoreFormHomeApplicantCancellation, StoreFormHomeApplicantCancellationActionTypes, useStoreFormHomeApplicantClaim, StoreFormHomeApplicantClaimActionTypes, useValidationApplicant, useValidationDwelling, useStoreFormHomeQuote, HomeQuoteDataHandler, useValidationHomeDiscount, useHandlerHomeQuoterEmail, useStoreFormLifeCoverage, StoreFormLifeCoverageActionTypes, useValidationCoverage, useAutofillLifeForm, useStoreFormLifeQuote, useStoreFormLifeApplicant, LifeQuoteDataHandler, useValidationLifeApplicant, useHandlerLifeQuoterEmail, StoreFormLifeApplicantActionTypes, useStoreFormCarPostal, useStoreFormLifePostal, ClearFormDataHandler, useStoreAppDevice, useStoreClient, useHandlerAuth, useHandlerPartner, StoreConfigAppLoaderActionTypes, StoreFormCarConfigActionTypes, StoreFormCarPostalActionTypes, StoreFormCarQuoteActionTypes, StoreFormHomeQuoteActionTypes, StoreFormLifePostalActionTypes, StoreFormLifeQuoteActionTypes, StoreClientActionTypes, StoreConfigAppDeviceActionTypes, StoreProvider, initHttpResponse } from '@mychoice/mychoice-sdk-store';
3
+ import { AppTypes, isMyChoiceLike, TitleForm, TooltipForm, IconDelete, ColorVariablesTypes, InputTypes, InputForm, InputFormPhone, InputFormEmail, InputFormLicence, SelectForm, getFormattedDate, DateTypes, getDateOptions, ButtonForm, defaultBrokerPhone, DriverPriorityTypes, SizeTypes, ButtonBase, CategoryTypes, ColorTypes, defaultLocalIndex, liabilityOptions, accidentBenefitsOptionalOptions, coverageOptions, lossOfUseOptions, liabilityForDamageOptions, limitedWaiverOfDepreciationOptions, OfferDetail, CompanyRoleTypes, OperationHoursInfo, OfferHeader, OfferPrice, ButtonTypes, ButtonVariantTypes, IconDropdownArrow, InsuranceTypes, HeaderNavGroup, ButtonMenu, DeviceTypes, IconLoaderPrimary, getInsuranceType, RequestStatusTypes, formatPostalCode, IconLoaderSecondary, postalCodeFormat, useEffectOnce, carCondition, carStatus, carWinterTiresCheck, carKeepPlace, carUsagePurpose, firstDriveDistanceList, yearlyDriveDistanceList, numberWithCommas, VehiclePrimaryUseTypes, businessUsePercentOptions, addDaysToDate, comprehensiveCoverage, collisionCoverage, maritalStatusOptions, subYearsFromDate, occupationOptions, genderOptions, applicantRelationshipOptions, addYearsToDate, checkDateIsSpecial, DriverLicenceTypes, getDifferenceInYears, compareDates, yesNoOptions, getLicenceTypeOptions, getDisabledLicenceTypes, getDifferenceInMonths, addMonthsToDate, getMinDate, getMinDateByYears, CheckboxForm, insuranceCancellationReasonOptions, subMonthsFromDate, DriverListTypes, licenceSuspensionsReasonOptions, trafficTicketsGroupOptions, ValidationStatusTypes, getPlaceholderEmail, QuoteEdit, homeOwnerTypeOptions, tenantBuildingStructureOptions, condoBuildingStructureOptions, homeBuildingStructureOptions, residentsOptions, insuredYearsOptions, getInsuranceYearsOptions, ApplicantListTypes, claimTypeOptions, exteriorFinishOptions, constructionTypeOptions, garageTypeOptions, getNumericOptions, fireHallDistanceOptions, fireHydrantDistanceOptions, primaryHeatingTypeOptions, auxHeatingTypeOptions, InfoMessage, ppOptions, homeCoverageOptions, homeLiabilityOptions, lifeInsuranceTypeOptions, lifeInsuranceOntarioTypeOptions, lifeCoverageOptions, smokerOptions, MychoiceStep, Step, IconClock, ButtonArrow, DirectionTypes, ButtonTabArrow, ButtonTab, ButtonTabMobile, NavigationCar, NavigationPerson, NavigationDiscount, NavigationQuotes, NavigationAddress, NavigationProperty, ModalTypes } from '@mychoice/mychoice-sdk-components';
4
+ import { useStoreAppConfig, useStoreFormCarVehicle, useStoreFormCarDriverBase, useStoreFormCarDiscount, StoreFormCarDiscountActionTypes, useStoreFormCarQuote, CarQuoteDataHandler, useValidationCarDiscount, StoreFormCarVehicleActionTypes, useStoreFormHomeDiscount, useStorePartner, useStoreDeviceType, useStoreAppLoader, useStoreAppModal, StoreConfigAppModalActionTypes, useHandlerPostal, useHandlerCarMake, useHandlerCarModel, useProvince, useAbReform, useValidationVehicle, useAutofillCarForm, StoreFormCarDriverBaseActionTypes, useStoreFormCarConfig, useStoreFormCarDriverInfo, StoreFormCarDriverInfoActionTypes, useStoreFormCarDriverLicence, addDayToDate, StoreFormCarDriverLicenceActionTypes, useStoreFormCarDriverInsurance, StoreFormCarDriverInsuranceActionTypes, useStoreFormCarDriverCancellation, StoreFormCarDriverCancellationActionTypes, useStoreFormCarDriverSuspension, StoreFormCarDriverSuspensionActionTypes, useStoreFormCarDriverAccident, StoreFormCarDriverAccidentActionTypes, useStoreFormCarDriverTicket, StoreFormCarDriverTicketActionTypes, useValidationDriver, useHandlerCarQuoterEmail, useHandlerCarQuoterPhone, useStoreFormHomeDwelling, useStoreFormHomePostal, useStoreFormHomeApplicantBase, StoreFormHomePostalActionTypes, StoreFormHomeDwellingActionTypes, StoreConfigAppConfigActionTypes, StoreFormHomeApplicantBaseActionTypes, useValidationAddress, useStoreFormHomeApplicantInfo, StoreFormHomeDiscountActionTypes, StoreFormHomeApplicantInfoActionTypes, useStoreFormHomeApplicantInsurance, StoreFormHomeApplicantInsuranceActionTypes, useStoreFormHomeApplicantCancellation, StoreFormHomeApplicantCancellationActionTypes, useStoreFormHomeApplicantClaim, StoreFormHomeApplicantClaimActionTypes, useValidationApplicant, useValidationDwelling, useStoreFormHomeQuote, HomeQuoteDataHandler, useValidationHomeDiscount, useHandlerHomeQuoterEmail, useHandlerHomeQuoterPhone, useStoreFormLifeCoverage, StoreFormLifeCoverageActionTypes, useValidationCoverage, useAutofillLifeForm, useStoreFormLifeQuote, useStoreFormLifeApplicant, LifeQuoteDataHandler, useValidationLifeApplicant, useHandlerLifeQuoterEmail, useHandlerLifeQuoterPhone, StoreFormLifeApplicantActionTypes, useStoreFormCarPostal, useStoreFormLifePostal, ClearFormDataHandler, useStoreAppDevice, useStoreClient, useHandlerAuth, useHandlerPartner, StoreConfigAppLoaderActionTypes, StoreFormCarConfigActionTypes, StoreFormCarPostalActionTypes, StoreFormCarQuoteActionTypes, StoreFormHomeQuoteActionTypes, StoreFormLifePostalActionTypes, StoreFormLifeQuoteActionTypes, StoreClientActionTypes, StoreConfigAppDeviceActionTypes, StoreProvider, initHttpResponse } from '@mychoice/mychoice-sdk-store';
5
5
  import { useNavigate, useLocation, BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
6
6
  import React, { useState, useCallback, useEffect, useRef, useMemo } from 'react';
7
7
  import { random } from 'lodash';
@@ -48,8 +48,8 @@ InputFormBox.defaultProps = {
48
48
  };
49
49
 
50
50
  const InputFormPhoneBox = (props) => {
51
- const { className, defaultValue, placeholder, disabled, error, name, title, onChange, errorMessage, hintMessage, } = props;
52
- return (jsx(Container, { name: name, className: ` ${className} ${error ? 'error' : ''}`, title: title, errorMessage: errorMessage, hintMessage: hintMessage, children: jsx(InputFormPhone, { className: "input-form", name: name, type: InputTypes.Text, defaultValue: defaultValue, onChange: onChange, placeholder: placeholder, disabled: disabled, error: error }) }));
51
+ const { className, defaultValue, placeholder, disabled, error, name, title, onChange, errorMessage, hintMessage, validationStatus, } = props;
52
+ return (jsx(Container, { name: name, className: ` ${className} ${error ? 'error' : ''}`, title: title, errorMessage: errorMessage, hintMessage: hintMessage, children: jsx(InputFormPhone, { className: "input-form", name: name, type: InputTypes.Text, defaultValue: defaultValue, onChange: onChange, placeholder: placeholder, disabled: disabled, error: error, validationStatus: validationStatus }) }));
53
53
  };
54
54
  InputFormPhoneBox.defaultProps = {
55
55
  className: '',
@@ -199,9 +199,11 @@ const capitalize = (text) => text.charAt(0).toUpperCase() + text.slice(1);
199
199
  const BlockVehLinks = () => {
200
200
  const { vehicleState: { items: vehicles } } = useStoreFormCarVehicle();
201
201
  const { driverState: { items: drivers } } = useStoreFormCarDriverBase();
202
- const { discountState: { vehlinks }, dispatchDiscountState } = useStoreFormCarDiscount();
203
- const driverOptions = drivers.map((driver, index) => ({ name: driver.firstName, value: index }));
204
- const handleDriverChange = (vehicleIndex) => ({ value }) => {
202
+ const { discountState: { vehlinks, occVehlinks }, dispatchDiscountState } = useStoreFormCarDiscount();
203
+ if (drivers.length <= 1) {
204
+ return null;
205
+ }
206
+ const handlePrimaryDriverChange = (vehicleIndex) => ({ value }) => {
205
207
  dispatchDiscountState({
206
208
  type: StoreFormCarDiscountActionTypes.FormCarDiscountVehlinkSelect,
207
209
  payload: {
@@ -210,14 +212,41 @@ const BlockVehLinks = () => {
210
212
  },
211
213
  });
212
214
  };
213
- if (drivers.length > 1) {
214
- return (jsxs(Fragment, { children: [jsx(LabelFormBox, { title: "Since there are multiple drivers in this quote,\n please tell us who drives which vehicle the most.\n Please provide an answer that best suits your situation." }), vehicles.map((vehicle, index) => {
215
- const { year, make, model } = vehicle;
216
- const selectedDriver = vehlinks.find((vehlink) => (vehlink.vehicleIndex === index && vehlink.priority === DriverPriorityTypes.Prn));
217
- return (jsx(SelectFormBox, { title: `Who is the principal driver of the ${year} ${make} ${model} ?`, onChange: handleDriverChange(index), options: driverOptions, defaultValue: selectedDriver?.driverIndex || 0, name: `vehlink-${index}` }, `vehlink-${index}`));
218
- })] }));
219
- }
220
- return null;
215
+ const handleOccDriverChange = (driverIndex) => ({ value }) => {
216
+ dispatchDiscountState({
217
+ type: StoreFormCarDiscountActionTypes.FormCarDiscountOccVehlinkSelect,
218
+ payload: {
219
+ driverIndex,
220
+ vehicleIndex: value,
221
+ },
222
+ });
223
+ };
224
+ // Drivers that are NOT assigned as primary for any vehicle
225
+ const primaryDriverIndices = vehlinks
226
+ .filter((l) => l.priority === DriverPriorityTypes.Prn)
227
+ .map((l) => l.driverIndex);
228
+ const unassignedDrivers = drivers
229
+ .map((driver, index) => ({ driver, index }))
230
+ .filter(({ index }) => !primaryDriverIndices.includes(index));
231
+ return (jsxs(Fragment, { children: [jsx(LabelFormBox, { title: "Since there are multiple drivers in this quote, please tell us who drives which vehicle the most. Please provide an answer that most accurately describes your situation." }), vehicles.map((vehicle, vehicleIndex) => {
232
+ const { year, make, model } = vehicle;
233
+ const selectedPrimary = vehlinks.find((l) => l.vehicleIndex === vehicleIndex && l.priority === DriverPriorityTypes.Prn);
234
+ const allDriverOptions = drivers
235
+ .map((driver, driverIndex) => ({ name: driver.firstName, value: driverIndex }));
236
+ const filteredOptions = allDriverOptions.filter(({ value }) => {
237
+ const assignedVehicle = vehlinks.find((l) => l.driverIndex === value && l.priority === DriverPriorityTypes.Prn);
238
+ return !assignedVehicle || assignedVehicle.vehicleIndex === vehicleIndex;
239
+ });
240
+ const availablePrimaryOptions = filteredOptions.length > 0 ? filteredOptions : allDriverOptions;
241
+ return (jsx(SelectFormBox, { title: `Who drives the ${year} ${make} ${model} the most?`, onChange: handlePrimaryDriverChange(vehicleIndex), options: availablePrimaryOptions, defaultValue: selectedPrimary?.driverIndex ?? 0, name: `vehlink-${vehicleIndex}` }, `vehlink-${vehicleIndex}`));
242
+ }), drivers.length > vehicles.length && unassignedDrivers.map(({ driver, index: driverIndex }) => {
243
+ const selectedVehicle = occVehlinks.find((l) => l.driverIndex === driverIndex);
244
+ const vehicleOptions = vehicles.map((vehicle, vehicleIndex) => ({
245
+ name: `${vehicle.year} ${vehicle.make} ${vehicle.model}`,
246
+ value: vehicleIndex,
247
+ }));
248
+ return (jsx(SelectFormBox, { title: `Which vehicle does ${driver.firstName} drive the most?`, onChange: handleOccDriverChange(driverIndex), options: vehicleOptions, defaultValue: selectedVehicle?.vehicleIndex ?? 0, name: `occ-vehlink-${driverIndex}` }, `occ-vehlink-${driverIndex}`));
249
+ })] }));
221
250
  };
222
251
 
223
252
  const BlockNextPageInfo$2 = () => {
@@ -670,14 +699,22 @@ const getRecommendedRange = (distanceDaily, distanceBusiness) => {
670
699
  kmEachDay = +distanceBusiness;
671
700
  }
672
701
  switch (true) {
702
+ case kmEachDay === 0:
703
+ return 5000;
673
704
  case kmEachDay === 1:
674
705
  return 8000;
675
- case ((kmEachDay >= 2) && (kmEachDay <= 10)):
706
+ case ((kmEachDay >= 2) && (kmEachDay <= 5)):
676
707
  return 10000;
677
- case ((kmEachDay >= 15) && (kmEachDay <= 20)):
708
+ case ((kmEachDay >= 6) && (kmEachDay <= 12)):
709
+ return 10000;
710
+ case ((kmEachDay >= 13) && (kmEachDay <= 20)):
678
711
  return 15000;
712
+ case ((kmEachDay >= 21) && (kmEachDay <= 29)):
713
+ return 20000;
679
714
  case ((kmEachDay >= 30) && (kmEachDay <= 40)):
680
715
  return 20000;
716
+ case ((kmEachDay >= 41) && (kmEachDay <= 49)):
717
+ return 30000;
681
718
  case ((kmEachDay >= 50) && (kmEachDay <= 80)):
682
719
  return 30000;
683
720
  case ((kmEachDay >= 90) && (kmEachDay <= 100)):
@@ -783,9 +820,9 @@ const BlockCarConditionInfo = () => {
783
820
  });
784
821
  }
785
822
  };
786
- const { year, condition, leased, winterTires, parkingLocation, primaryUse, distanceDaily, distanceBusiness, distanceYearly, purchaseYear, purchaseMonth, purchaseDay, } = vehicleState.items[vehicleState.activeIndex];
823
+ const { year, condition, leased, winterTires, parkingLocation, primaryUse, distanceDaily, distanceBusiness, distanceYearly, businessUsePercent, purchaseYear, purchaseMonth, purchaseDay, } = vehicleState.items[vehicleState.activeIndex];
787
824
  // eslint-disable-next-line max-len
788
- const primaryUseHintMessage = primaryUse === 'business' ? 'Please choose "Business" only if your vehicle is used primarily for work (sales representatives, realtors, consultants, etc.). If you drive back and forth to work or use your vehicle occasionally for work, please select "Personal".' : '';
825
+ const primaryUseHintMessage = primaryUse === 'business' ? 'Please choose "Business" if your vehicle is used for any work purposes (sales representatives, realtors, consultants, etc.). If you only drive back and forth to work, please choose "Personal" and select your commute distance.' : '';
789
826
  const defaultPurchaseDate = {
790
827
  day: purchaseDay,
791
828
  month: purchaseMonth,
@@ -846,33 +883,30 @@ const BlockCarConditionInfo = () => {
846
883
  type: StoreFormCarVehicleActionTypes.FormCarDailyDistanceSelect,
847
884
  payload: { distanceDaily: value },
848
885
  });
886
+ const yearlyDefault = `${getRecommendedRange(value, primaryUse === VehiclePrimaryUseTypes.Business ? distanceBusiness : 1)}`;
849
887
  dispatchVehicleState({
850
888
  type: StoreFormCarVehicleActionTypes.FormCarYearlyDistanceSelect,
851
- payload: { distanceYearly: `${getRecommendedRange(value, primaryUse === VehiclePrimaryUseTypes.Business ? distanceBusiness : 1)}` },
889
+ payload: { distanceYearly: yearlyDefault },
852
890
  });
853
891
  };
854
- const handleCarBusinessDailyDistanceChange = ({ value }) => {
855
- dispatchVehicleState({
856
- type: StoreFormCarVehicleActionTypes.FormCarBusinessDistanceSelect,
857
- payload: { distanceBusiness: value },
858
- });
892
+ const handleCarYearlyDistanceChange = ({ value }) => {
859
893
  dispatchVehicleState({
860
894
  type: StoreFormCarVehicleActionTypes.FormCarYearlyDistanceSelect,
861
- payload: { distanceYearly: `${getRecommendedRange(value, primaryUse === VehiclePrimaryUseTypes.Business ? distanceBusiness : 1)}` },
895
+ payload: { distanceYearly: value },
862
896
  });
863
897
  };
864
- const handleCarYearlyDistanceChange = ({ value }) => {
898
+ const handleBusinessUsePercentChange = ({ value }) => {
865
899
  dispatchVehicleState({
866
- type: StoreFormCarVehicleActionTypes.FormCarYearlyDistanceSelect,
867
- payload: { distanceYearly: value },
900
+ type: StoreFormCarVehicleActionTypes.FormCarBusinessUsePercentSelect,
901
+ payload: { businessUsePercent: value },
868
902
  });
869
903
  };
870
904
  return (jsxs(Fragment, { children: [jsx(SwitchButtonBox, { items: carCondition, onChange: handleConditionChange, name: "condition", defaultValue: getSelectedOption(carCondition, condition), description: "Used cars are usually cheaper to insure than new ones because of the depreciation. The cost to replace this vehicle is typically less expensive and insurers will account for the condition of the car when giving you a rate.", title: "Was this car new or used when you bought it?" }), jsx(SwitchButtonBox, { items: carStatus, onChange: handleLeasedChange, name: "leased", defaultValue: getSelectedOption(carStatus, leased), description: "You can own or lease a car. Ownership means that you bought the vehicle or are currently financing it. Leasing is renting it under a long-term contract. In this case, the leasing company maintains ownership of the vehicle, which you will see clearly on your insurance policy.", title: "Is this car owned/financed or leased?" }), jsx(DateSelectFormBox, { name: "purchaseDate", dateNames: ['purchaseYear', 'purchaseMonth'], onDateChange: handlePurchaseDateChange, defaultValue: defaultPurchaseDate, title: "When did you buy this car?", description: "Car insurers in Ontario ask for your vehicle purchase date because it is a key factor that can affect its value, depreciation, and condition, which can impact the likelihood and cost of repairs or replacement. This information helps insurers assess the level of risk and calculate an appropriate premium.", errorMessage: getDateErrorMessage([
871
905
  purchaseDay || '',
872
906
  purchaseMonth || '',
873
907
  purchaseYear || '',
874
- ], vehicleState.inValidation), error: vehicleState.inValidation, minDate: year ? `${Number(year) - 1}-01-01` : getFormattedDate('', 'yyyy-MM-dd'), maxDate: getFormattedDate('', 'yyyy-MM-dd') }), !(isAlbertaProvince && isTheBig) && (jsx(SwitchButtonBox, { items: carWinterTiresCheck, onChange: handleWinterTiresChange, name: "winterTires", defaultValue: getSelectedOption(carWinterTiresCheck, winterTires), description: "Snow. Ice. Freezing temperatures. Winter tires protect you from all these winter weather conditions, and more. It also protects your wallet. Investing in winter tires can save you $50 to $100 on your insurance.", title: "Does your car have winter tires?" })), jsx(SelectFormBox, { options: carKeepPlace, name: "parkingLocation", onChange: handleCarParkingLocationChange, defaultValue: getSelectedOption(carKeepPlace, parkingLocation), title: "Where do you keep your car overnight?", placeholder: "Select from the list", description: "For many of us, the answer is \u201Cat home.\u201D If you park your car in various locations throughout the year, then select the most frequently parking spot. Be honest\u2014some insurers will use your overnight parking location to calculate a quote, which could affect your claims in the future.", autoSelectIfValueIsOutOfOptions: false, error: !parkingLocation && vehicleState.inValidation, errorMessage: getErrorMessage(parkingLocation, vehicleState.inValidation) }), jsx(SwitchButtonBox, { items: carUsagePurpose, onChange: handleCarUsageChange, name: "primaryUse", defaultValue: getSelectedOption(carUsagePurpose, primaryUse) || carUsagePurpose[0].value, hintMessage: primaryUseHintMessage, description: "The way you use your vehicle is a primary factor that insurers use in your policy terms and fees, whether it be personal or business.\n \u2022 Personal is driving from work or school to home.\n \u2022 Business considers other uses like sales calls, pick-ups or deliveries, or other business errands.", title: "What do you mainly use your car for?" }), jsx(SelectFormBox, { options: firstDriveDistanceList, name: "distanceDaily", onChange: handleCarDailyDistanceChange, defaultValue: getSelectedOption(firstDriveDistanceList, distanceDaily), title: "How far is your 1-way commute to work or school?", placeholder: "Select", description: "The distance you drive to work or school would be an example of your daily commute. It is one of the most important factors when determining coverage options since it exposes you to traffic each day. The shorter your commute, the less risk you carry of an accident.", autoSelectIfValueIsOutOfOptions: false, error: !distanceDaily && vehicleState.inValidation, errorMessage: getErrorMessage(distanceDaily, vehicleState.inValidation) }), primaryUse === 'business' && (jsx(SelectFormBox, { options: dailyDriveBusinessDistanceList, name: "distanceBusiness", onChange: handleCarBusinessDailyDistanceChange, defaultValue: getSelectedOption(dailyDriveBusinessDistanceList, distanceBusiness), title: "How many kilometers are driven for business use each day?", placeholder: "Select", autoSelectIfValueIsOutOfOptions: false, error: !distanceBusiness && vehicleState.inValidation, errorMessage: getErrorMessage(distanceBusiness, vehicleState.inValidation) })), jsx(SelectFormBox, { options: yearlyDriveDistanceList, name: "distanceYearly", onChange: handleCarYearlyDistanceChange, defaultValue: getSelectedOption(yearlyDriveDistanceList, distanceYearly), title: "How many total kilometers are driven each year?", placeholder: "Select", hintMessage: distanceDaily ? `Based on your daily driven kilometers, we recommend
875
- ${numberWithCommas(getRecommendedRange(distanceDaily, primaryUse === VehiclePrimaryUseTypes.Business ? distanceBusiness : 1))} for your yearly driven kilometers` : '', autoSelectIfValueIsOutOfOptions: false, error: !distanceYearly && vehicleState.inValidation, errorMessage: getErrorMessage(distanceYearly, vehicleState.inValidation) }), showPolicyStartOnVehiclePage && (jsx(DateSelectFormBox, { name: "policyStart", dateNames: ['policyStartYear', 'policyStartMonth', 'policyStartDay'], onDateChange: handlePolicyStartDateChange, defaultValue: defaultPolicyStartDate, title: "What is the ideal start date for your new insurance policy?", description: "Select your preferred date for the beginning of your new insurance policy. For instance, you may set the start date for the day that your current insurance expires to ensure that you're continuously covered. Alternatively, select today's date for a quote or new policy.", minDate: addDaysToDate('', 1), maxDate: addDaysToDate('', 90), isDay: true }))] }));
908
+ ], vehicleState.inValidation), error: vehicleState.inValidation, minDate: year ? `${Number(year) - 1}-01-01` : getFormattedDate('', 'yyyy-MM-dd'), maxDate: getFormattedDate('', 'yyyy-MM-dd') }), !(isAlbertaProvince && isTheBig) && (jsx(SwitchButtonBox, { items: carWinterTiresCheck, onChange: handleWinterTiresChange, name: "winterTires", defaultValue: getSelectedOption(carWinterTiresCheck, winterTires), description: "Snow. Ice. Freezing temperatures. Winter tires protect you from all these winter weather conditions, and more. It also protects your wallet. Investing in winter tires can save you $50 to $100 on your insurance.", title: "Does your car have winter tires?" })), jsx(SelectFormBox, { options: carKeepPlace, name: "parkingLocation", onChange: handleCarParkingLocationChange, defaultValue: getSelectedOption(carKeepPlace, parkingLocation), title: "Where do you keep your car overnight?", placeholder: "Select from the list", description: "For many of us, the answer is \u201Cat home.\u201D If you park your car in various locations throughout the year, then select the most frequently parking spot. Be honest\u2014some insurers will use your overnight parking location to calculate a quote, which could affect your claims in the future.", autoSelectIfValueIsOutOfOptions: false, error: !parkingLocation && vehicleState.inValidation, errorMessage: getErrorMessage(parkingLocation, vehicleState.inValidation) }), jsx(SwitchButtonBox, { items: carUsagePurpose, onChange: handleCarUsageChange, name: "primaryUse", defaultValue: getSelectedOption(carUsagePurpose, primaryUse) || carUsagePurpose[0].value, hintMessage: primaryUseHintMessage, description: "The way you use your vehicle is a primary factor that insurers use in your policy terms and fees, whether it be personal or business.\n \u2022 Personal is driving from work or school to home.\n \u2022 Business considers other uses like sales calls, pick-ups or deliveries, or other business errands.", title: "What do you use your car for?" }), jsx(SelectFormBox, { options: firstDriveDistanceList, name: "distanceDaily", onChange: handleCarDailyDistanceChange, defaultValue: getSelectedOption(firstDriveDistanceList, distanceDaily), title: "How far is your 1-way commute to work or school?", placeholder: "Select", description: "The distance you drive to work or school would be an example of your daily commute. It is one of the most important factors when determining coverage options since it exposes you to traffic each day. The shorter your commute, the less risk you carry of an accident.", autoSelectIfValueIsOutOfOptions: false, error: distanceDaily === undefined && vehicleState.inValidation, errorMessage: getErrorMessage(distanceDaily, vehicleState.inValidation) }), jsx(SelectFormBox, { options: yearlyDriveDistanceList, name: "distanceYearly", onChange: handleCarYearlyDistanceChange, defaultValue: getSelectedOption(yearlyDriveDistanceList, distanceYearly), title: "How many total kilometers are driven each year?", placeholder: "Select", hintMessage: distanceDaily !== undefined ? `Based on your daily driven kilometers, we recommend
909
+ ${numberWithCommas(getRecommendedRange(distanceDaily, primaryUse === VehiclePrimaryUseTypes.Business ? distanceBusiness : 1))} for your yearly driven kilometers` : '', autoSelectIfValueIsOutOfOptions: false, error: !distanceYearly && vehicleState.inValidation, errorMessage: getErrorMessage(distanceYearly, vehicleState.inValidation) }), primaryUse === 'business' && (jsx(SelectFormBox, { options: businessUsePercentOptions, name: "businessUsePercent", onChange: handleBusinessUsePercentChange, defaultValue: getSelectedOption(businessUsePercentOptions, businessUsePercent), title: "What percentage of your total kilometers are driven for business purposes?", placeholder: "Select", autoSelectIfValueIsOutOfOptions: false, error: !businessUsePercent && vehicleState.inValidation, errorMessage: getErrorMessage(businessUsePercent, vehicleState.inValidation) })), showPolicyStartOnVehiclePage && (jsx(DateSelectFormBox, { name: "policyStart", dateNames: ['policyStartYear', 'policyStartMonth', 'policyStartDay'], onDateChange: handlePolicyStartDateChange, defaultValue: defaultPolicyStartDate, title: "What is the ideal start date for your new insurance policy?", description: "Select your preferred date for the beginning of your new insurance policy. For instance, you may set the start date for the day that your current insurance expires to ensure that you're continuously covered. Alternatively, select today's date for a quote or new policy.", minDate: addDaysToDate('', 1), maxDate: addDaysToDate('', 90), isDay: true }))] }));
876
910
  };
877
911
 
878
912
  const VehicleSectionMain = () => {
@@ -1201,96 +1235,174 @@ const SectionDriverInfo = () => {
1201
1235
  return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [mychoiceCls && jsx("h2", { className: "section-title", children: "Time for a micro autobiography \u2013 tell us about you." }), jsx(InputFormBox, { name: "firstName", title: "What is your legal first name?", onChange: handleFirstNameChange, defaultValue: firstName, description: "The name on a policy should match the one on your official driver\u2019s licence.", placeholder: "Driver First Name", error: !firstName && driverState.inValidation, errorMessage: getErrorMessage(firstName, driverState.inValidation) }), jsx(SelectFormBox, { options: maritalStatusOptions, name: "maritalStatus", onChange: handleMaritalStatusChange, defaultValue: getSelectedOption(maritalStatusOptions, maritalStatus), title: "What is your marital status?", placeholder: "Select from the list", description: "If you are married, it may have a positive effect on your car insurance premiums and coverage. In some provinces, the law now considers same-sex partners to have a common-law marriage, so you will need to check your local regulations. If you are divorced or widowed, select single.", autoSelectIfValueIsOutOfOptions: false, error: !maritalStatus && driverState.inValidation, errorMessage: getErrorMessage(maritalStatus, driverState.inValidation) }), jsx(DateSelectFormBox, { name: "dateOfBirth", dateNames: ['birthYear', 'birthMonth', 'birthDay'], onDateChange: handleDateOfBirthChange, defaultValue: defaultDateOfBirth, title: "When were you born?", description: "Insurers generally consider your age and driving experience when calculating a vehicle insurance quote. The safest drivers are often those who are over thirty, but each insurer will have their own parameters. The youngest and oldest drivers have the greatest liability reflected in their premiums due to inexperience or health complications, respectively.", errorMessage: getDateErrorMessage([birthDay || '', birthMonth || '', birthYear || ''], driverState.inValidation), error: driverState.inValidation, maxDate: subYearsFromDate('', configState.licenceConfig.minLicenceAge || 16), isDay: true }), jsx(SwitchButtonBox, { name: "occupation", items: occupationOptions, onChange: handleOccupationChange, defaultValue: getSelectedOption(occupationOptions, occupation), title: "Are you currently employed or unemployed?", description: "Your employment status reflects your driving frequency, and insurers consider this in your policy." }), jsx(SwitchButtonBox, { items: genderOptions, onChange: handleGenderChange, name: "gender", defaultValue: getSelectedOption(genderOptions, gender), title: "What is your gender?", description: "The gender on the policy should match your official driver\u2019s licence. Some insurers analyze a driver's sex when creating a policy. Men are typically considered higher risk than female drivers, but the statistics supporting this idea vary from province to province. On average, men and women pay roughly the same for insurance, though." }), driverState.activeIndex > 0 && (jsx(SelectFormBox, { options: applicantRelationshipOptions, name: "applicantRelationship", onChange: handleApplicantRelationshipChange, defaultValue: getSelectedOption(applicantRelationshipOptions, applicantRelationship), title: "Relationship to applicant", placeholder: "Select...", autoSelectIfValueIsOutOfOptions: false, error: !applicantRelationship && driverState.inValidation, errorMessage: getErrorMessage(applicantRelationship, driverState.inValidation) }))] }));
1202
1236
  };
1203
1237
 
1238
+ // Max months between consecutive Ontario GDL licence classes (spec 1-2 e/f)
1239
+ const ON_MAX_MONTHS_BETWEEN_CLASSES = 60;
1204
1240
  const SectionDriverLicence = () => {
1205
1241
  const { appConfigState: { appType }, } = useStoreAppConfig();
1206
1242
  const [driverEducation, setDriverEducation] = useState(false);
1207
1243
  const { configState } = useStoreFormCarConfig();
1208
1244
  const { driverState, dispatchDriverLicenceState } = useStoreFormCarDriverLicence();
1209
- const { isAlbertaProvince } = useProvince();
1245
+ const { isAlbertaProvince, isOntarioProvince } = useProvince();
1210
1246
  const mychoiceCls = isMyChoiceLike(appType) ? 'mychoice' : '';
1211
- const { firstName, birthDay, birthMonth, birthYear, licenceInfo: { firstLicenceAge, licenceType, g1LicenceYear, g1LicenceMonth, gLicenceYear, gLicenceMonth, g2LicenceYear, g2LicenceMonth, passedDriverTraining, previousLicence, }, minMaxDates, } = driverState.items[driverState.activeIndex];
1247
+ const isTheBig = appType === AppTypes.TheBig;
1248
+ // Ontario flow applies only for MyChoice-like (WL/MC) quoters, not TheBig
1249
+ const useOntarioFlow = isOntarioProvince && !isTheBig;
1250
+ const { firstName, birthDay, birthMonth, birthYear, licenceInfo: { firstLicenceAge, licenceType, g1LicenceYear, g1LicenceMonth, gLicenceYear, gLicenceMonth, g2LicenceYear, g2LicenceMonth, passedDriverTraining, previousLicence, receivedG2, receivedG, }, minMaxDates, } = driverState.items[driverState.activeIndex];
1212
1251
  const { gMax = getFormattedDate('', 'yyyy-MM-dd'), gMin = '1922-01-01', gOneMax = getFormattedDate('', 'yyyy-MM-dd'), gOneMin = '1922-01-01', gTwoMax = getFormattedDate('', 'yyyy-MM-dd'), gTwoMin = '1922-01-01', gBlock = false, gTwoBlock = false, gOneBlock = false, licenceAgeMax = 16, } = minMaxDates ?? {};
1213
1252
  const maxLicenceAge = licenceAgeMax;
1214
1253
  const driverNameDefault = `Driver ${driverState.activeIndex + 1}`;
1215
1254
  const birthDate = birthYear && birthMonth && birthDay ? `${birthYear}-${birthMonth}-${birthDay}` : '';
1216
1255
  const defaultMinDate = birthDate && firstLicenceAge ? addYearsToDate(birthDate, +firstLicenceAge) : '';
1217
- const isOnlyG = checkDateIsSpecial(defaultMinDate, configState.minDates.g.specialDate);
1218
- const isTheBig = appType === AppTypes.TheBig;
1256
+ const getOntarioQ1YearMonth = () => {
1257
+ if (licenceType === DriverLicenceTypes.G2)
1258
+ return { year: g2LicenceYear, month: g2LicenceMonth };
1259
+ if (licenceType === DriverLicenceTypes.G)
1260
+ return { year: gLicenceYear, month: gLicenceMonth };
1261
+ return { year: g1LicenceYear, month: g1LicenceMonth };
1262
+ };
1263
+ const { year: ontarioQ1Year, month: ontarioQ1Month } = getOntarioQ1YearMonth();
1264
+ const ontarioQ1Date = ontarioQ1Year && ontarioQ1Month ? `${ontarioQ1Year}-${ontarioQ1Month}-01` : '';
1265
+ const isOnlyG = useOntarioFlow
1266
+ ? (!!ontarioQ1Date && checkDateIsSpecial(ontarioQ1Date, configState.minDates.g.specialDate))
1267
+ : checkDateIsSpecial(defaultMinDate, configState.minDates.g.specialDate);
1268
+ const driverName = firstName || driverNameDefault;
1269
+ const today = getFormattedDate('', 'yyyy-MM-dd');
1219
1270
  const { g, g1, g2, minLicenceAge } = configState.licenceConfig;
1220
1271
  const licenceTypeOptions = [
1221
1272
  { value: g.name, name: g.title },
1222
1273
  { value: g1.name, name: g1.title },
1223
1274
  { value: g2.name, name: g2.title },
1224
1275
  ];
1276
+ // Ontario class dropdown options
1277
+ const ontarioFirstClassOptions = [
1278
+ { value: DriverLicenceTypes.G1, name: 'G1 Beginner' },
1279
+ { value: DriverLicenceTypes.G2, name: 'G2 Intermediate' },
1280
+ { value: DriverLicenceTypes.G, name: 'G Full or equivalent' },
1281
+ ];
1282
+ // Ontario "before 1994" — only G available, shown as disabled single option
1283
+ const ontarioOnlyGOptions = [
1284
+ { value: DriverLicenceTypes.G, name: 'G Full or equivalent' },
1285
+ ];
1286
+ // Legacy non-Ontario education effect
1225
1287
  useEffect(() => {
1226
- if (!gOneBlock && !gTwoBlock) {
1227
- if (licenceType !== DriverLicenceTypes.G1) {
1228
- const g2Date = addDayToDate(`${g2LicenceYear}-${g2LicenceMonth}`, birthDay ? +birthDay + 1 : 1);
1229
- if (getDifferenceInYears('', g2Date) <= 3) {
1230
- setDriverEducation(true);
1288
+ if (!useOntarioFlow) {
1289
+ if (!gOneBlock && !gTwoBlock) {
1290
+ if (licenceType !== DriverLicenceTypes.G1) {
1291
+ const g2Date = addDayToDate(`${g2LicenceYear}-${g2LicenceMonth}`, birthDay ? +birthDay + 1 : 1);
1292
+ if (getDifferenceInYears('', g2Date) <= 3) {
1293
+ setDriverEducation(true);
1294
+ }
1295
+ else {
1296
+ setDriverEducation(false);
1297
+ }
1231
1298
  }
1232
1299
  else {
1233
1300
  setDriverEducation(false);
1234
1301
  }
1235
1302
  }
1236
- else {
1237
- setDriverEducation(false);
1238
- }
1239
1303
  }
1240
- }, [g2LicenceYear, g2LicenceMonth, licenceType]);
1304
+ }, [g2LicenceYear, g2LicenceMonth, licenceType, useOntarioFlow]);
1305
+ // If the user picks their birth month in their 16th year and birthDay > 1,
1306
+ // selecting that month would imply a date before their actual birthday (since dates are assumed
1307
+ // as the 1st). Auto-advance the Q1 month to birthMonth + 1.
1308
+ useEffect(() => {
1309
+ if (!useOntarioFlow || !birthDate || !ontarioQ1Year || !ontarioQ1Month)
1310
+ return;
1311
+ const birthDayNum = parseInt(birthDay || '1', 10);
1312
+ if (birthDayNum <= 1)
1313
+ return;
1314
+ const birthYearNum = parseInt(birthYear || '0', 10);
1315
+ if (parseInt(ontarioQ1Year, 10) !== birthYearNum + 16 || ontarioQ1Month !== birthMonth)
1316
+ return;
1317
+ const q1SlotForCorrection = licenceType || DriverLicenceTypes.G1;
1318
+ let correctedMonth = parseInt(birthMonth || '1', 10) + 1;
1319
+ let correctedYear = birthYearNum + 16;
1320
+ if (correctedMonth > 12) {
1321
+ correctedMonth = 1;
1322
+ correctedYear += 1;
1323
+ }
1324
+ dispatchDriverLicenceState({
1325
+ type: StoreFormCarDriverLicenceActionTypes.FormCarDriverLicenceMonthSelect,
1326
+ payload: { value: String(correctedMonth).padStart(2, '0'), config: configState, type: q1SlotForCorrection },
1327
+ });
1328
+ if (correctedYear !== birthYearNum + 16) {
1329
+ dispatchDriverLicenceState({
1330
+ type: StoreFormCarDriverLicenceActionTypes.FormCarDriverLicenceYearSelect,
1331
+ payload: { value: String(correctedYear), config: configState, type: q1SlotForCorrection },
1332
+ });
1333
+ }
1334
+ }, [ontarioQ1Year, ontarioQ1Month]);
1335
+ // ── helpers ────────────────────────────────────────────────
1241
1336
  const getMinDate = (type) => {
1242
1337
  switch (type) {
1243
- case DriverLicenceTypes.G:
1244
- return gMin;
1245
- case DriverLicenceTypes.G1:
1246
- return gOneMin;
1247
- case DriverLicenceTypes.G2:
1248
- return gTwoMin;
1249
- default:
1250
- return '';
1338
+ case DriverLicenceTypes.G: return gMin;
1339
+ case DriverLicenceTypes.G1: return gOneMin;
1340
+ case DriverLicenceTypes.G2: return gTwoMin;
1341
+ default: return '';
1251
1342
  }
1252
1343
  };
1253
1344
  const getMaxDate = (type) => {
1254
1345
  switch (type) {
1255
- case DriverLicenceTypes.G:
1256
- return gMax;
1257
- case DriverLicenceTypes.G1:
1258
- return gOneMax;
1259
- case DriverLicenceTypes.G2:
1260
- return gTwoMax;
1261
- default:
1262
- return '';
1346
+ case DriverLicenceTypes.G: return gMax;
1347
+ case DriverLicenceTypes.G1: return gOneMax;
1348
+ case DriverLicenceTypes.G2: return gTwoMax;
1349
+ default: return '';
1263
1350
  }
1264
1351
  };
1265
1352
  const getLicenceYear = (type) => {
1266
1353
  switch (type) {
1267
- case DriverLicenceTypes.G:
1268
- return gLicenceYear;
1269
- case DriverLicenceTypes.G1:
1270
- return g1LicenceYear;
1271
- case DriverLicenceTypes.G2:
1272
- return g2LicenceYear;
1273
- default:
1274
- return '';
1354
+ case DriverLicenceTypes.G: return gLicenceYear;
1355
+ case DriverLicenceTypes.G1: return g1LicenceYear;
1356
+ case DriverLicenceTypes.G2: return g2LicenceYear;
1357
+ default: return '';
1275
1358
  }
1276
1359
  };
1277
1360
  const getLicenceMonth = (type) => {
1278
1361
  switch (type) {
1279
- case DriverLicenceTypes.G:
1280
- return gLicenceMonth;
1281
- case DriverLicenceTypes.G1:
1282
- return g1LicenceMonth;
1283
- case DriverLicenceTypes.G2:
1284
- return g2LicenceMonth;
1285
- default:
1286
- return '';
1362
+ case DriverLicenceTypes.G: return gLicenceMonth;
1363
+ case DriverLicenceTypes.G1: return g1LicenceMonth;
1364
+ case DriverLicenceTypes.G2: return g2LicenceMonth;
1365
+ default: return '';
1287
1366
  }
1288
1367
  };
1289
1368
  const getDefaultLicenceDate = (type) => ({
1290
1369
  year: getLicenceYear(type),
1291
1370
  month: getLicenceMonth(type),
1292
- day: birthDay || '01',
1371
+ day: '01',
1293
1372
  });
1373
+ // Build a YYYY-MM-01 string from stored year/month, returns '' if either missing
1374
+ const toDate = (year, month) => (year && month ? `${year}-${month}-01` : '');
1375
+ const validateLicenceDate = (year, month, minDate) => {
1376
+ const dateStr = toDate(year, month);
1377
+ if (!dateStr)
1378
+ return '';
1379
+ if (compareDates(dateStr, today) > 0)
1380
+ return 'License dates cannot be in the future';
1381
+ if (minDate && compareDates(dateStr, minDate) < 0) {
1382
+ return 'This license date must be equal or later than the prior license date. Please check your selection';
1383
+ }
1384
+ return '';
1385
+ };
1386
+ const validate60Months = (earlierYear, earlierMonth, laterYear, laterMonth) => {
1387
+ const earlier = toDate(earlierYear, earlierMonth);
1388
+ const later = toDate(laterYear, laterMonth);
1389
+ if (!earlier || !later)
1390
+ return '';
1391
+ const months = getDifferenceInMonths(later, earlier);
1392
+ if (months > ON_MAX_MONTHS_BETWEEN_CLASSES) {
1393
+ return "Ontario's graduated license program must be completed within 5 years. Please check your selection";
1394
+ }
1395
+ return '';
1396
+ };
1397
+ // In the Ontario flow, firstLicenceAge is never entered, so gOneMin is stale/empty.
1398
+ // Compute min from DOB + 16, capped to today so minDate never exceeds maxDate.
1399
+ const getG1MinDate = () => {
1400
+ if (useOntarioFlow && birthDate) {
1401
+ const computed = addYearsToDate(birthDate, 16);
1402
+ return compareDates(computed, today) > 0 ? today : computed;
1403
+ }
1404
+ return gOneMin;
1405
+ };
1294
1406
  const handleLicenceAgeChange = ({ value }) => {
1295
1407
  dispatchDriverLicenceState({
1296
1408
  type: StoreFormCarDriverLicenceActionTypes.FormCarDriverLicenceAgeSelect,
@@ -1315,6 +1427,18 @@ const SectionDriverLicence = () => {
1315
1427
  payload: { previousLicence: value },
1316
1428
  });
1317
1429
  };
1430
+ const handleReceivedG2Change = ({ value }) => {
1431
+ dispatchDriverLicenceState({
1432
+ type: StoreFormCarDriverLicenceActionTypes.FormCarDriverReceivedG2Select,
1433
+ payload: { receivedG2: value },
1434
+ });
1435
+ };
1436
+ const handleReceivedGChange = ({ value }) => {
1437
+ dispatchDriverLicenceState({
1438
+ type: StoreFormCarDriverLicenceActionTypes.FormCarDriverReceivedGSelect,
1439
+ payload: { receivedG: value },
1440
+ });
1441
+ };
1318
1442
  const handleLicenceDateChange = (type) => (dateType) => ({ value }) => {
1319
1443
  if (dateType === DateTypes.Month) {
1320
1444
  dispatchDriverLicenceState({
@@ -1334,23 +1458,86 @@ const SectionDriverLicence = () => {
1334
1458
  const licenceMinDate = getMinDate(currentType);
1335
1459
  const licenceTypeTitle = configState.licenceConfig[currentType].title;
1336
1460
  const formattedMinDate = `${getFormattedDate(licenceMinDate, 'MMMM yyyy')}`;
1337
- const defaultHintMessage = `${formattedMinDate} would be your earliest ${licenceTypeTitle}
1338
- licence date based on your first licenced age and date of birth`;
1461
+ const defaultHintMessage = `${formattedMinDate} would be your earliest ${licenceTypeTitle} licence date based on your first licenced age and date of birth`;
1339
1462
  return currentType === DriverLicenceTypes.G2
1340
- ? `${defaultHintMessage}
1341
- if you completed a driver education course`
1463
+ ? `${defaultHintMessage} if you completed a driver education course`
1342
1464
  : defaultHintMessage;
1343
1465
  };
1344
1466
  const getLicenceAgeTitle = () => {
1345
- if (isAlbertaProvince && isTheBig) {
1467
+ if (isAlbertaProvince && isTheBig)
1346
1468
  return 'At what age was Class 5 GDL or Class 5 obtained?';
1347
- }
1348
- return `What age was ${firstName || driverNameDefault} when first licenced?`;
1349
- };
1469
+ return `What age was ${driverName} when first licenced?`;
1470
+ };
1471
+ if (useOntarioFlow) {
1472
+ // When isOnlyG (before Apr 1994), treat as G Full regardless of what licenceType is in the store
1473
+ const firstClass = isOnlyG ? DriverLicenceTypes.G : licenceType;
1474
+ // Q1 date lives in whichever slot the store wrote to (always ${licenceType}LicenceYear/Month).
1475
+ const q1SlotType = licenceType || DriverLicenceTypes.G1;
1476
+ const q1Year = getLicenceYear(q1SlotType);
1477
+ const q1Month = getLicenceMonth(q1SlotType);
1478
+ const q1Date = toDate(q1Year, q1Month);
1479
+ // ── path booleans ──
1480
+ const showG2Date = firstClass === DriverLicenceTypes.G1 && receivedG2 === true;
1481
+ // G question shows after G2 date entered (G1→G2 path) OR after No-G2 answer (G1→No G2 path)
1482
+ const showGQuestionAfterG1 = firstClass === DriverLicenceTypes.G1
1483
+ && (receivedG2 === false || showG2Date);
1484
+ const showGDateAfterG1 = showGQuestionAfterG1 && receivedG === true;
1485
+ const showGDateAfterG2 = firstClass === DriverLicenceTypes.G2 && receivedG === true;
1486
+ const g2Date = toDate(g2LicenceYear, g2LicenceMonth);
1487
+ const gDate = toDate(gLicenceYear, gLicenceMonth);
1488
+ // G1 branch: ask once, based on the first licence date. Show/hide uses 5-year gate; question text says "3 years".
1489
+ const showDtcG1Only = firstClass === DriverLicenceTypes.G1
1490
+ && !!q1Date
1491
+ && getDifferenceInYears('', q1Date) <= 5
1492
+ && !showG2Date;
1493
+ // Branch B: DTC shown as soon as class=G2 and Q1 is within 5 years (before G question)
1494
+ const showDtcG2Only = firstClass === DriverLicenceTypes.G2
1495
+ && !!q1Date
1496
+ && getDifferenceInYears('', q1Date) <= 5;
1497
+ // Branch C G Full: within 5 years of Q1 (G date)
1498
+ const showDtcGFull = firstClass === DriverLicenceTypes.G
1499
+ && !!q1Date
1500
+ && getDifferenceInYears('', q1Date) <= 5;
1501
+ // ── Validation error messages ──
1502
+ const q1MinDate = getG1MinDate();
1503
+ const q1ChronoError = driverState.inValidation
1504
+ ? validateLicenceDate(q1Year, q1Month, q1MinDate)
1505
+ : '';
1506
+ const q1FutureError = q1Date && compareDates(q1Date, today) > 0
1507
+ ? 'License dates cannot be in the future' : '';
1508
+ const q1Error = q1FutureError || q1ChronoError || getDateErrorMessage(['01', q1Month, q1Year], driverState.inValidation);
1509
+ const g2ChronoError = driverState.inValidation
1510
+ ? validateLicenceDate(g2LicenceYear, g2LicenceMonth, q1Date)
1511
+ : '';
1512
+ const g260MonthError = validate60Months(q1Year, q1Month, g2LicenceYear, g2LicenceMonth);
1513
+ const g2FutureError = g2Date && compareDates(g2Date, today) > 0 ? 'License dates cannot be in the future' : '';
1514
+ const g2Error = g2FutureError || g260MonthError || g2ChronoError || getDateErrorMessage(['01', g2LicenceMonth, g2LicenceYear], driverState.inValidation);
1515
+ // G preceding date: G2 date if on G1→G2→G path, else Q1 date
1516
+ const gPrecedingDate = showGDateAfterG1 && showG2Date ? g2Date : q1Date;
1517
+ const gChronoError = driverState.inValidation
1518
+ ? validateLicenceDate(gLicenceYear, gLicenceMonth, gPrecedingDate)
1519
+ : '';
1520
+ const g60MonthError = validate60Months(q1Year, q1Month, gLicenceYear, gLicenceMonth);
1521
+ const gFutureError = gDate && compareDates(gDate, today) > 0 ? 'License dates cannot be in the future' : '';
1522
+ const gError = gFutureError || g60MonthError || gChronoError || getDateErrorMessage(['01', gLicenceMonth, gLicenceYear], driverState.inValidation);
1523
+ // ── Min dates (always capped to today so minDate never exceeds maxDate) ──
1524
+ const g2MinRaw = q1Date && compareDates(q1Date, gTwoMin) > 0 ? q1Date : gTwoMin;
1525
+ const g2MinDate = compareDates(g2MinRaw, today) > 0 ? today : g2MinRaw;
1526
+ const gMinRaw = gPrecedingDate && compareDates(gPrecedingDate, gMin) > 0 ? gPrecedingDate : gMin;
1527
+ const gMinDate = compareDates(gMinRaw, today) > 0 ? today : gMinRaw;
1528
+ const getMax60Date = (refDate) => {
1529
+ if (!refDate)
1530
+ return today;
1531
+ const max60 = addMonthsToDate(refDate, ON_MAX_MONTHS_BETWEEN_CLASSES);
1532
+ return compareDates(today, max60) > 0 ? max60 : today;
1533
+ };
1534
+ const g2MaxDate = getMax60Date(q1Date);
1535
+ const gMaxDate = getMax60Date(q1Date);
1536
+ return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [jsx(DateSelectFormBox, { name: "firstLicenceDate", dateNames: ['firstLicenceYear', 'firstLicenceMonth'], onDateChange: handleLicenceDateChange(q1SlotType), defaultValue: getDefaultLicenceDate(q1SlotType), title: `When did ${driverName} first receive their drivers license in Canada?`, description: "Select the year and month in which you received your first license to drive an automobile in Canada. This would include a beginners, intermediate or full license.", errorMessage: q1Error, error: driverState.inValidation, minDate: q1MinDate, maxDate: today, disabled: !birthDate }), q1Date && (jsx(SelectFormBox, { options: isOnlyG ? ontarioOnlyGOptions : ontarioFirstClassOptions, name: "firstLicenceClass", onChange: handleLicenceTypeChange, defaultValue: getSelectedOption(isOnlyG ? ontarioOnlyGOptions : ontarioFirstClassOptions, licenceType), title: "What class of license was it?", placeholder: "Select from the list", disabled: isOnlyG, description: "Drivers licensed in Ontario under the graduated licensing program would select G1 Beginner. If the driver was licensed outside Ontario or granted an exception for having driving experience from another jurisdiction then select the license class they first received. Select class G Full or equivalent if the driver was licensed in Ontario before 1994 or was licensed in another province. G equivalent classes in Canada are class 5.", autoSelectIfValueIsOutOfOptions: false })), firstClass === DriverLicenceTypes.G1 && (jsxs(Fragment, { children: [showDtcG1Only && (jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleTrainingChange, name: "passedDriverTraining", defaultValue: getSelectedOption(yesNoOptions, passedDriverTraining), title: `Has ${driverName} completed a gov't approved drivers education course within the past 3 years?` })), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleReceivedG2Change, name: "receivedG2", defaultValue: getSelectedOption(yesNoOptions, receivedG2), title: `Did ${driverName} receive a G2 license?` }), showG2Date && (jsx(DateSelectFormBox, { name: "g2LicenceDate", dateNames: ['g2LicenceYear', 'g2LicenceMonth'], onDateChange: handleLicenceDateChange(DriverLicenceTypes.G2), defaultValue: getDefaultLicenceDate(DriverLicenceTypes.G2), title: `When did ${driverName} receive this G2 license?`, errorMessage: g2Error, error: driverState.inValidation, minDate: g2MinDate, maxDate: g2MaxDate })), showGQuestionAfterG1 && (jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleReceivedGChange, name: "receivedG", defaultValue: getSelectedOption(yesNoOptions, receivedG), title: `Did ${driverName} receive a G license?` })), showGDateAfterG1 && (jsx(DateSelectFormBox, { name: "gLicenceDate", dateNames: ['gLicenceYear', 'gLicenceMonth'], onDateChange: handleLicenceDateChange(DriverLicenceTypes.G), defaultValue: getDefaultLicenceDate(DriverLicenceTypes.G), title: `When did ${driverName} receive this G license?`, errorMessage: gError, error: driverState.inValidation, minDate: gMinDate, maxDate: gMaxDate }))] })), firstClass === DriverLicenceTypes.G2 && (jsxs(Fragment, { children: [showDtcG2Only && (jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleTrainingChange, name: "passedDriverTraining", defaultValue: getSelectedOption(yesNoOptions, passedDriverTraining), title: `Has ${driverName} completed a gov't approved drivers education course within the past 3 years?` })), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleReceivedGChange, name: "receivedG", defaultValue: getSelectedOption(yesNoOptions, receivedG), title: `Did ${driverName} receive a G license?` }), showGDateAfterG2 && (jsx(DateSelectFormBox, { name: "gLicenceDate", dateNames: ['gLicenceYear', 'gLicenceMonth'], onDateChange: handleLicenceDateChange(DriverLicenceTypes.G), defaultValue: getDefaultLicenceDate(DriverLicenceTypes.G), title: `When did ${driverName} receive this G license?`, errorMessage: gError, error: driverState.inValidation, minDate: gMinDate, maxDate: gMaxDate }))] })), firstClass === DriverLicenceTypes.G && !isOnlyG && showDtcGFull && (jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleTrainingChange, name: "passedDriverTraining", defaultValue: getSelectedOption(yesNoOptions, passedDriverTraining), title: `Has ${driverName} completed a gov't approved drivers education course within the past 3 years?` })), isOnlyG && showDtcGFull && (jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleTrainingChange, name: "passedDriverTraining", defaultValue: getSelectedOption(yesNoOptions, passedDriverTraining), title: `Has ${driverName} completed a gov't approved drivers education course within the past 3 years?` })), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handlePreviousLicenceChange, name: "previousLicence", defaultValue: getSelectedOption(yesNoOptions, previousLicence), title: `Has ${driverName} ever had a full license anywhere else in Canada or USA?`, description: "If you have driving experience outside Canada or the United States, it may lower your premium. Your insurer may require proof of insurance in these other locations or some proof of driving experience from the country you indicate (like a copy of a previous driver's licence)." })] }));
1537
+ }
1350
1538
  return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [jsx(InputFormBox, { name: "firstLicenceAge", title: getLicenceAgeTitle(), onChange: handleLicenceAgeChange, type: InputTypes.Number, defaultValue: firstLicenceAge, description: configState.toolTip.licenceAge, hintMessage: birthDate
1351
- ? `${firstName || driverNameDefault} was licenced in
1352
- ${Number(birthYear) + Number(firstLicenceAge)} - ${Number(birthYear) + Number(firstLicenceAge) + 1}`
1353
- : '', placeholder: "Select Licence Age", disabled: !birthDate, error: !firstLicenceAge && driverState.inValidation, errorMessage: getErrorMessage(firstLicenceAge, driverState.inValidation), minValue: minLicenceAge || 16, maxValue: maxLicenceAge }), jsx(SelectFormBox, { options: getLicenceTypeOptions(licenceTypeOptions, getDisabledLicenceTypes(gBlock, gTwoBlock, gOneBlock), true), name: "licenceType", onChange: handleLicenceTypeChange, defaultValue: getSelectedOption(licenceTypeOptions, licenceType), title: `Please choose the type of licence that ${firstName || driverNameDefault} currently holds`, placeholder: "Select from the list", disabled: !birthDate, description: configState.toolTip.licenceType, autoSelectIfValueIsOutOfOptions: false }), licenceType === DriverLicenceTypes.G && !isOnlyG && (jsx(DateSelectFormBox, { name: "g2LicenceDate", dateNames: ['g2LicenceYear', 'g2LicenceMonth'], onDateChange: handleLicenceDateChange(DriverLicenceTypes.G2), defaultValue: getDefaultLicenceDate(DriverLicenceTypes.G2), title: `${configState.licenceConfig.g2.title} licence date`, errorMessage: getDateErrorMessage(['01', g2LicenceMonth, g2LicenceYear], driverState.inValidation), hintMessage: getHintMessage(DriverLicenceTypes.G2), error: driverState.inValidation, minDate: getMinDate(DriverLicenceTypes.G2), maxDate: getMaxDate(DriverLicenceTypes.G2) })), licenceType && (jsx(DateSelectFormBox, { name: `${licenceType}LicenceDate`, dateNames: [`${licenceType}LicenceYear`, `${licenceType}LicenceMonth`], onDateChange: handleLicenceDateChange(), defaultValue: getDefaultLicenceDate(licenceType), title: `${configState.licenceConfig[licenceType].title} licence date`, errorMessage: getDateErrorMessage(['01', getLicenceMonth(licenceType), getLicenceYear(licenceType)], driverState.inValidation), hintMessage: getHintMessage(), error: driverState.inValidation, maxDate: getMaxDate(licenceType), minDate: getMinDate(licenceType) })), driverEducation && (jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleTrainingChange, name: "passedDriverTraining", defaultValue: getSelectedOption(yesNoOptions, passedDriverTraining), title: `Has ${firstName || driverNameDefault} completed a driver education course within the last 3 years?` })), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handlePreviousLicenceChange, name: "previousLicence", defaultValue: getSelectedOption(yesNoOptions, previousLicence), title: `Has ${firstName || driverNameDefault} ever had a full license anywhere else in Canada or USA?`, description: "If you have driving experience outside Canada or the United States, it may lower your premium. Your insurer may require proof of insurance in these other locations or some proof of driving experience from the country you indicate (like a copy of a previous driver\u2019s licence)." })] }));
1539
+ ? `${driverName} was licenced in ${Number(birthYear) + Number(firstLicenceAge)} - ${Number(birthYear) + Number(firstLicenceAge) + 1}`
1540
+ : '', placeholder: "Select Licence Age", disabled: !birthDate, error: !firstLicenceAge && driverState.inValidation, errorMessage: getErrorMessage(firstLicenceAge, driverState.inValidation), minValue: minLicenceAge || 16, maxValue: maxLicenceAge }), jsx(SelectFormBox, { options: getLicenceTypeOptions(licenceTypeOptions, getDisabledLicenceTypes(gBlock, gTwoBlock, gOneBlock), true), name: "licenceType", onChange: handleLicenceTypeChange, defaultValue: getSelectedOption(licenceTypeOptions, licenceType), title: `Please choose the type of licence that ${driverName} currently holds`, placeholder: "Select from the list", disabled: !birthDate, description: configState.toolTip.licenceType, autoSelectIfValueIsOutOfOptions: false }), licenceType === DriverLicenceTypes.G && !isOnlyG && (jsx(DateSelectFormBox, { name: "g2LicenceDate", dateNames: ['g2LicenceYear', 'g2LicenceMonth'], onDateChange: handleLicenceDateChange(DriverLicenceTypes.G2), defaultValue: getDefaultLicenceDate(DriverLicenceTypes.G2), title: `${configState.licenceConfig.g2.title} licence date`, errorMessage: getDateErrorMessage(['01', g2LicenceMonth, g2LicenceYear], driverState.inValidation), hintMessage: getHintMessage(DriverLicenceTypes.G2), error: driverState.inValidation, minDate: getMinDate(DriverLicenceTypes.G2), maxDate: getMaxDate(DriverLicenceTypes.G2) })), licenceType && (jsx(DateSelectFormBox, { name: `${licenceType}LicenceDate`, dateNames: [`${licenceType}LicenceYear`, `${licenceType}LicenceMonth`], onDateChange: handleLicenceDateChange(), defaultValue: getDefaultLicenceDate(licenceType), title: `${configState.licenceConfig[licenceType].title} licence date`, errorMessage: getDateErrorMessage(['01', getLicenceMonth(licenceType), getLicenceYear(licenceType)], driverState.inValidation), hintMessage: getHintMessage(), error: driverState.inValidation, maxDate: getMaxDate(licenceType), minDate: getMinDate(licenceType) })), driverEducation && (jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleTrainingChange, name: "passedDriverTraining", defaultValue: getSelectedOption(yesNoOptions, passedDriverTraining), title: `Has ${driverName} completed a driver education course within the last 3 years?` })), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handlePreviousLicenceChange, name: "previousLicence", defaultValue: getSelectedOption(yesNoOptions, previousLicence), title: `Has ${driverName} ever had a full license anywhere else in Canada or USA?`, description: "If you have driving experience outside Canada or the United States, it may lower your premium. Your insurer may require proof of insurance in these other locations or some proof of driving experience from the country you indicate (like a copy of a previous driver's licence)." })] }));
1354
1541
  };
1355
1542
 
1356
1543
  const SectionDriverInsurancePolicy = () => {
@@ -1359,7 +1546,7 @@ const SectionDriverInsurancePolicy = () => {
1359
1546
  const { driverState, dispatchDriverInsuranceState } = useStoreFormCarDriverInsurance();
1360
1547
  const { discountState, dispatchDiscountState } = useStoreFormCarDiscount();
1361
1548
  const { quoteState: { isRequested }, } = useStoreFormCarQuote();
1362
- const { listed, listedMonth = '', listedYear = '', insured, insuredDate = '', firstName, birthYear, birthMonth, birthDay, licenceInfo: { firstLicenceAge, licenceType, gLicenceYear, gLicenceMonth, g1LicenceYear, g1LicenceMonth }, } = driverState.items[driverState.activeIndex];
1549
+ const { listed, listedMonth = '', listedYear = '', insured, insuredDate = '', lastPolicyEndYear = '', lastPolicyEndMonth = '', lastPolicyCancelReason = '', firstName, birthYear, birthMonth, birthDay, licenceInfo: { firstLicenceAge, licenceType, gLicenceYear, gLicenceMonth, g1LicenceYear, g1LicenceMonth, g2LicenceYear, g2LicenceMonth, }, } = driverState.items[driverState.activeIndex];
1363
1550
  const { policyStartYear, policyStartMonth, policyStartDay } = discountState;
1364
1551
  const driverNameDefault = `Driver ${driverState.activeIndex + 1}`;
1365
1552
  const birthDate = birthYear && birthMonth && birthDay ? `${birthYear}-${birthMonth}-${birthDay}` : '';
@@ -1370,20 +1557,20 @@ const SectionDriverInsurancePolicy = () => {
1370
1557
  const options = [{ value: '', name: 'Date Period', disabled: true }];
1371
1558
  if (year && month) {
1372
1559
  const todayDate = new Date();
1373
- const month = String(todayDate.getMonth() + 1).padStart(2, '0');
1374
- const day = String(todayDate.getDate()).padStart(2, '0');
1375
- const yearsInPast = todayDate.getFullYear() - parseInt(year);
1376
- for (let i = yearsInPast; i > 0; i--) {
1377
- const pastDate = `${todayDate.getFullYear() - i}-${month}-${day}`;
1560
+ const effectiveMonth = policyStartMonth || String(todayDate.getMonth() + 1).padStart(2, '0');
1561
+ const effectiveDay = policyStartDay || String(todayDate.getDate()).padStart(2, '0');
1562
+ const yearsInPast = Math.min(todayDate.getFullYear() - parseInt(year, 10), 10);
1563
+ options.push({
1564
+ value: subMonthsFromDate('', 6),
1565
+ name: 'Less than 1 year',
1566
+ });
1567
+ for (let i = 1; i <= yearsInPast; i += 1) {
1568
+ const pastDate = `${todayDate.getFullYear() - i}-${effectiveMonth}-${effectiveDay}`;
1378
1569
  options.push({
1379
1570
  value: pastDate,
1380
- name: `${i} ${i === 1 ? 'Year' : 'Years'}`,
1571
+ name: i === 10 ? '10+ Years' : `${i} ${i === 1 ? 'Year' : 'Years'}`,
1381
1572
  });
1382
1573
  }
1383
- options.push({
1384
- value: `${todayDate.getFullYear() - 1}-${month}-${day}`,
1385
- name: 'Less than 1 Year',
1386
- });
1387
1574
  }
1388
1575
  return options;
1389
1576
  };
@@ -1397,17 +1584,49 @@ const SectionDriverInsurancePolicy = () => {
1397
1584
  month: policyStartMonth,
1398
1585
  day: policyStartDay,
1399
1586
  };
1587
+ const prevListedRef = useRef({ year: listedYear, month: listedMonth });
1588
+ const getFirstLicenceDateKey = () => {
1589
+ if (licenceType === DriverLicenceTypes.G)
1590
+ return `${gLicenceYear || ''}-${gLicenceMonth || ''}`;
1591
+ if (licenceType === DriverLicenceTypes.G2)
1592
+ return `${g2LicenceYear || ''}-${g2LicenceMonth || ''}`;
1593
+ if (licenceType === DriverLicenceTypes.G1)
1594
+ return `${g1LicenceYear || ''}-${g1LicenceMonth || ''}`;
1595
+ return `${firstLicenceAge || ''}`;
1596
+ };
1597
+ const firstLicenceDateKey = getFirstLicenceDateKey();
1598
+ const prevFirstLicenceRef = useRef(firstLicenceDateKey);
1400
1599
  useEffect(() => {
1401
1600
  if (listedYear && listedMonth && !isRequested) {
1402
- const options = getPeriodOptions(listedYear, listedMonth);
1403
- if (options.length > 1) {
1404
- dispatchDriverInsuranceState({
1405
- type: StoreFormCarDriverInsuranceActionTypes.FormCarDriverInsuredDateSelect,
1406
- payload: { insuredDate: options[1].value },
1407
- });
1601
+ const prev = prevListedRef.current;
1602
+ const hasChanged = prev.year !== listedYear || prev.month !== listedMonth;
1603
+ prevListedRef.current = { year: listedYear, month: listedMonth };
1604
+ if (!insuredDate || hasChanged) {
1605
+ const options = getPeriodOptions(listedYear, listedMonth);
1606
+ if (options.length > 1) {
1607
+ dispatchDriverInsuranceState({
1608
+ type: StoreFormCarDriverInsuranceActionTypes.FormCarDriverInsuredDateSelect,
1609
+ payload: { insuredDate: options[1].value },
1610
+ });
1611
+ }
1408
1612
  }
1409
1613
  }
1410
1614
  }, [listedYear, listedMonth]);
1615
+ useEffect(() => {
1616
+ if (!listedYear || !listedMonth || isRequested)
1617
+ return;
1618
+ const hasChanged = prevFirstLicenceRef.current !== firstLicenceDateKey;
1619
+ prevFirstLicenceRef.current = firstLicenceDateKey;
1620
+ if (!hasChanged)
1621
+ return;
1622
+ const options = getPeriodOptions(listedYear, listedMonth);
1623
+ if (options.length > 1) {
1624
+ dispatchDriverInsuranceState({
1625
+ type: StoreFormCarDriverInsuranceActionTypes.FormCarDriverInsuredDateSelect,
1626
+ payload: { insuredDate: options[1].value },
1627
+ });
1628
+ }
1629
+ }, [firstLicenceDateKey]);
1411
1630
  useEffect(() => {
1412
1631
  if (listedYear && listedMonth && listed) {
1413
1632
  const listedDate = addDaysToDate(`${listedYear}-${listedMonth}-01`, birthDay ? +birthDay + 1 : 1);
@@ -1448,6 +1667,30 @@ you had insurance. If this is correct, please continue with the form.`);
1448
1667
  type: StoreFormCarDriverInsuranceActionTypes.FormCarDriverInsuredSelect,
1449
1668
  payload: { insured: !value },
1450
1669
  });
1670
+ dispatchDriverInsuranceState({
1671
+ type: StoreFormCarDriverInsuranceActionTypes.FormCarDriverNotCurrentlyInsuredSelect,
1672
+ payload: { notCurrentlyInsured: value },
1673
+ });
1674
+ };
1675
+ const handleLastPolicyEndDateChange = (dateType) => ({ value }) => {
1676
+ if (dateType === DateTypes.Month) {
1677
+ dispatchDriverInsuranceState({
1678
+ type: StoreFormCarDriverInsuranceActionTypes.FormCarDriverLastPolicyEndMonthSelect,
1679
+ payload: { lastPolicyEndMonth: value },
1680
+ });
1681
+ }
1682
+ if (dateType === DateTypes.Year) {
1683
+ dispatchDriverInsuranceState({
1684
+ type: StoreFormCarDriverInsuranceActionTypes.FormCarDriverLastPolicyEndYearSelect,
1685
+ payload: { lastPolicyEndYear: value },
1686
+ });
1687
+ }
1688
+ };
1689
+ const handleLastPolicyCancelReasonChange = ({ value }) => {
1690
+ dispatchDriverInsuranceState({
1691
+ type: StoreFormCarDriverInsuranceActionTypes.FormCarDriverLastPolicyCancelReasonSelect,
1692
+ payload: { lastPolicyCancelReason: value },
1693
+ });
1451
1694
  };
1452
1695
  const handleListedChange = ({ value }) => {
1453
1696
  dispatchDriverInsuranceState({
@@ -1475,6 +1718,14 @@ you had insurance. If this is correct, please continue with the form.`);
1475
1718
  });
1476
1719
  }
1477
1720
  };
1721
+ const firstInsuredMinDate = listedYear && listedMonth
1722
+ ? addDaysToDate(`${listedYear}-${listedMonth}-01`, birthDay ? +birthDay + 1 : 1)
1723
+ : getMinDate(birthDate, firstLicenceAge);
1724
+ const twentyYearsAgo = getMinDateByYears(getFormattedDate('', 'yyyy-MM-dd'), 20);
1725
+ let lastPolicyEndMinDate = twentyYearsAgo;
1726
+ if (firstInsuredMinDate && compareDates(firstInsuredMinDate, twentyYearsAgo) > 0) {
1727
+ lastPolicyEndMinDate = firstInsuredMinDate;
1728
+ }
1478
1729
  const handlePolicyStartDateChange = (dateType) => ({ value }) => {
1479
1730
  if (dateType === DateTypes.Day) {
1480
1731
  dispatchDiscountState({
@@ -1495,20 +1746,26 @@ you had insurance. If this is correct, please continue with the form.`);
1495
1746
  });
1496
1747
  }
1497
1748
  };
1498
- return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [jsxs("div", { className: "box-container", children: [jsx(DateSelectFormBox, { name: "listedYear", dateNames: ['listedYear', 'listedMonth'], onDateChange: handleListedDateChange, defaultValue: defaultListedDate, disabled: !listed, title: `When was ${firstName || driverNameDefault} first listed as a driver on a Canadian or US insurance policy?`, description: "The selection indicates what year the main driver was first listed on a Canadian or US insurance policy. If you do not remember your age, it is acceptable to provide a best estimate for the purposes of the policy or quote.", errorMessage: listed
1749
+ return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [jsxs("div", { className: "box-container", children: [jsx(DateSelectFormBox, { name: "listedYear", dateNames: ['listedYear', 'listedMonth'], onDateChange: handleListedDateChange, defaultValue: defaultListedDate, disabled: !listed, title: `When was ${firstName || driverNameDefault} first listed as a driver on a Canadian or US insurance policy?`, description: "The selection indicates what month and year the driver was first listed on a Canadian or US insurance policy. If you do not remember this date, it is acceptable to provide a best estimate for the purposes of the policy or quote.", errorMessage: listed
1499
1750
  ? getDateErrorMessage(['01', listedMonth, listedYear], driverState.inValidation)
1500
- : '', error: driverState.inValidation, hintMessage: hintMessage, minDate: getMinDate(birthDate, firstLicenceAge) }), jsx(CheckboxForm, { name: "listed", label: "Never listed on an insurance policy", onChange: handleListedChange, defaultValue: !listed })] }), listed && (jsxs("div", { className: "box-container", children: [jsx(SelectFormBox, { name: "insuredDate", onChange: handleInsuredPeriodChange, options: getPeriodOptions(listedYear, listedMonth), defaultValue: insuredDate, disabled: !insured, title: `How long has ${firstName || driverNameDefault} been with their current insurance provider?`, description: "It is common for insurers to provide loyalty rewards or discounts for valued customers. Loyalty is a positive trait in the industry, and most insurance companies will want to provide some incentive for continued customer relationships through tangible policy rewards.", errorMessage: insured ? getErrorMessage(insuredDate, driverState.inValidation) : '', error: !insuredDate && driverState.inValidation }), jsx(CheckboxForm, { name: "insured", label: "Not currently insured", onChange: handleInsuredChange, defaultValue: !insured })] })), !isTheBig && !isMyChoiceLike(appType) && (jsx(DateSelectFormBox, { name: "policyStart", dateNames: ['policyStartYear', 'policyStartMonth', 'policyStartDay'], onDateChange: handlePolicyStartDateChange, defaultValue: defaultPolicyStartDate, title: "What is the ideal start date for your new insurance policy?", description: "Select your preferred date for the beginning of your new insurance policy. For instance, you may set the start date for the day that your current insurance expires to ensure that you\u2019re continuously covered. Alternatively, select today's date for a quote or new policy.", errorMessage: getDateErrorMessage([policyStartDay || '', policyStartMonth || '', policyStartYear || ''], driverState.inValidation), error: driverState.inValidation, minDate: addDaysToDate('', 1), maxDate: addDaysToDate('', 60), isDay: true }))] }));
1751
+ : '', error: driverState.inValidation, hintMessage: hintMessage, minDate: getMinDate(birthDate, firstLicenceAge) }), jsx(CheckboxForm, { name: "listed", label: "Never listed on an insurance policy", onChange: handleListedChange, defaultValue: !listed })] }), listed && (jsxs("div", { className: "box-container", children: [jsx(SelectFormBox, { name: "insuredDate", onChange: handleInsuredPeriodChange, options: getPeriodOptions(listedYear, listedMonth), defaultValue: insuredDate, disabled: !insured, title: `How long has ${firstName || driverNameDefault} been with their current insurance provider?`, description: "It is common for insurers to provide loyalty rewards or discounts for valued customers. Loyalty is a positive trait in the industry, and most insurance companies will want to provide some incentive for continued customer relationships through tangible policy rewards.", errorMessage: insured ? getErrorMessage(insuredDate, driverState.inValidation) : '', error: !insuredDate && driverState.inValidation }), jsx(CheckboxForm, { name: "insured", label: "Not currently insured", onChange: handleInsuredChange, defaultValue: !insured })] })), listed && !insured && (jsxs(Fragment, { children: [jsx(DateSelectFormBox, { name: "lastPolicyEnd", dateNames: ['lastPolicyEndYear', 'lastPolicyEndMonth'], onDateChange: handleLastPolicyEndDateChange, defaultValue: { year: lastPolicyEndYear, month: lastPolicyEndMonth, day: '01' }, title: `When did ${firstName || driverNameDefault}'s most recent policy end?`, errorMessage: getDateErrorMessage(['01', lastPolicyEndMonth, lastPolicyEndYear], driverState.inValidation), error: driverState.inValidation, maxDate: getFormattedDate('', 'yyyy-MM-dd'), minDate: lastPolicyEndMinDate }), lastPolicyEndYear && lastPolicyEndMonth && (jsx(SelectFormBox, { options: insuranceCancellationReasonOptions, name: "lastPolicyCancelReason", onChange: handleLastPolicyCancelReasonChange, defaultValue: lastPolicyCancelReason, title: "Why was this last insurance policy cancelled?", placeholder: "Select from the list", autoSelectIfValueIsOutOfOptions: false, error: !lastPolicyCancelReason && driverState.inValidation, errorMessage: getErrorMessage(lastPolicyCancelReason, driverState.inValidation) }))] })), !isTheBig && !isMyChoiceLike(appType) && (jsx(DateSelectFormBox, { name: "policyStart", dateNames: ['policyStartYear', 'policyStartMonth', 'policyStartDay'], onDateChange: handlePolicyStartDateChange, defaultValue: defaultPolicyStartDate, title: "What is the ideal start date for your new insurance policy?", description: "Select your preferred date for the beginning of your new insurance policy. For instance, you may set the start date for the day that your current insurance expires to ensure that you\u2019re continuously covered. Alternatively, select today's date for a quote or new policy.", errorMessage: getDateErrorMessage([policyStartDay || '', policyStartMonth || '', policyStartYear || ''], driverState.inValidation), error: driverState.inValidation, minDate: addDaysToDate('', 1), maxDate: addDaysToDate('', 60), isDay: true }))] }));
1501
1752
  };
1502
1753
 
1503
1754
  const SectionDriverCancellation = () => {
1504
1755
  const { driverState, dispatchDriverCancellationState } = useStoreFormCarDriverCancellation();
1505
1756
  const { dispatchDriverBaseState } = useStoreFormCarDriverBase();
1757
+ const { discountState } = useStoreFormCarDiscount();
1506
1758
  const { insuranceCancellation, insuranceCancellationList = [] } = driverState.items[driverState.activeIndex];
1507
1759
  const { appConfigState: { appType }, } = useStoreAppConfig();
1508
1760
  const isTheBig = appType === AppTypes.TheBig;
1509
1761
  const mychoiceCls = isMyChoiceLike(appType) ? 'mychoice' : '';
1510
- const { firstName, birthYear, birthMonth, birthDay, licenceInfo: { firstLicenceAge }, } = driverState.items[driverState.activeIndex];
1762
+ const { firstName, birthYear, birthMonth, birthDay, listedYear, listedMonth, licenceInfo: { firstLicenceAge }, } = driverState.items[driverState.activeIndex];
1511
1763
  const birthDate = birthYear && birthMonth && birthDay ? `${birthYear}-${birthMonth}-${birthDay}` : '';
1764
+ const policyStart = discountState.policyStart || getFormattedDate('', 'yyyy-MM-dd');
1765
+ const firstInsuredDate = listedYear && listedMonth ? `${listedYear}-${listedMonth}-01` : '';
1766
+ const rawYearsSinceFirstInsured = firstInsuredDate ? getDifferenceInYears(policyStart, firstInsuredDate) : 0;
1767
+ const cancellationYearCap = Math.min(rawYearsSinceFirstInsured, 10);
1768
+ const cancellationYearLabel = cancellationYearCap <= 1 ? 'past year' : `past ${cancellationYearCap} years`;
1512
1769
  const handleIconClick = (index) => () => {
1513
1770
  dispatchDriverCancellationState({
1514
1771
  type: StoreFormCarDriverCancellationActionTypes.FormCarDriverInsuranceCancellationDelete,
@@ -1581,8 +1838,7 @@ const SectionDriverCancellation = () => {
1581
1838
  });
1582
1839
  }
1583
1840
  };
1584
- return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [jsx("h2", { className: isTheBig ? 'thebig-bold' : '', children: "Insurance Cancellation" }), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleCancellationChange, name: "insuranceCancellation", defaultValue: getSelectedOption(yesNoOptions, insuranceCancellation), title: `Has ${firstName} had an insurance company cancellation or
1585
- a time without insurance coverage, within the past 3 years?`, description: "If an insurance company cancels your policy, it will increase your future insurance premiums. The most common reasons for cancellations include missed payments, excessive claims, false declarations, or criminal actions, for example. If you cancel the insurance policy, it is not relevant." }), insuranceCancellation && (jsxs(Fragment, { children: [insuranceCancellationList?.map(({ cancellationReason, startYear, startMonth, endYear, endMonth }, index) => {
1841
+ return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [jsx("h2", { className: isTheBig ? 'thebig-bold' : '', children: "Insurance Cancellation" }), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleCancellationChange, name: "insuranceCancellation", defaultValue: getSelectedOption(yesNoOptions, insuranceCancellation), title: `Has ${firstName} had an insurance company cancellation or a time without insurance coverage, within the ${cancellationYearLabel}?`, description: "If an insurance company cancels your policy, it will increase your future insurance premiums. The most common reasons for cancellations include missed payments, excessive claims, false declarations, or criminal actions, for example. If you cancel the insurance policy, it is not relevant." }), insuranceCancellation && (jsxs(Fragment, { children: [insuranceCancellationList?.map(({ cancellationReason, startYear, startMonth, endYear, endMonth }, index) => {
1586
1842
  const defaultStartDate = {
1587
1843
  year: startYear,
1588
1844
  month: startMonth,
@@ -1594,7 +1850,7 @@ const SectionDriverCancellation = () => {
1594
1850
  const now = getFormattedDate('', 'yyyy-MM-dd');
1595
1851
  const days = birthDay ? +birthDay + 1 : 1;
1596
1852
  const endDate = endYear && endMonth ? addDayToDate(`${endYear}-${endMonth}`, days) : now;
1597
- const currentMinDate = getMinDateByYears(getMinDate(birthDate, firstLicenceAge), 3);
1853
+ const currentMinDate = getMinDateByYears(getMinDate(birthDate, firstLicenceAge), cancellationYearCap + 1);
1598
1854
  const currentEndDate = compareDates(endDate, currentMinDate) < 0 ? currentMinDate : endDate;
1599
1855
  return (jsxs("div", { className: "list-block", children: [jsx("hr", {}), jsxs("div", { className: "list-item", children: [jsx(SelectFormBox, { options: insuranceCancellationReasonOptions, name: `cancellationReason-${index}`, onChange: handleReasonChange(index), defaultValue: cancellationReason, title: "Reason", placeholder: "Select from the list", isRemovable: insuranceCancellationList.length > 1, onIconClick: handleIconClick(index), autoSelectIfValueIsOutOfOptions: false, error: !cancellationReason && driverState.inValidation, errorMessage: getErrorMessage(cancellationReason, driverState.inValidation) }), jsx(DateSelectFormBox, { name: `startDate-${index}`, dateNames: [`startYear-${index}`, `startMonth-${index}`], onDateChange: handleStartDateChange(index), defaultValue: defaultStartDate, title: "Start date", errorMessage: getDateErrorMessage(['01', startMonth, startYear], driverState.inValidation), error: driverState.inValidation, minDate: currentMinDate, maxDate: currentEndDate }), jsx(DateSelectFormBox, { name: `endDate-${index}`, dateNames: [`endYear-${index}`, `endMonth-${index}`], onDateChange: handleEndDateChange(index), defaultValue: defaultEndDate, title: "End Date", errorMessage: getDateErrorMessage(['01', endMonth, endYear], driverState.inValidation), error: driverState.inValidation, minDate: startMonth && startYear ? addDayToDate(`${startYear}-${startMonth}`, days) : currentMinDate })] })] }, `insurance-cancellation-${index}`));
1600
1856
  }), insuranceCancellationList?.length < 3 && (jsx(ButtonBase, { category: CategoryTypes.Filled, onClick: handleAddButtonClick, size: SizeTypes.Medium, color: ColorTypes.Primary, label: "Add another" }))] }))] }));
@@ -1604,10 +1860,15 @@ const BlockDriverSuspension = () => {
1604
1860
  const { driverState, dispatchDriverSuspensionState } = useStoreFormCarDriverSuspension();
1605
1861
  const { licenceSuspension, licenceSuspensionList = [] } = driverState.items[driverState.activeIndex];
1606
1862
  const { dispatchDriverBaseState } = useStoreFormCarDriverBase();
1863
+ const { discountState } = useStoreFormCarDiscount();
1607
1864
  const { appConfigState: { appType } } = useStoreAppConfig();
1608
1865
  const isTheBig = appType === AppTypes.TheBig;
1609
1866
  const { firstName, birthYear, birthMonth, birthDay, licenceInfo: { firstLicenceAge }, } = driverState.items[driverState.activeIndex];
1610
1867
  const birthDate = birthYear && birthMonth && birthDay ? `${birthYear}-${birthMonth}-${birthDay}` : '';
1868
+ const earliestLicenceDate = birthDate && firstLicenceAge ? addYearsToDate(birthDate, +firstLicenceAge) : '';
1869
+ const policyStart = discountState.policyStart || getFormattedDate('', 'yyyy-MM-dd');
1870
+ const yearsElapsed = earliestLicenceDate ? Math.min(getDifferenceInYears(policyStart, earliestLicenceDate), 6) : 6;
1871
+ const suspensionYearLabel = yearsElapsed <= 1 ? 'past year' : `past ${yearsElapsed} years`;
1611
1872
  const handleSuspensionChange = ({ value }) => {
1612
1873
  dispatchDriverSuspensionState({
1613
1874
  type: StoreFormCarDriverSuspensionActionTypes.FormCarDriverLicenceSuspensionSelect,
@@ -1680,7 +1941,7 @@ const BlockDriverSuspension = () => {
1680
1941
  });
1681
1942
  }
1682
1943
  };
1683
- return (jsxs("div", { className: "form-block-container", children: [jsx("h2", { className: isTheBig ? 'thebig-bold' : '', children: "Licence Suspensions" }), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleSuspensionChange, name: "licenceSuspension", defaultValue: getSelectedOption(yesNoOptions, licenceSuspension), title: `Has ${firstName} had a licence suspension within the past 3 years?`, description: "Three licence suspensions are common: 1) driving under the influence, 2) being found guilty of drinking and driving, and 3) a police officer finding reasonable grounds for a driving offence. Licence suspensions are also different from driving prohibitions as part of a criminal sentence." }), licenceSuspension && (jsxs(Fragment, { children: [licenceSuspensionList?.map(({ suspensionReason, suspensionYear, suspensionMonth, reinstatementYear, reinstatementMonth, }, index) => {
1944
+ return (jsxs("div", { className: "form-block-container", children: [jsx("h2", { className: isTheBig ? 'thebig-bold' : '', children: "Licence Suspensions" }), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleSuspensionChange, name: "licenceSuspension", defaultValue: getSelectedOption(yesNoOptions, licenceSuspension), title: `Has ${firstName} had a licence suspension within the ${suspensionYearLabel}?`, description: "There are two main types of licence suspensions: 1. Non-administrated suspension for cause: A driver's licence is suspended or cancelled because of traffic and criminal code driving offences or collecting too many demerit points. 2. Administrative suspension/cancellation/lapse: A driver's licence is suspended, cancelled, or allowed to lapse for reasons other than driving offences or demerit points such as a roadside licence suspension, medical conditions or failure to comply with court\u2011ordered obligations." }), licenceSuspension && (jsxs(Fragment, { children: [licenceSuspensionList?.map(({ suspensionReason, suspensionYear, suspensionMonth, reinstatementYear, reinstatementMonth, }, index) => {
1684
1945
  const defaultSuspensionDate = {
1685
1946
  year: suspensionYear,
1686
1947
  month: suspensionMonth,
@@ -1692,7 +1953,7 @@ const BlockDriverSuspension = () => {
1692
1953
  const now = getFormattedDate('', 'yyyy-MM-dd');
1693
1954
  const days = birthDay ? (+birthDay + 1) : 1;
1694
1955
  const endDate = reinstatementYear && reinstatementMonth ? addDayToDate(`${reinstatementYear}-${reinstatementMonth}`, days) : now;
1695
- const currentMinDate = getMinDateByYears(getMinDate(birthDate, firstLicenceAge), 3);
1956
+ const currentMinDate = getMinDateByYears(getMinDate(birthDate, firstLicenceAge), 6);
1696
1957
  const currentEndDate = compareDates(endDate, currentMinDate) < 0 ? currentMinDate : endDate;
1697
1958
  return (jsxs("div", { className: "list-block", children: [jsx("hr", {}), jsxs("div", { className: "list-item", children: [jsx(SelectFormBox, { options: licenceSuspensionsReasonOptions, name: `suspensionReason-${index}`, onChange: handleReasonChange(index), defaultValue: suspensionReason, title: "Reason for licence suspension", placeholder: "Select from the list", isRemovable: licenceSuspensionList.length > 1, onIconClick: handleIconClick(index), autoSelectIfValueIsOutOfOptions: false, error: !suspensionReason && driverState.inValidation, errorMessage: getErrorMessage(suspensionReason, driverState.inValidation) }), jsx(DateSelectFormBox, { name: `suspensionDate-${index}`, dateNames: [`suspensionYear-${index}`, `suspensionMonth-${index}`], onDateChange: handleSuspensionDateChange(index), defaultValue: defaultSuspensionDate, title: "Start date", errorMessage: getDateErrorMessage(['01', suspensionMonth, suspensionYear], driverState.inValidation), error: driverState.inValidation, minDate: currentMinDate, maxDate: currentEndDate }), jsx(DateSelectFormBox, { name: `reinstatementDate-${index}`, dateNames: [`reinstatementYear-${index}`, `reinstatementMonth-${index}`], onDateChange: handleReinstatementDateChange(index), defaultValue: defaultReinstatementDate, title: "End Date", errorMessage: getDateErrorMessage(['01', reinstatementMonth, reinstatementYear], driverState.inValidation), error: driverState.inValidation, minDate: suspensionYear && suspensionMonth
1698
1959
  ? addDayToDate(`${suspensionYear}-${suspensionMonth}`, days) : currentMinDate })] })] }, `suspension-${index}`));
@@ -1703,10 +1964,25 @@ const BlockDriverAccident = () => {
1703
1964
  const { driverState, dispatchDriverAccidentState } = useStoreFormCarDriverAccident();
1704
1965
  const { dispatchDriverBaseState } = useStoreFormCarDriverBase();
1705
1966
  const { appConfigState: { appType } } = useStoreAppConfig();
1967
+ const { discountState } = useStoreFormCarDiscount();
1968
+ const { isAlbertaProvince, isNovaScotiaProvince, isNewfoundlandProvince, isOntarioProvince } = useProvince();
1706
1969
  const isTheBig = appType === AppTypes.TheBig;
1970
+ const accidentYearCap = isTheBig || isAlbertaProvince || isNovaScotiaProvince || isNewfoundlandProvince ? 10 : 25;
1707
1971
  const { accident, accidentList = [] } = driverState.items[driverState.activeIndex];
1708
- const { firstName, birthYear, birthMonth, birthDay, licenceInfo: { firstLicenceAge }, } = driverState.items[driverState.activeIndex];
1972
+ const { firstName, birthYear, birthMonth, birthDay, licenceInfo: { firstLicenceAge, licenceType, g1LicenceYear, g1LicenceMonth, g2LicenceYear, g2LicenceMonth, gLicenceYear, gLicenceMonth, }, } = driverState.items[driverState.activeIndex];
1709
1973
  const birthDate = birthYear && birthMonth && birthDay ? `${birthYear}-${birthMonth}-${birthDay}` : '';
1974
+ const getOntarioQ1Date = () => {
1975
+ if (licenceType === DriverLicenceTypes.G2)
1976
+ return g2LicenceYear && g2LicenceMonth ? `${g2LicenceYear}-${g2LicenceMonth}-01` : '';
1977
+ if (licenceType === DriverLicenceTypes.G)
1978
+ return gLicenceYear && gLicenceMonth ? `${gLicenceYear}-${gLicenceMonth}-01` : '';
1979
+ return g1LicenceYear && g1LicenceMonth ? `${g1LicenceYear}-${g1LicenceMonth}-01` : '';
1980
+ };
1981
+ const ontarioQ1Date = isOntarioProvince && isMyChoiceLike(appType) ? getOntarioQ1Date() : '';
1982
+ const earliestLicenceDate = ontarioQ1Date || (birthDate && firstLicenceAge ? addYearsToDate(birthDate, +firstLicenceAge) : '');
1983
+ const policyStart = discountState.policyStart || getFormattedDate('', 'yyyy-MM-dd');
1984
+ const yearsElapsed = earliestLicenceDate ? Math.min(getDifferenceInYears(policyStart, earliestLicenceDate), accidentYearCap) : accidentYearCap;
1985
+ const accidentYearLabel = yearsElapsed <= 1 ? 'past year' : `past ${yearsElapsed} years`;
1710
1986
  const handleAccidentChange = ({ value }) => {
1711
1987
  dispatchDriverAccidentState({
1712
1988
  type: StoreFormCarDriverAccidentActionTypes.FormCarDriverAccidentSelect,
@@ -1750,27 +2026,28 @@ const BlockDriverAccident = () => {
1750
2026
  });
1751
2027
  }
1752
2028
  };
1753
- return (jsxs("div", { className: "form-block-container", children: [jsx("h2", { className: isTheBig ? 'thebig-bold' : '', children: "Accidents" }), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleAccidentChange, name: "accident", defaultValue: getSelectedOption(yesNoOptions, accident), title: `Has ${firstName} ever been at-fault for any accidents?`, description: "An at-fault accident means you are responsible for the car accident according to the investigative report. Whether you did not obey traffic signals or hit the brakes too late, it will show up on your insurance record for up to ten years. Insurers access at-fault information if one party reports it, so it is best to disclose previous incidents. A clean driving record mitigates additional hikes to your insurance premium." }), accident && (jsxs(Fragment, { children: [accidentList?.map(({ accidentYear, accidentMonth, }, index) => {
2029
+ return (jsxs("div", { className: "form-block-container", children: [jsx("h2", { className: isTheBig ? 'thebig-bold' : '', children: "Accidents" }), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleAccidentChange, name: "accident", defaultValue: getSelectedOption(yesNoOptions, accident), title: `Has ${firstName} been at-fault for any accidents in the ${accidentYearLabel}?`, description: "An at-fault accident means you were responsible for the car accident according to provincially regulated Fault Determination Rules. Whether you did not obey traffic signals or hit the brakes too late, it can show up on your insurance record for up to 25 years. Insurers access at-fault information if one party reports it, so it is best to disclose previous incidents. A clean driving record mitigates additional hikes to your insurance premium." }), accident && (jsxs(Fragment, { children: [accidentList?.map(({ accidentYear, accidentMonth, }, index) => {
1754
2030
  const defaultSuspensionDate = {
1755
2031
  year: accidentYear,
1756
2032
  month: accidentMonth,
1757
2033
  day: '01',
1758
2034
  };
1759
- return (jsxs("div", { className: "list-block", children: [jsx("hr", {}), jsx(DateSelectFormBox, { name: `accidentDate-${index}`, dateNames: [`accidentYear-${index}`, `accidentMonth-${index}`], onDateChange: handleAccidentDateChange(index), isRemovable: accidentList.length > 1, onIconClick: handleIconClick(index), defaultValue: defaultSuspensionDate, title: "Accident date", errorMessage: getDateErrorMessage(['01', accidentMonth, accidentYear], driverState.inValidation), error: driverState.inValidation, minDate: getMinDate(birthDate, firstLicenceAge) })] }, `accident-${index}`));
2035
+ return (jsxs("div", { className: "list-block", children: [jsx("hr", {}), jsx(DateSelectFormBox, { name: `accidentDate-${index}`, dateNames: [`accidentYear-${index}`, `accidentMonth-${index}`], onDateChange: handleAccidentDateChange(index), isRemovable: accidentList.length > 1, onIconClick: handleIconClick(index), defaultValue: defaultSuspensionDate, title: "Accident date", errorMessage: getDateErrorMessage(['01', accidentMonth, accidentYear], driverState.inValidation), error: driverState.inValidation, minDate: getMinDateByYears(ontarioQ1Date || getMinDate(birthDate, firstLicenceAge), accidentYearCap) })] }, `accident-${index}`));
1760
2036
  }), accidentList?.length < 3 && (jsx(ButtonBase, { category: CategoryTypes.Filled, onClick: handleAddButtonClick, size: SizeTypes.Medium, color: ColorTypes.Primary, label: "Add another" }))] }))] }));
1761
2037
  };
1762
2038
 
1763
2039
  /**
1764
- * Filter out G1/G2 options from "Serious" section for trafficTicketsGroupOptions
2040
+ * Filter out G1/G2 options (ALC, RB) from the "Criminal" section for trafficTicketsGroupOptions
1765
2041
  */
1766
2042
  const getTrafficTicketsGroupOptionsWithoutG1G2 = () => {
1767
2043
  const excludeOptions = ['ALC', 'RB'];
1768
- const seriousOptions = trafficTicketsGroupOptions.find((entry) => entry.label === 'Serious');
1769
- const filteredSeriousOptions = seriousOptions.options.filter((option) => !excludeOptions.includes(option.value));
1770
- return trafficTicketsGroupOptions.map((option) => {
1771
- if (option.label === 'Serious')
1772
- return { ...option, options: filteredSeriousOptions };
1773
- return option;
2044
+ return trafficTicketsGroupOptions.map((group) => {
2045
+ if (group.label !== 'Criminal')
2046
+ return group;
2047
+ return {
2048
+ ...group,
2049
+ options: group.options.filter((option) => !excludeOptions.includes(option.value)),
2050
+ };
1774
2051
  });
1775
2052
  };
1776
2053
 
@@ -1783,11 +2060,43 @@ const BlockDriverTicket = () => {
1783
2060
  const isTheBig = appType === AppTypes.TheBig;
1784
2061
  const { firstName, minMaxDates, } = driverState.items[driverState.activeIndex];
1785
2062
  const { gOneMin } = minMaxDates;
2063
+ // Each speeding tier is tagged with the picklist section it belongs to.
2064
+ // The tier itself determines the Fortus <Speed> and <Severity>, so no speed is asked of the user.
2065
+ const getSpeedingOptions = () => {
2066
+ if (isNovaScotiaProvince) {
2067
+ return [
2068
+ { value: 'SP_NS_MINOR', name: 'Speeding 1 to 30 kph over limit', section: 'Minor' },
2069
+ { value: 'SP_NS_MAJOR', name: 'Speeding 31 to 50 kph over limit', section: 'Major' },
2070
+ { value: 'SP_NS_CRIMINAL', name: 'Speeding 51 kph or more over limit', section: 'Criminal' },
2071
+ ];
2072
+ }
2073
+ if (isAlbertaProvince || isNewfoundlandProvince) {
2074
+ return [
2075
+ { value: 'SP_MINOR', name: 'Speeding 1 to 50 kph over limit', section: 'Minor' },
2076
+ { value: 'SP_51_CRIMINAL', name: 'Speeding 51 kph or more over limit', section: 'Criminal' },
2077
+ ];
2078
+ }
2079
+ return [
2080
+ { value: 'SP_MINOR', name: 'Speeding 1 to 49 kph over limit', section: 'Minor' },
2081
+ { value: 'SP_50_CRIMINAL', name: 'Speeding 50 kph or more over limit', section: 'Criminal' },
2082
+ ];
2083
+ };
1786
2084
  const getTrafficTicketsGroupOptions = () => {
1787
- if ((isAlbertaProvince || isNewBrunswickProvince || isNovaScotiaProvince || isNewfoundlandProvince) && isTheBig) {
1788
- return getTrafficTicketsGroupOptionsWithoutG1G2();
1789
- }
1790
- return trafficTicketsGroupOptions;
2085
+ const base = (isAlbertaProvince || isNewBrunswickProvince || isNovaScotiaProvince || isNewfoundlandProvince) && isTheBig
2086
+ ? getTrafficTicketsGroupOptionsWithoutG1G2()
2087
+ : trafficTicketsGroupOptions;
2088
+ const speedingOptions = getSpeedingOptions();
2089
+ const toOption = ({ value, name }) => ({ value, name });
2090
+ return base.map((group) => {
2091
+ // Drop the generic "Speeding" entry; tiers are injected per section below.
2092
+ const options = group.options.filter((opt) => !(opt.value === 'SP' && opt.name === 'Speeding'));
2093
+ // Each tier appears in the Common section and in its matching severity section.
2094
+ const tiersForGroup = speedingOptions.filter((tier) => group.label === 'Common' || group.label === tier.section);
2095
+ return {
2096
+ ...group,
2097
+ options: [...options, ...tiersForGroup.map(toOption)],
2098
+ };
2099
+ });
1791
2100
  };
1792
2101
  const handleTicketChange = ({ value }) => {
1793
2102
  dispatchDriverTicketState({
@@ -1941,12 +2250,14 @@ const getDynamicLicenceBoxProps = ({ isAlbertaProvince, isOntarioProvince, isNew
1941
2250
  const SectionDiscountInfo$1 = () => {
1942
2251
  const { appConfigState: { appType }, } = useStoreAppConfig();
1943
2252
  const allProvinces = useProvince();
2253
+ const { isAlbertaProvince } = allProvinces;
1944
2254
  const isTheBig = appType === AppTypes.TheBig;
1945
2255
  const mychoiceCls = isMyChoiceLike(appType) ? 'mychoice' : '';
1946
2256
  const { discountState, dispatchDiscountState } = useStoreFormCarDiscount();
1947
2257
  const { validateEmail, errorMessage } = useHandlerCarQuoterEmail();
2258
+ const { validatePhone, errorMessage: phoneErrorMessage } = useHandlerCarQuoterPhone();
1948
2259
  const { multiplePoliciesDiscount, appInstallDiscount, caaMemberDiscount, quoterInfo, emailTo: { email, emailStatus }, } = discountState;
1949
- const { firstName, lastName, phone, driverLicense = '', caslConsent } = quoterInfo;
2260
+ const { firstName, lastName, phone, phoneStatus, driverLicense = '', caslConsent } = quoterInfo;
1950
2261
  const handleMultiplePolicyChange = ({ value }) => {
1951
2262
  dispatchDiscountState({
1952
2263
  type: StoreFormCarDiscountActionTypes.FormCarDiscountMultiplePoliciesSelect,
@@ -1984,10 +2295,16 @@ const SectionDiscountInfo$1 = () => {
1984
2295
  });
1985
2296
  };
1986
2297
  const handlePhoneNumberChange = ({ value }) => {
1987
- dispatchDiscountState({
1988
- type: StoreFormCarDiscountActionTypes.FormCarDiscountQuoterPhoneSet,
1989
- payload: { phone: value },
1990
- });
2298
+ const digits = value.replace(/\D/g, '');
2299
+ if (digits.length === 10) {
2300
+ validatePhone(value);
2301
+ }
2302
+ else {
2303
+ dispatchDiscountState({
2304
+ type: StoreFormCarDiscountActionTypes.FormCarDiscountQuoterPhoneStatusSet,
2305
+ payload: { phone: value, phoneStatus: ValidationStatusTypes.Initial },
2306
+ });
2307
+ }
1991
2308
  };
1992
2309
  const handleEmailChange = ({ value }) => {
1993
2310
  validateEmail(value);
@@ -1998,7 +2315,11 @@ const SectionDiscountInfo$1 = () => {
1998
2315
  payload: { caslConsent: value },
1999
2316
  });
2000
2317
  };
2001
- return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [isTheBig ? (jsx(LabelFormBox, { title: "You are seconds away from receiving your car insurance quotes,\n please provide your email after completing the discount section so we\n can send you your personalized free car insurance quotes!" })) : (jsxs(Fragment, { children: [jsx("h2", { className: "section-title", children: "A little extra info for discounts and connecting you with our partners." }), jsx("span", { className: "info-title-message", children: "You are seconds away from receiving your car insurance quotes, please provide your email after completing the discount section so we can send you your personalized free car insurance quotes!" })] })), jsx(BlockVehLinks, {}), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleMultiplePolicyChange, name: "multiplePoliciesDiscount", defaultValue: getSelectedOption(yesNoOptions, multiplePoliciesDiscount), title: "You could receive a 10-15% discount for bundling insurance with multiple policies with the same insurance company. Does that interest you?", description: "Bundling your home and auto insurance can save you significantly on insurance premiums as a whole package. Do you want to learn more about the benefits of multiple policies for home, tenant, condo, or car insurance? All you have to do is select yes.." }), !isTheBig && (jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleCaaMemberChange, name: "caaMemberDiscount", defaultValue: getSelectedOption(yesNoOptions, caaMemberDiscount), title: "Please indicate if you are a member of CAA, you could save up to an additional 20%." })), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleAppInstallChange, name: "appInstallDiscount", defaultValue: getSelectedOption(yesNoOptions, appInstallDiscount), title: "You could receive up to a 30% discount by using an app to track driving habits. Does that interest you?", description: "Get rewarded for safe driving with the click of a button. If you install the app, you may be eligible for a 30% discount on your insurance premiums. Typically, you receive 10% of the discount upfront and the balance after six months of good driving." }), isTheBig ? (jsxs("div", { className: "input-form-box-container", children: [jsx(LabelFormBox, { title: "Complete this form to see all your personalized\n quotes on the next page, you will also be able to:" }), jsxs("ol", { className: "ordered-block", children: [jsx("li", { children: "See what rates insurance carriers are offering" }), jsx("li", { children: "Get in touch with us and secure your rate" }), jsx("li", { children: "Potentially save more by speaking with a broker" })] })] })) : (jsx("h2", { children: "Complete the form below to see which companies are offering your quotes." })), jsx(InputFormBox, { name: "firstName", title: "First Name", onChange: handleFirstNameChange, defaultValue: firstName, placeholder: "Your First Name", error: !firstName && discountState.inValidation, errorMessage: getErrorMessage(firstName, discountState.inValidation) }), jsx(InputFormBox, { name: "lastname", title: "Last Name", onChange: handleLastNameChange, defaultValue: lastName, placeholder: "Your Last Name", error: !lastName && discountState.inValidation, errorMessage: getErrorMessage(lastName, discountState.inValidation) }), isTheBig && (jsx(InputFormLicenceBox, { ...getDynamicLicenceBoxProps({ ...allProvinces }), name: "driverLicense", title: "Driver Licence Number (Optional)", onChange: handleDriverLicenseChange, defaultValue: driverLicense, description: "Enter your drivers licence number in to receive a more accurate, prequalified quote from our broker partners. This will enable you to provide less details over the phone if you choose to have a broker contact you. This is an optional input." })), jsx(InputFormPhoneBox, { name: "phone", onChange: handlePhoneNumberChange, defaultValue: phone, title: "Phone Number", placeholder: "(855) 325-8444", error: !phone && discountState.inValidation, errorMessage: getErrorMessage(phone, discountState.inValidation) }), jsx(InputFormEmailBox, { validationStatus: emailStatus, errorMessage: emailStatus === ValidationStatusTypes.Declined
2318
+ return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [isTheBig ? (jsx(LabelFormBox, { title: "You are seconds away from receiving your car insurance quotes,\n please provide your email after completing the discount section so we\n can send you your personalized free car insurance quotes!" })) : (jsxs(Fragment, { children: [jsx("h2", { className: "section-title", children: "A little extra info for discounts and connecting you with our partners." }), jsx("span", { className: "info-title-message", children: "You are seconds away from receiving your car insurance quotes, please provide your email after completing the discount section so we can send you your personalized free car insurance quotes!" })] })), jsx(BlockVehLinks, {}), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleMultiplePolicyChange, name: "multiplePoliciesDiscount", defaultValue: getSelectedOption(yesNoOptions, multiplePoliciesDiscount), title: "You could receive a 10-15% discount for bundling insurance with multiple policies with the same insurance company. Does that interest you?", description: "Bundling your home and auto insurance can save you significantly on insurance premiums as a whole package. Do you want to learn more about the benefits of multiple policies for home, tenant, condo, or car insurance? All you have to do is select yes.." }), !isTheBig && !isAlbertaProvince && (jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleCaaMemberChange, name: "caaMemberDiscount", defaultValue: getSelectedOption(yesNoOptions, caaMemberDiscount), title: "Please indicate if you are a member of CAA, you could save up to an additional 20%." })), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleAppInstallChange, name: "appInstallDiscount", defaultValue: getSelectedOption(yesNoOptions, appInstallDiscount), title: "You could receive up to a 30% discount by using an app to track driving habits. Does that interest you?", description: "Get rewarded for safe driving with the click of a button. If you install the app, you may be eligible for a 30% discount on your insurance premiums. Typically, you receive 10% of the discount upfront and the balance after six months of good driving." }), isTheBig ? (jsxs("div", { className: "input-form-box-container", children: [jsx(LabelFormBox, { title: "Complete this form to see all your personalized\n quotes on the next page, you will also be able to:" }), jsxs("ol", { className: "ordered-block", children: [jsx("li", { children: "See what rates insurance carriers are offering" }), jsx("li", { children: "Get in touch with us and secure your rate" }), jsx("li", { children: "Potentially save more by speaking with a broker" })] })] })) : (jsx("h2", { children: "Complete the form below to see which companies are offering your quotes." })), jsx(InputFormBox, { name: "firstName", title: "First Name", onChange: handleFirstNameChange, defaultValue: firstName, placeholder: "Your First Name", error: !firstName && discountState.inValidation, errorMessage: getErrorMessage(firstName, discountState.inValidation) }), jsx(InputFormBox, { name: "lastname", title: "Last Name", onChange: handleLastNameChange, defaultValue: lastName, placeholder: "Your Last Name", error: !lastName && discountState.inValidation, errorMessage: getErrorMessage(lastName, discountState.inValidation) }), isTheBig && (jsx(InputFormLicenceBox, { ...getDynamicLicenceBoxProps({ ...allProvinces }), name: "driverLicense", title: "Driver Licence Number (Optional)", onChange: handleDriverLicenseChange, defaultValue: driverLicense, description: "Enter your drivers licence number in to receive a more accurate, prequalified quote from our broker partners. This will enable you to provide less details over the phone if you choose to have a broker contact you. This is an optional input." })), jsx(InputFormPhoneBox, { name: "phone", onChange: handlePhoneNumberChange, defaultValue: phone, title: "Phone Number", placeholder: "(855) 325-8444", validationStatus: phoneStatus, error: phoneStatus === ValidationStatusTypes.Declined
2319
+ || (phoneStatus === ValidationStatusTypes.Initial && discountState.inValidation)
2320
+ || (!phone && discountState.inValidation), errorMessage: phoneStatus === ValidationStatusTypes.Declined
2321
+ ? phoneErrorMessage
2322
+ : getErrorMessage(phone, discountState.inValidation) || (discountState.inValidation ? 'Enter a valid phone number.' : '') }), jsx(InputFormEmailBox, { validationStatus: emailStatus, errorMessage: emailStatus === ValidationStatusTypes.Declined
2002
2323
  ? errorMessage
2003
2324
  : getErrorMessage(email, discountState.inValidation), error: emailStatus === ValidationStatusTypes.Declined || (!email && discountState.inValidation), name: "email", title: "Please share your email address with us, we'll use it to send you a copy of your quotes.", description: "We will provide you with your insurance quotes immediately after this form completion. If you are not ready to apply today, don\u2019t worry as we will be emailing your quotes to you if you\u2019d like to complete at a later date with the help of one of our trusted broker partners.", onChange: handleEmailChange, defaultValue: email, placeholder: getPlaceholderEmail(appType) }), isTheBig && (jsx(CheckboxForm, { className: "casl-consent", name: "caslConsent", label: "Yes, I consent to receiving emails from the Billyard Insurance Group.\n I understand that I can unsubscribe at any time", onChange: handleCaslConsentChange, defaultValue: caslConsent })), jsx(BlockSubmit$2, { className: isTheBig ? 'thebig-bold' : 'mychoice' }), jsx(BlockNextPageInfo$2, {})] }));
2004
2325
  };
@@ -3183,8 +3504,9 @@ const SectionDiscountInfo = () => {
3183
3504
  const { discountState, dispatchDiscountState } = useStoreFormHomeDiscount();
3184
3505
  // const { applicantState, dispatchApplicantInfoState } = useStoreFormHomeApplicantInfo();
3185
3506
  const { validateEmail, errorMessage } = useHandlerHomeQuoterEmail();
3507
+ const { validatePhone, errorMessage: phoneErrorMessage } = useHandlerHomeQuoterPhone();
3186
3508
  const { multiplePoliciesDiscount, emailTo: { email, emailStatus }, quoterInfo = {}, } = discountState;
3187
- const { firstName = '', lastName = '', phone = '', caslConsent } = quoterInfo;
3509
+ const { firstName = '', lastName = '', phone = '', phoneStatus, caslConsent } = quoterInfo;
3188
3510
  const handleMultiplePolicyChange = ({ value }) => {
3189
3511
  dispatchDiscountState({
3190
3512
  type: StoreFormHomeDiscountActionTypes.FormHomeDiscountMultiplePoliciesSelect,
@@ -3204,10 +3526,16 @@ const SectionDiscountInfo = () => {
3204
3526
  });
3205
3527
  };
3206
3528
  const handlePhoneNumberChange = ({ value }) => {
3207
- dispatchDiscountState({
3208
- type: StoreFormHomeDiscountActionTypes.FormHomeQuoterPhoneSet,
3209
- payload: { phone: value },
3210
- });
3529
+ const digits = value.replace(/\D/g, '');
3530
+ if (digits.length === 10) {
3531
+ validatePhone(value);
3532
+ }
3533
+ else {
3534
+ dispatchDiscountState({
3535
+ type: StoreFormHomeDiscountActionTypes.FormHomeQuoterPhoneStatusSet,
3536
+ payload: { phone: value, phoneStatus: ValidationStatusTypes.Initial },
3537
+ });
3538
+ }
3211
3539
  };
3212
3540
  const handleEmailChange = ({ value }) => {
3213
3541
  validateEmail(value);
@@ -3220,7 +3548,11 @@ const SectionDiscountInfo = () => {
3220
3548
  };
3221
3549
  return (jsxs("div", { className: `form-section ${mychoiceCls}`, children: [jsx("h2", { className: "section-title", children: "A little extra info for discounts and connecting you with our partners." }), isTheBig ? (jsx(LabelFormBox, { title: `You are seconds away from receiving your ${insuranceType} insurance quotes, please provide your email after completing the discount section so we can send you your personalized free ${insuranceType} insurance quotes!` })) : (jsx("span", { className: "info-title-message", children: `You are seconds away from receiving your ${insuranceType} insurance quotes,
3222
3550
  please provide your email after completing the discount section so we
3223
- can send you your personalized free ${insuranceType} insurance quotes!` })), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleMultiplePolicyChange, name: "multiplePoliciesDiscount", defaultValue: getSelectedOption(yesNoOptions, multiplePoliciesDiscount), title: "You could potentially save up to 18% more. Would you consider consolidating multiple policies (like auto insurance) with the same provider?", description: "Most insurers offer discounts to consumers who purchase multiple policies. Select \u2018yes\u2019 if you\u2019d like to bundle your home and auto insurance policies." }), jsx(BlockDwellingInfo, {}), jsx(InputFormBox, { name: "firstName", title: "First Name", onChange: handleFirstNameChange, defaultValue: firstName, placeholder: "Your First Name", error: !firstName && discountState.inValidation, errorMessage: getErrorMessage(firstName, discountState.inValidation) }), jsx(InputFormBox, { name: "lastName", title: "Last Name", onChange: handleLastNameChange, defaultValue: lastName, placeholder: "Your Last Name", error: !lastName && discountState.inValidation, errorMessage: getErrorMessage(lastName, discountState.inValidation) }), jsx(InputFormPhoneBox, { name: "phone", onChange: handlePhoneNumberChange, defaultValue: phone, title: "Phone Number", placeholder: "(855) 325-8444", error: !phone && discountState.inValidation, errorMessage: getErrorMessage(phone, discountState.inValidation) }), jsx(InputFormEmailBox, { validationStatus: emailStatus, name: "email", title: "Please share your email address with us, we'll use it to send you a copy of your quotes.", description: "We will provide you with your insurance quotes immediately after this form completion. If you are not ready to apply today, don\u2019t worry as we will be emailing your quotes to you if you\u2019d like to complete at a later date with the help of one of our trusted broker partners.", onChange: handleEmailChange, defaultValue: email, placeholder: getPlaceholderEmail(appType), errorMessage: emailStatus === ValidationStatusTypes.Declined
3551
+ can send you your personalized free ${insuranceType} insurance quotes!` })), jsx(SwitchButtonBox, { items: yesNoOptions, onChange: handleMultiplePolicyChange, name: "multiplePoliciesDiscount", defaultValue: getSelectedOption(yesNoOptions, multiplePoliciesDiscount), title: "You could potentially save up to 18% more. Would you consider consolidating multiple policies (like auto insurance) with the same provider?", description: "Most insurers offer discounts to consumers who purchase multiple policies. Select \u2018yes\u2019 if you\u2019d like to bundle your home and auto insurance policies." }), jsx(BlockDwellingInfo, {}), jsx(InputFormBox, { name: "firstName", title: "First Name", onChange: handleFirstNameChange, defaultValue: firstName, placeholder: "Your First Name", error: !firstName && discountState.inValidation, errorMessage: getErrorMessage(firstName, discountState.inValidation) }), jsx(InputFormBox, { name: "lastName", title: "Last Name", onChange: handleLastNameChange, defaultValue: lastName, placeholder: "Your Last Name", error: !lastName && discountState.inValidation, errorMessage: getErrorMessage(lastName, discountState.inValidation) }), jsx(InputFormPhoneBox, { name: "phone", onChange: handlePhoneNumberChange, defaultValue: phone, title: "Phone Number", placeholder: "(855) 325-8444", validationStatus: phoneStatus, error: phoneStatus === ValidationStatusTypes.Declined
3552
+ || (phoneStatus === ValidationStatusTypes.Initial && discountState.inValidation)
3553
+ || (!phone && discountState.inValidation), errorMessage: phoneStatus === ValidationStatusTypes.Declined
3554
+ ? phoneErrorMessage
3555
+ : getErrorMessage(phone, discountState.inValidation) || (discountState.inValidation ? 'Enter a valid phone number.' : '') }), jsx(InputFormEmailBox, { validationStatus: emailStatus, name: "email", title: "Please share your email address with us, we'll use it to send you a copy of your quotes.", description: "We will provide you with your insurance quotes immediately after this form completion. If you are not ready to apply today, don\u2019t worry as we will be emailing your quotes to you if you\u2019d like to complete at a later date with the help of one of our trusted broker partners.", onChange: handleEmailChange, defaultValue: email, placeholder: getPlaceholderEmail(appType), errorMessage: emailStatus === ValidationStatusTypes.Declined
3224
3556
  ? errorMessage
3225
3557
  : getErrorMessage(email, discountState.inValidation), error: emailStatus === ValidationStatusTypes.Declined || (!email && discountState.inValidation) }), isTheBig && (jsx(CheckboxForm, { className: "casl-consent", name: "caslConsent", label: "Yes, I consent to receiving emails from the Billyard Insurance Group.\n I understand that I can unsubscribe at any time", onChange: handleCaslConsentChange, defaultValue: caslConsent })), jsx(BlockSubmit$1, { className: isTheBig ? 'thebig-bold' : 'mychoice' }), jsx(BlockNextPageInfo$1, {})] }));
3226
3558
  };
@@ -3542,8 +3874,9 @@ const SectionApplicant = () => {
3542
3874
  const isTheBig = appType === AppTypes.TheBig;
3543
3875
  const { applicantState, dispatchApplicantState } = useStoreFormLifeApplicant();
3544
3876
  const { validateEmail, errorMessage } = useHandlerLifeQuoterEmail();
3877
+ const { validatePhone, errorMessage: phoneErrorMessage } = useHandlerLifeQuoterPhone();
3545
3878
  const { birthYear, birthMonth, birthDay, gender, smoker, quoterInfo, emailTo: { email, emailStatus }, inValidation, } = applicantState;
3546
- const { firstName, lastName, phone } = quoterInfo || {};
3879
+ const { firstName, lastName, phone, phoneStatus } = quoterInfo || {};
3547
3880
  const defaultDateOfBirth = {
3548
3881
  day: birthDay,
3549
3882
  month: birthMonth,
@@ -3594,10 +3927,16 @@ const SectionApplicant = () => {
3594
3927
  });
3595
3928
  };
3596
3929
  const handlePhoneNumberChange = ({ value }) => {
3597
- dispatchApplicantState({
3598
- type: StoreFormLifeApplicantActionTypes.FormLifeQuoterPhoneSet,
3599
- payload: { phone: value },
3600
- });
3930
+ const digits = value.replace(/\D/g, '');
3931
+ if (digits.length === 10) {
3932
+ validatePhone(value);
3933
+ }
3934
+ else {
3935
+ dispatchApplicantState({
3936
+ type: StoreFormLifeApplicantActionTypes.FormLifeQuoterPhoneStatusSet,
3937
+ payload: { phone: value, phoneStatus: ValidationStatusTypes.Initial },
3938
+ });
3939
+ }
3601
3940
  };
3602
3941
  const handleEmailChange = ({ value }) => {
3603
3942
  validateEmail(value);
@@ -3617,7 +3956,11 @@ const SectionApplicant = () => {
3617
3956
  textAlign: 'center',
3618
3957
  fontSize: '1.15rem',
3619
3958
  marginTop: '10px',
3620
- }, children: `Canadians have compared rates in the last 24 hours and saved ${savedPercentage}% on average` })] }), jsx("h2", { className: "section-title", style: { textAlign: 'center' }, children: `${lockEmoji} Complete the form below to see which companies are offering your quotes.` }), jsx("span", { className: "info-title-message", children: "You are seconds away from receiving your life insurance quotes, please provide your email after completing the final steps so we can send you your personalized free life insurance quotes!" }), jsx(DateSelectFormBox, { name: "dateOfBirth", dateNames: ['birthYear', 'birthMonth', 'birthDay'], onDateChange: handleDateOfBirthChange, defaultValue: defaultDateOfBirth, title: "Date of birth", error: inValidation, errorMessage: getDateErrorMessage([birthDay || '', birthMonth || '', birthYear || ''], inValidation), maxDate: subYearsFromDate('', 14), isDay: true }), jsx(SelectFormBox, { options: genderOptions, name: "gender", onChange: handleGenderChange, defaultValue: getSelectedOption(genderOptions, gender), title: "Gender", placeholder: "Select", autoSelectIfValueIsOutOfOptions: false, error: !gender && inValidation, errorMessage: getErrorMessage(`${gender}`.toString(), inValidation) }), jsx(SwitchButtonBox, { items: smokerOptions, onChange: handleSmokerChange, name: "smoker", defaultValue: getSelectedOption(smokerOptions, smoker), title: "Smoker" }), isTheBig && (jsxs("div", { className: "input-form-box-container", children: [jsx(LabelFormBox, { title: "Complete this form to see all your personalized\n quotes on the next page, you will also be able to:" }), jsxs("ol", { className: "ordered-block", children: [jsx("li", { children: "See what rates insurance carriers are offering" }), jsx("li", { children: "Get in touch with us and secure your rate" }), jsx("li", { children: "Potentially save more by speaking with a broker" })] })] })), jsx(InputFormBox, { name: "firstName", title: "First Name", onChange: handleFirstNameChange, defaultValue: firstName, placeholder: "Your First Name", error: !firstName && inValidation, errorMessage: getErrorMessage(firstName, inValidation) }), jsx(InputFormBox, { name: "lastname", title: "Last Name", onChange: handleLastNameChange, defaultValue: lastName, placeholder: "Your Last Name", error: !lastName && inValidation, errorMessage: getErrorMessage(lastName, inValidation) }), jsx(InputFormPhoneBox, { name: "phone", onChange: handlePhoneNumberChange, defaultValue: phone, title: "Phone Number", placeholder: "(855) 325-8444", error: !phone && inValidation, errorMessage: getErrorMessage(phone, inValidation) }), jsx(InputFormEmailBox, { validationStatus: emailStatus, name: "email", title: "Please provide your email address so we can send you a copy of your quotes", onChange: handleEmailChange, defaultValue: email, placeholder: getPlaceholderEmail(appType), errorMessage: emailStatus === ValidationStatusTypes.Declined
3959
+ }, children: `Canadians have compared rates in the last 24 hours and saved ${savedPercentage}% on average` })] }), jsx("h2", { className: "section-title", style: { textAlign: 'center' }, children: `${lockEmoji} Complete the form below to see which companies are offering your quotes.` }), jsx("span", { className: "info-title-message", children: "You are seconds away from receiving your life insurance quotes, please provide your email after completing the final steps so we can send you your personalized free life insurance quotes!" }), jsx(DateSelectFormBox, { name: "dateOfBirth", dateNames: ['birthYear', 'birthMonth', 'birthDay'], onDateChange: handleDateOfBirthChange, defaultValue: defaultDateOfBirth, title: "Date of birth", error: inValidation, errorMessage: getDateErrorMessage([birthDay || '', birthMonth || '', birthYear || ''], inValidation), maxDate: subYearsFromDate('', 14), isDay: true }), jsx(SelectFormBox, { options: genderOptions, name: "gender", onChange: handleGenderChange, defaultValue: getSelectedOption(genderOptions, gender), title: "Gender", placeholder: "Select", autoSelectIfValueIsOutOfOptions: false, error: !gender && inValidation, errorMessage: getErrorMessage(`${gender}`.toString(), inValidation) }), jsx(SwitchButtonBox, { items: smokerOptions, onChange: handleSmokerChange, name: "smoker", defaultValue: getSelectedOption(smokerOptions, smoker), title: "Smoker" }), isTheBig && (jsxs("div", { className: "input-form-box-container", children: [jsx(LabelFormBox, { title: "Complete this form to see all your personalized\n quotes on the next page, you will also be able to:" }), jsxs("ol", { className: "ordered-block", children: [jsx("li", { children: "See what rates insurance carriers are offering" }), jsx("li", { children: "Get in touch with us and secure your rate" }), jsx("li", { children: "Potentially save more by speaking with a broker" })] })] })), jsx(InputFormBox, { name: "firstName", title: "First Name", onChange: handleFirstNameChange, defaultValue: firstName, placeholder: "Your First Name", error: !firstName && inValidation, errorMessage: getErrorMessage(firstName, inValidation) }), jsx(InputFormBox, { name: "lastname", title: "Last Name", onChange: handleLastNameChange, defaultValue: lastName, placeholder: "Your Last Name", error: !lastName && inValidation, errorMessage: getErrorMessage(lastName, inValidation) }), jsx(InputFormPhoneBox, { name: "phone", onChange: handlePhoneNumberChange, defaultValue: phone, title: "Phone Number", placeholder: "(855) 325-8444", validationStatus: phoneStatus, error: phoneStatus === ValidationStatusTypes.Declined
3960
+ || (phoneStatus === ValidationStatusTypes.Initial && inValidation)
3961
+ || (!phone && inValidation), errorMessage: phoneStatus === ValidationStatusTypes.Declined
3962
+ ? phoneErrorMessage
3963
+ : getErrorMessage(phone, inValidation) || (inValidation ? 'Enter a valid phone number.' : '') }), jsx(InputFormEmailBox, { validationStatus: emailStatus, name: "email", title: "Please provide your email address so we can send you a copy of your quotes", onChange: handleEmailChange, defaultValue: email, placeholder: getPlaceholderEmail(appType), errorMessage: emailStatus === ValidationStatusTypes.Declined
3621
3964
  ? errorMessage
3622
3965
  : getErrorMessage(email, inValidation), error: emailStatus === ValidationStatusTypes.Declined || (!email && inValidation) }), jsx(BlockSubmit, { className: isTheBig ? 'thebig-bold' : '' }), jsx(BlockNextPageInfo, {})] }));
3623
3966
  };