@mychoice/mychoice-sdk-modules 2.2.29 → 2.2.31

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,6 +1,6 @@
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, yearlyDriveDistanceList, numberWithCommas, VehiclePrimaryUseTypes, businessUsePercentOptions, addDaysToDate, comprehensiveCoverage, collisionCoverage, maritalStatusOptions, subYearsFromDate, occupationOptions, genderOptions, applicantRelationshipOptions, addYearsToDate, checkDateIsSpecial, DriverLicenceTypes, getDifferenceInYears, getDifferenceInMonths, compareDates, yesNoOptions, getLicenceTypeOptions, getDisabledLicenceTypes, 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';
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, getDifferenceInMonths, compareDates, yesNoOptions, getLicenceTypeOptions, getDisabledLicenceTypes, addMonthsToDate, getMinDate, CheckboxForm, insuranceCancellationReasonOptions, subMonthsFromDate, getMinDateByYears, 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
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, useEffect, useCallback, useRef, useMemo } from 'react';
@@ -208,40 +208,84 @@ const BlockVehLinks = () => {
208
208
  const { vehicleState: { items: vehicles } } = useStoreFormCarVehicle();
209
209
  const { driverState: { items: drivers } } = useStoreFormCarDriverBase();
210
210
  const { discountState: { vehlinks, occVehlinks, inValidation }, dispatchDiscountState } = useStoreFormCarDiscount();
211
- // Spec: 2 drivers / 2 vehicles — ask only for Vehicle1; system assigns the other driver as PO on Vehicle2.
212
- const isTwoByTwo = drivers.length === 2 && vehicles.length === 2;
211
+ const equalCounts = drivers.length === vehicles.length;
212
+ const askedVehicleCount = equalCounts ? vehicles.length - 1 : vehicles.length;
213
213
  const assignPrimary = (driverIndex, vehicleIndex) => {
214
214
  dispatchDiscountState({
215
215
  type: StoreFormCarDiscountActionTypes.FormCarDiscountVehlinkSelect,
216
216
  payload: { driverIndex, vehicleIndex },
217
217
  });
218
218
  };
219
+ const primaryOf = (vehicleIndex) => vehlinks.find((l) => l.vehicleIndex === vehicleIndex && l.priority === DriverPriorityTypes.Prn)?.driverIndex ?? -1;
220
+ const getTwoDriverSystemAllocation = () => {
221
+ if (drivers.length !== 2 || vehicles.length !== 3)
222
+ return { driverIndex: -1, vehicleIndex: -1 };
223
+ const firstTwo = [primaryOf(0), primaryOf(1)];
224
+ if (firstTwo.some((driverIndex) => driverIndex < 0) || new Set(firstTwo).size === drivers.length) {
225
+ return { driverIndex: -1, vehicleIndex: -1 };
226
+ }
227
+ const driverIndex = drivers.findIndex((_driver, index) => !firstTwo.includes(index));
228
+ return { driverIndex, vehicleIndex: 2 };
229
+ };
219
230
  useEffect(() => {
220
- if (!isTwoByTwo)
231
+ if (!equalCounts || drivers.length <= 1)
232
+ return;
233
+ const askedDrivers = new Set();
234
+ for (let vehicleIndex = 0; vehicleIndex < askedVehicleCount; vehicleIndex += 1) {
235
+ const po = primaryOf(vehicleIndex);
236
+ if (po < 0)
237
+ return;
238
+ askedDrivers.add(po);
239
+ }
240
+ if (askedDrivers.size !== askedVehicleCount)
241
+ return;
242
+ const remainingDriver = drivers.findIndex((_, driverIndex) => !askedDrivers.has(driverIndex));
243
+ if (remainingDriver < 0)
221
244
  return;
222
- const v1 = vehlinks.find((l) => l.vehicleIndex === 0 && l.priority === DriverPriorityTypes.Prn);
223
- if (!v1 || v1.driverIndex < 0)
245
+ const lastVehicleIndex = vehicles.length - 1;
246
+ if (primaryOf(lastVehicleIndex) === remainingDriver)
247
+ return;
248
+ assignPrimary(remainingDriver, lastVehicleIndex);
249
+ }, [equalCounts, askedVehicleCount, vehlinks, drivers, vehicles]);
250
+ useEffect(() => {
251
+ const { driverIndex, vehicleIndex } = getTwoDriverSystemAllocation();
252
+ if (driverIndex >= 0 && vehicleIndex >= 0 && primaryOf(vehicleIndex) !== driverIndex) {
253
+ assignPrimary(driverIndex, vehicleIndex);
254
+ }
255
+ }, [vehlinks, drivers, vehicles]);
256
+ useEffect(() => {
257
+ if (vehicles.length <= drivers.length || drivers.length <= 1)
224
258
  return;
225
- const otherDriverIndex = drivers.findIndex((_, index) => index !== v1.driverIndex);
226
- if (otherDriverIndex < 0)
259
+ for (let vehicleIndex = 0; vehicleIndex < vehicles.length; vehicleIndex += 1) {
260
+ if (primaryOf(vehicleIndex) < 0)
261
+ return;
262
+ }
263
+ const usedDrivers = new Set(vehicles.map((_, vehicleIndex) => primaryOf(vehicleIndex)));
264
+ const unusedDriver = drivers.findIndex((_, driverIndex) => !usedDrivers.has(driverIndex));
265
+ if (unusedDriver < 0)
227
266
  return;
228
- const v2 = vehlinks.find((l) => l.vehicleIndex === 1 && l.priority === DriverPriorityTypes.Prn);
229
- if (v2?.driverIndex === otherDriverIndex)
267
+ // Target the last vehicle whose PO is a duplicate, so we never strand another driver.
268
+ const poCounts = new Map();
269
+ vehicles.forEach((_v, vehicleIndex) => {
270
+ const po = primaryOf(vehicleIndex);
271
+ poCounts.set(po, (poCounts.get(po) ?? 0) + 1);
272
+ });
273
+ let target = -1;
274
+ for (let vehicleIndex = vehicles.length - 1; vehicleIndex >= 0; vehicleIndex -= 1) {
275
+ if ((poCounts.get(primaryOf(vehicleIndex)) ?? 0) > 1) {
276
+ target = vehicleIndex;
277
+ break;
278
+ }
279
+ }
280
+ if (target < 0)
230
281
  return;
231
- assignPrimary(otherDriverIndex, 1);
232
- }, [isTwoByTwo, vehlinks, drivers]);
282
+ assignPrimary(unusedDriver, target);
283
+ }, [vehlinks, drivers, vehicles]);
233
284
  if (drivers.length <= 1) {
234
285
  return null;
235
286
  }
236
287
  const handlePrimaryDriverChange = (vehicleIndex) => ({ value }) => {
237
- const driverIndex = Number(value);
238
- assignPrimary(driverIndex, vehicleIndex);
239
- if (isTwoByTwo && vehicleIndex === 0) {
240
- const otherDriverIndex = drivers.findIndex((_, index) => index !== driverIndex);
241
- if (otherDriverIndex >= 0) {
242
- assignPrimary(otherDriverIndex, 1);
243
- }
244
- }
288
+ assignPrimary(value === '' ? -1 : Number(value), vehicleIndex);
245
289
  };
246
290
  const handleOccDriverChange = (driverIndex) => ({ value }) => {
247
291
  dispatchDiscountState({
@@ -259,24 +303,34 @@ const BlockVehLinks = () => {
259
303
  const unassignedDrivers = drivers
260
304
  .map((driver, index) => ({ driver, index }))
261
305
  .filter(({ index }) => !primaryDriverIndices.includes(index));
262
- const vehiclesToAsk = isTwoByTwo ? vehicles.slice(0, 1) : vehicles;
306
+ const vehiclesToAsk = vehicles.slice(0, askedVehicleCount);
307
+ const { vehicleIndex: systemAllocatedVehicleIndex } = getTwoDriverSystemAllocation();
308
+ const primaryQuestionsAnswered = vehiclesToAsk.every((_vehicle, vehicleIndex) => vehlinks.some((l) => l.vehicleIndex === vehicleIndex
309
+ && l.priority === DriverPriorityTypes.Prn
310
+ && l.driverIndex >= 0));
311
+ const primaryQuestionsAreUnique = new Set(primaryDriverIndices).size >= vehicles.length;
312
+ const shouldAskOccasional = drivers.length > vehicles.length
313
+ && vehicles.length > 1
314
+ && primaryQuestionsAnswered
315
+ && primaryQuestionsAreUnique;
263
316
  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." }), vehiclesToAsk.map((vehicle, vehicleIndex) => {
317
+ if (vehicleIndex === systemAllocatedVehicleIndex)
318
+ return null;
264
319
  const { year, make, model } = vehicle;
265
320
  const selectedPrimary = vehlinks.find((l) => l.vehicleIndex === vehicleIndex && l.priority === DriverPriorityTypes.Prn);
266
321
  const isPrimaryAnswered = selectedPrimary !== undefined && selectedPrimary.driverIndex >= 0;
267
- // Show all drivers so the user can freely reselect / re-order primaries.
322
+ const previousPrimaryDriverIndices = new Set(vehlinks
323
+ .filter((l) => l.vehicleIndex < vehicleIndex
324
+ && l.priority === DriverPriorityTypes.Prn
325
+ && l.driverIndex >= 0)
326
+ .map((l) => l.driverIndex));
327
+ const canRepeatPrimary = vehicles.length > drivers.length;
268
328
  const primaryOptions = drivers
269
- .map((driver, driverIndex) => ({ name: driver.firstName, value: driverIndex }));
270
- const isDuplicatePrimary = !isTwoByTwo
271
- && isPrimaryAnswered
272
- && drivers.length >= vehicles.length
273
- && vehlinks.some((l) => l.vehicleIndex !== vehicleIndex
274
- && l.priority === DriverPriorityTypes.Prn
275
- && l.driverIndex === selectedPrimary?.driverIndex);
276
- return (jsx(SelectFormBox, { title: `Who is the principal driver of the ${year} ${make} ${model}?`, onChange: handlePrimaryDriverChange(vehicleIndex), options: primaryOptions, defaultValue: isPrimaryAnswered ? selectedPrimary.driverIndex : '', name: `vehlink-${vehicleIndex}`, placeholder: "Select from the list", autoSelectIfValueIsOutOfOptions: false, error: (!isPrimaryAnswered && inValidation) || isDuplicatePrimary, errorMessage: isDuplicatePrimary
277
- ? 'This driver is already the primary driver of another vehicle. Each vehicle should have a different primary driver.'
278
- : '' }, `vehlink-${vehicleIndex}`));
279
- }), drivers.length > vehicles.length && vehicles.length > 1
329
+ .map((driver, driverIndex) => ({ name: driver.firstName, value: driverIndex }))
330
+ .filter(({ value }) => canRepeatPrimary
331
+ || !previousPrimaryDriverIndices.has(value));
332
+ return (jsx(SelectFormBox, { title: `Who is the principal driver of the ${year} ${make} ${model}?`, onChange: handlePrimaryDriverChange(vehicleIndex), options: primaryOptions, defaultValue: isPrimaryAnswered ? selectedPrimary.driverIndex : '', name: `vehlink-${vehicleIndex}`, placeholder: "Select from the list", autoSelectIfValueIsOutOfOptions: false, error: !isPrimaryAnswered && inValidation }, `vehlink-${vehicleIndex}`));
333
+ }), shouldAskOccasional
280
334
  && unassignedDrivers.map(({ driver, index: driverIndex }) => {
281
335
  const selectedVehicle = occVehlinks.find((l) => l.driverIndex === driverIndex);
282
336
  const vehicleOptions = vehicles.map((vehicle, vehicleIndex) => ({
@@ -1214,6 +1268,10 @@ const SectionDriverInfo = () => {
1214
1268
  month: birthMonth,
1215
1269
  year: birthYear,
1216
1270
  };
1271
+ const policyEffectiveDate = discountState.policyStartYear && discountState.policyStartMonth
1272
+ && discountState.policyStartDay
1273
+ ? `${discountState.policyStartYear}-${discountState.policyStartMonth}-${discountState.policyStartDay}`
1274
+ : discountState.policyStart;
1217
1275
  useEffect(() => {
1218
1276
  if (discountState.quoterInfo.firstName !== driverState.items[0].firstName) {
1219
1277
  dispatchDiscountState({
@@ -1238,19 +1296,19 @@ const SectionDriverInfo = () => {
1238
1296
  if (dateType === DateTypes.Day) {
1239
1297
  dispatchDriverInfoState({
1240
1298
  type: StoreFormCarDriverInfoActionTypes.FormCarDriverBirthDaySelect,
1241
- payload: { birthDay: value, config: configState },
1299
+ payload: { birthDay: value, config: configState, appType },
1242
1300
  });
1243
1301
  }
1244
1302
  if (dateType === DateTypes.Month) {
1245
1303
  dispatchDriverInfoState({
1246
1304
  type: StoreFormCarDriverInfoActionTypes.FormCarDriverBirthMonthSelect,
1247
- payload: { birthMonth: value, config: configState },
1305
+ payload: { birthMonth: value, config: configState, appType },
1248
1306
  });
1249
1307
  }
1250
1308
  if (dateType === DateTypes.Year) {
1251
1309
  dispatchDriverInfoState({
1252
1310
  type: StoreFormCarDriverInfoActionTypes.FormCarDriverBirthYearSelect,
1253
- payload: { birthYear: value, config: configState },
1311
+ payload: { birthYear: value, config: configState, appType },
1254
1312
  });
1255
1313
  }
1256
1314
  };
@@ -1272,11 +1330,13 @@ const SectionDriverInfo = () => {
1272
1330
  payload: { applicantRelationship: value },
1273
1331
  });
1274
1332
  };
1275
- 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) }))] }));
1333
+ 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(policyEffectiveDate, 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) }))] }));
1276
1334
  };
1277
1335
 
1278
1336
  // Max months between consecutive Ontario GDL licence classes (spec 1-2 e/f)
1279
1337
  const ON_MAX_MONTHS_BETWEEN_CLASSES = 60;
1338
+ const ON_MIN_MONTHS_G1_TO_G2 = 8;
1339
+ const ON_MIN_MONTHS_G1_TO_G = 20;
1280
1340
  const SectionDriverLicence = () => {
1281
1341
  const { appConfigState: { appType }, } = useStoreAppConfig();
1282
1342
  const [driverEducation, setDriverEducation] = useState(false);
@@ -1302,7 +1362,11 @@ const SectionDriverLicence = () => {
1302
1362
  ? (!!ontarioQ1Date && checkDateIsSpecial(ontarioQ1Date, configState.minDates.g.specialDate))
1303
1363
  : checkDateIsSpecial(defaultMinDate, configState.minDates.g.specialDate);
1304
1364
  const driverName = firstName || driverNameDefault;
1365
+ const { policyStart, policyStartYear, policyStartMonth, policyStartDay, } = discountState;
1305
1366
  const today = getFormattedDate('', 'yyyy-MM-dd');
1367
+ const policyEffectiveDate = policyStartYear && policyStartMonth && policyStartDay
1368
+ ? `${policyStartYear}-${policyStartMonth}-${policyStartDay}`
1369
+ : policyStart || today;
1306
1370
  const { g, g1, g2, minLicenceAge } = configState.licenceConfig;
1307
1371
  const licenceTypeOptions = [
1308
1372
  { value: g.name, name: g.title },
@@ -1338,36 +1402,6 @@ const SectionDriverLicence = () => {
1338
1402
  }
1339
1403
  }
1340
1404
  }, [g2LicenceYear, g2LicenceMonth, licenceType, useOntarioFlow]);
1341
- // If the user picks their birth month in their 16th year and birthDay > 1,
1342
- // selecting that month would imply a date before their actual birthday (since dates are assumed
1343
- // as the 1st). Auto-advance the Q1 month to birthMonth + 1.
1344
- useEffect(() => {
1345
- if (!useOntarioFlow || !birthDate || !ontarioQ1Year || !ontarioQ1Month)
1346
- return;
1347
- const birthDayNum = parseInt(birthDay || '1', 10);
1348
- if (birthDayNum <= 1)
1349
- return;
1350
- const birthYearNum = parseInt(birthYear || '0', 10);
1351
- if (parseInt(ontarioQ1Year, 10) !== birthYearNum + 16 || ontarioQ1Month !== birthMonth)
1352
- return;
1353
- const q1SlotForCorrection = DriverLicenceTypes.G1;
1354
- let correctedMonth = parseInt(birthMonth || '1', 10) + 1;
1355
- let correctedYear = birthYearNum + 16;
1356
- if (correctedMonth > 12) {
1357
- correctedMonth = 1;
1358
- correctedYear += 1;
1359
- }
1360
- dispatchDriverLicenceState({
1361
- type: StoreFormCarDriverLicenceActionTypes.FormCarDriverLicenceMonthSelect,
1362
- payload: { value: String(correctedMonth).padStart(2, '0'), config: configState, type: q1SlotForCorrection },
1363
- });
1364
- if (correctedYear !== birthYearNum + 16) {
1365
- dispatchDriverLicenceState({
1366
- type: StoreFormCarDriverLicenceActionTypes.FormCarDriverLicenceYearSelect,
1367
- payload: { value: String(correctedYear), config: configState, type: q1SlotForCorrection },
1368
- });
1369
- }
1370
- }, [ontarioQ1Year, ontarioQ1Month]);
1371
1405
  // ── helpers ────────────────────────────────────────────────
1372
1406
  const getMinDate = (type) => {
1373
1407
  switch (type) {
@@ -1408,11 +1442,11 @@ const SectionDriverLicence = () => {
1408
1442
  });
1409
1443
  // Build a YYYY-MM-01 string from stored year/month, returns '' if either missing
1410
1444
  const toDate = (year, month) => (year && month ? `${year}-${month}-01` : '');
1411
- const validateLicenceDate = (year, month, minDate) => {
1412
- const dateStr = toDate(year, month);
1445
+ const validateLicenceDate = (year, month, minDate, dateOverride) => {
1446
+ const dateStr = dateOverride || toDate(year, month);
1413
1447
  if (!dateStr)
1414
1448
  return '';
1415
- if (compareDates(dateStr, today) > 0)
1449
+ if (compareDates(dateStr, policyEffectiveDate) > 0)
1416
1450
  return 'License dates cannot be in the future';
1417
1451
  if (minDate && compareDates(dateStr, minDate) < 0) {
1418
1452
  return 'This license date must be equal or later than the prior license date. Please check your selection';
@@ -1431,11 +1465,11 @@ const SectionDriverLicence = () => {
1431
1465
  return '';
1432
1466
  };
1433
1467
  // In the Ontario flow, firstLicenceAge is never entered, so gOneMin is stale/empty.
1434
- // Compute min from DOB + 16, capped to today so minDate never exceeds maxDate.
1468
+ // Compute the minimum from DOB + 16 and validate it against the policy effective date.
1435
1469
  const getG1MinDate = () => {
1436
1470
  if (useOntarioFlow && birthDate) {
1437
1471
  const computed = addYearsToDate(birthDate, 16);
1438
- return compareDates(computed, today) > 0 ? today : computed;
1472
+ return compareDates(computed, policyEffectiveDate) > 0 ? policyEffectiveDate : computed;
1439
1473
  }
1440
1474
  return gOneMin;
1441
1475
  };
@@ -1513,18 +1547,30 @@ const SectionDriverLicence = () => {
1513
1547
  const q1Year = getLicenceYear(q1SlotType);
1514
1548
  const q1Month = getLicenceMonth(q1SlotType);
1515
1549
  const q1Date = toDate(q1Year, q1Month);
1550
+ const g2Date = toDate(g2LicenceYear, g2LicenceMonth);
1551
+ const gDate = toDate(gLicenceYear, gLicenceMonth);
1552
+ // Thresholds per the licensing flow: G1 < 5 years (4y11m = 59 months); G2/G < 3 years (2y11m = 35 months).
1553
+ const q1BirthdayDate = birthDate
1554
+ && q1Year === String(Number(birthYear) + 16)
1555
+ && q1Month === birthMonth
1556
+ ? `${q1Year}-${birthMonth}-${birthDay}`
1557
+ : q1Date;
1558
+ const q1MonthsFromEffective = q1BirthdayDate
1559
+ ? getDifferenceInMonths(policyEffectiveDate, q1BirthdayDate)
1560
+ : Infinity;
1561
+ // A G2 requires at least 8 months after G1; a G requires another 12 months.
1562
+ const canHaveG2 = !!q1Date && q1MonthsFromEffective >= ON_MIN_MONTHS_G1_TO_G2;
1563
+ const canHaveG = !!q1Date && q1MonthsFromEffective >= ON_MIN_MONTHS_G1_TO_G;
1516
1564
  // ── path booleans ──
1517
- const showG2Date = firstClass === DriverLicenceTypes.G1 && receivedG2 === true;
1565
+ const showG2Question = firstClass === DriverLicenceTypes.G1 && canHaveG2;
1566
+ const showG2Date = showG2Question && receivedG2 === true;
1518
1567
  // G question shows after G2 date entered (G1→G2 path) OR after No-G2 answer (G1→No G2 path)
1519
1568
  const showGQuestionAfterG1 = firstClass === DriverLicenceTypes.G1
1569
+ && canHaveG
1520
1570
  && (receivedG2 === false || showG2Date);
1571
+ const showGQuestionAfterG2 = firstClass === DriverLicenceTypes.G2 && canHaveG;
1521
1572
  const showGDateAfterG1 = showGQuestionAfterG1 && receivedG === true;
1522
- const showGDateAfterG2 = firstClass === DriverLicenceTypes.G2 && receivedG === true;
1523
- const g2Date = toDate(g2LicenceYear, g2LicenceMonth);
1524
- const gDate = toDate(gLicenceYear, gLicenceMonth);
1525
- // Thresholds per the licensing flow: G1 < 5 years (4y11m = 59 months); G2/G < 3 years (2y11m = 35 months).
1526
- const policyStart = discountState.policyStart || today;
1527
- const q1MonthsFromEffective = q1Date ? getDifferenceInMonths(policyStart, q1Date) : Infinity;
1573
+ const showGDateAfterG2 = showGQuestionAfterG2 && receivedG === true;
1528
1574
  // G1 branch: ask once, based on the first licence date (< 5 years / 60 months).
1529
1575
  const showDtcG1Only = firstClass === DriverLicenceTypes.G1
1530
1576
  && !!q1Date
@@ -1540,39 +1586,46 @@ const SectionDriverLicence = () => {
1540
1586
  // ── Validation error messages ──
1541
1587
  const q1MinDate = getG1MinDate();
1542
1588
  const q1ChronoError = driverState.inValidation
1543
- ? validateLicenceDate(q1Year, q1Month, q1MinDate)
1589
+ ? validateLicenceDate(q1Year, q1Month, q1MinDate, q1BirthdayDate)
1544
1590
  : '';
1545
- const q1FutureError = q1Date && compareDates(q1Date, today) > 0
1591
+ const q1FutureError = q1BirthdayDate && compareDates(q1BirthdayDate, policyEffectiveDate) > 0
1546
1592
  ? 'License dates cannot be in the future' : '';
1547
1593
  const q1Error = q1FutureError || q1ChronoError || getDateErrorMessage(['01', q1Month, q1Year], driverState.inValidation);
1548
1594
  const g2ChronoError = driverState.inValidation
1549
- ? validateLicenceDate(g2LicenceYear, g2LicenceMonth, q1Date)
1595
+ ? validateLicenceDate(g2LicenceYear, g2LicenceMonth, q1BirthdayDate)
1550
1596
  : '';
1551
- const g260MonthError = validate60Months(q1Year, q1Month, g2LicenceYear, g2LicenceMonth);
1552
- const g2FutureError = g2Date && compareDates(g2Date, today) > 0 ? 'License dates cannot be in the future' : '';
1597
+ const g260MonthError = validate60Months(q1BirthdayDate?.slice(0, 4), q1BirthdayDate?.slice(5, 7), g2LicenceYear, g2LicenceMonth);
1598
+ const g2FutureError = g2Date && compareDates(g2Date, policyEffectiveDate) > 0 ? 'License dates cannot be in the future' : '';
1553
1599
  const g2Error = g2FutureError || g260MonthError || g2ChronoError || getDateErrorMessage(['01', g2LicenceMonth, g2LicenceYear], driverState.inValidation);
1554
1600
  // G preceding date: G2 date if on G1→G2→G path, else Q1 date
1555
- const gPrecedingDate = showGDateAfterG1 && showG2Date ? g2Date : q1Date;
1601
+ const gPrecedingDate = showGDateAfterG1 && showG2Date ? g2Date : q1BirthdayDate;
1556
1602
  const gChronoError = driverState.inValidation
1557
1603
  ? validateLicenceDate(gLicenceYear, gLicenceMonth, gPrecedingDate)
1558
1604
  : '';
1559
- const g60MonthError = validate60Months(q1Year, q1Month, gLicenceYear, gLicenceMonth);
1560
- const gFutureError = gDate && compareDates(gDate, today) > 0 ? 'License dates cannot be in the future' : '';
1605
+ const g60MonthError = validate60Months(q1BirthdayDate?.slice(0, 4), q1BirthdayDate?.slice(5, 7), gLicenceYear, gLicenceMonth);
1606
+ const gFutureError = gDate && compareDates(gDate, policyEffectiveDate) > 0 ? 'License dates cannot be in the future' : '';
1561
1607
  const gError = gFutureError || g60MonthError || gChronoError || getDateErrorMessage(['01', gLicenceMonth, gLicenceYear], driverState.inValidation);
1562
- // ── Min dates (always capped to today so minDate never exceeds maxDate) ──
1563
- const g2MinRaw = q1Date && compareDates(q1Date, gTwoMin) > 0 ? q1Date : gTwoMin;
1564
- const g2MinDate = compareDates(g2MinRaw, today) > 0 ? today : g2MinRaw;
1608
+ // ── Min dates (capped to the policy effective date so a future policy remains selectable) ──
1609
+ const g2MinRaw = q1BirthdayDate && compareDates(q1BirthdayDate, gTwoMin) > 0 ? q1BirthdayDate : gTwoMin;
1610
+ const g2MinDate = compareDates(g2MinRaw, policyEffectiveDate) > 0 ? policyEffectiveDate : g2MinRaw;
1565
1611
  const gMinRaw = gPrecedingDate && compareDates(gPrecedingDate, gMin) > 0 ? gPrecedingDate : gMin;
1566
- const gMinDate = compareDates(gMinRaw, today) > 0 ? today : gMinRaw;
1612
+ const gMinDate = compareDates(gMinRaw, policyEffectiveDate) > 0 ? policyEffectiveDate : gMinRaw;
1613
+ const getMonthPickerMinDate = (minDate) => {
1614
+ if (!minDate || getFormattedDate(minDate, 'dd') === '01')
1615
+ return minDate;
1616
+ return addMonthsToDate(minDate, 1);
1617
+ };
1618
+ const g2PickerMinDate = getMonthPickerMinDate(g2MinDate);
1619
+ const gPickerMinDate = getMonthPickerMinDate(gMinDate);
1567
1620
  const getMax60Date = (refDate) => {
1568
1621
  if (!refDate)
1569
- return today;
1622
+ return policyEffectiveDate;
1570
1623
  const max60 = addMonthsToDate(refDate, ON_MAX_MONTHS_BETWEEN_CLASSES);
1571
- return compareDates(today, max60) > 0 ? max60 : today;
1624
+ return compareDates(policyEffectiveDate, max60) > 0 ? max60 : policyEffectiveDate;
1572
1625
  };
1573
- const g2MaxDate = getMax60Date(q1Date);
1574
- const gMaxDate = getMax60Date(q1Date);
1575
- 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, firstClass), title: "What class of license was it?", placeholder: "Select from the list", 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 5 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)." })] }));
1626
+ const g2MaxDate = getMax60Date(q1BirthdayDate);
1627
+ const gMaxDate = getMax60Date(q1BirthdayDate);
1628
+ 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: policyEffectiveDate, disabled: !birthDate }), q1Date && (jsx(SelectFormBox, { options: isOnlyG ? ontarioOnlyGOptions : ontarioFirstClassOptions, name: "firstLicenceClass", onChange: handleLicenceTypeChange, defaultValue: getSelectedOption(isOnlyG ? ontarioOnlyGOptions : ontarioFirstClassOptions, firstClass), title: "What class of license was it?", placeholder: "Select from the list", 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?` })), showG2Question && (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: g2PickerMinDate, 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: gPickerMinDate, 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?` })), showGQuestionAfterG2 && (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: gPickerMinDate, 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)." })] }));
1576
1629
  }
1577
1630
  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
1578
1631
  ? `${driverName} was licenced in ${Number(birthYear) + Number(firstLicenceAge)} - ${Number(birthYear) + Number(firstLicenceAge) + 1}`
@@ -1760,7 +1813,7 @@ you had insurance. If this is correct, please continue with the form.`);
1760
1813
  const firstInsuredMinDate = listedYear && listedMonth
1761
1814
  ? addDaysToDate(`${listedYear}-${listedMonth}-01`, birthDay ? +birthDay + 1 : 1)
1762
1815
  : getMinDate(birthDate, firstLicenceAge);
1763
- const twentyYearsAgo = getMinDateByYears(getFormattedDate('', 'yyyy-MM-dd'), 20);
1816
+ const twentyYearsAgo = subYearsFromDate('', 20);
1764
1817
  let lastPolicyEndMinDate = twentyYearsAgo;
1765
1818
  if (firstInsuredMinDate && compareDates(firstInsuredMinDate, twentyYearsAgo) > 0) {
1766
1819
  lastPolicyEndMinDate = firstInsuredMinDate;