@alma/widgets 2.2.10 → 2.3.2

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.
@@ -1506,7 +1506,7 @@ var messagesDE = {
1506
1506
  "payment-plan-strings.deferred": "{totalAmount} zu zahlen am {dueDate}",
1507
1507
  "payment-plan-strings.ineligible-greater-than-max": "Bis zu {maxAmount}",
1508
1508
  "payment-plan-strings.ineligible-lower-than-min": "Ab {minAmount}",
1509
- "payment-plan-strings.multiple-installments": "{firstInstallmentAmount} dann {numberOfRemainingInstallments} x {othersInstallmentAmount}",
1509
+ "payment-plan-strings.multiple-installments": "{numberOfRemainingInstallments, plural, one {{firstInstallmentAmount} dann {numberOfRemainingInstallments} x {othersInstallmentAmount}} other {{firstInstallmentAmount} dann {numberOfRemainingInstallments} x {othersInstallmentAmount}}}",
1510
1510
  "payment-plan-strings.multiple-installments-same-amount": "{installmentsCount} x {totalAmount}",
1511
1511
  "payment-plan-strings.no-fee": "(gebührenfrei)"
1512
1512
  };
@@ -1528,7 +1528,7 @@ var messagesEN = {
1528
1528
  "payment-plan-strings.deferred": "{totalAmount} to be paid on {dueDate}",
1529
1529
  "payment-plan-strings.ineligible-greater-than-max": "Until {maxAmount}",
1530
1530
  "payment-plan-strings.ineligible-lower-than-min": "From {minAmount}",
1531
- "payment-plan-strings.multiple-installments": "{firstInstallmentAmount} then {numberOfRemainingInstallments} x {othersInstallmentAmount}",
1531
+ "payment-plan-strings.multiple-installments": "{numberOfRemainingInstallments, plural, one {{firstInstallmentAmount} then {numberOfRemainingInstallments} x {othersInstallmentAmount}} other {{firstInstallmentAmount} then {numberOfRemainingInstallments} x {othersInstallmentAmount}}}",
1532
1532
  "payment-plan-strings.multiple-installments-same-amount": "{installmentsCount} x {totalAmount}",
1533
1533
  "payment-plan-strings.no-fee": "(free of charge)"
1534
1534
  };
@@ -1550,7 +1550,7 @@ var messagesES = {
1550
1550
  "payment-plan-strings.deferred": "{totalAmount} a pagar el {dueDate}",
1551
1551
  "payment-plan-strings.ineligible-greater-than-max": "Hasta {maxAmount}",
1552
1552
  "payment-plan-strings.ineligible-lower-than-min": "Desde {minAmount}",
1553
- "payment-plan-strings.multiple-installments": "{firstInstallmentAmount} hoy, después {numberOfRemainingInstallments, plural, one {# mensualidad} other {# mensualidades}} de {othersInstallmentAmount}",
1553
+ "payment-plan-strings.multiple-installments": "{numberOfRemainingInstallments, plural, one {{firstInstallmentAmount} hoy, después {numberOfRemainingInstallments} mensualidad de {othersInstallmentAmount}} other {{firstInstallmentAmount} hoy, después {numberOfRemainingInstallments} mensualidades de {othersInstallmentAmount}}}",
1554
1554
  "payment-plan-strings.multiple-installments-same-amount": "{installmentsCount} plazos de {totalAmount}",
1555
1555
  "payment-plan-strings.no-fee": "(sin intereses)"
1556
1556
  };
@@ -1572,7 +1572,7 @@ var messagesFR = {
1572
1572
  "payment-plan-strings.deferred": "{totalAmount} à payer le {dueDate}",
1573
1573
  "payment-plan-strings.ineligible-greater-than-max": "Jusqu'à {maxAmount}",
1574
1574
  "payment-plan-strings.ineligible-lower-than-min": "À partir de {minAmount}",
1575
- "payment-plan-strings.multiple-installments": "{firstInstallmentAmount} puis {numberOfRemainingInstallments} x {othersInstallmentAmount}",
1575
+ "payment-plan-strings.multiple-installments": "{numberOfRemainingInstallments, plural, one {{firstInstallmentAmount} puis {numberOfRemainingInstallments} x {othersInstallmentAmount}} other {{firstInstallmentAmount} puis {numberOfRemainingInstallments} x {othersInstallmentAmount}}}",
1576
1576
  "payment-plan-strings.multiple-installments-same-amount": "{installmentsCount} x {totalAmount}",
1577
1577
  "payment-plan-strings.no-fee": "(sans frais)"
1578
1578
  };
@@ -1594,7 +1594,7 @@ var messagesIT = {
1594
1594
  "payment-plan-strings.deferred": "{totalAmount} da pagare il {dueDate}",
1595
1595
  "payment-plan-strings.ineligible-greater-than-max": "Disponibile fino a {maxAmount}",
1596
1596
  "payment-plan-strings.ineligible-lower-than-min": "Pagamento rateale disponibile a partire da {minAmount}",
1597
- "payment-plan-strings.multiple-installments": "Oggi paghi {firstInstallmentAmount} poi {numberOfRemainingInstallments} rate mensili di {othersInstallmentAmount}",
1597
+ "payment-plan-strings.multiple-installments": "{numberOfRemainingInstallments, plural, one {Oggi paghi {firstInstallmentAmount} poi tra {numberOfRemainingInstallments} mese {othersInstallmentAmount}} other {Oggi paghi {firstInstallmentAmount} poi {numberOfRemainingInstallments} rate mensili di {othersInstallmentAmount}}}",
1598
1598
  "payment-plan-strings.multiple-installments-same-amount": "In {installmentsCount} rate mensili di {totalAmount}",
1599
1599
  "payment-plan-strings.no-fee": "(senza interessi)"
1600
1600
  };
@@ -1602,7 +1602,7 @@ var messagesIT = {
1602
1602
  var messagesNL = {
1603
1603
  "eligibility-modal.bullet-1": "Kies <strong>Alma</strong> bij het afrekenen.",
1604
1604
  "eligibility-modal.bullet-2": "Vul de <strong>gevraagde informatie</strong> in.",
1605
- "eligibility-modal.bullet-3": "Validatie van uw betaling <strong>onmiddellijk</strong>!",
1605
+ "eligibility-modal.bullet-3": "Onmiddelijke validatie van uw betaling ",
1606
1606
  "eligibility-modal.cost": "Waarvan kosten",
1607
1607
  "eligibility-modal.credit-commitment": "Een lening bindt je en moet worden terugbetaald. Ga na of u kunt terugbetalen voordat u zich vastlegt.",
1608
1608
  "eligibility-modal.credit-cost": "Waarvan kosten van krediet",
@@ -1616,7 +1616,7 @@ var messagesNL = {
1616
1616
  "payment-plan-strings.deferred": "{totalAmount} te betalen op {dueDate}",
1617
1617
  "payment-plan-strings.ineligible-greater-than-max": "Tot {maxAmount}",
1618
1618
  "payment-plan-strings.ineligible-lower-than-min": "Van {minAmount}",
1619
- "payment-plan-strings.multiple-installments": "{firstInstallmentAmount} dan {numberOfRemainingInstallments} x {othersInstallmentAmount}",
1619
+ "payment-plan-strings.multiple-installments": "{numberOfRemainingInstallments, plural, one {{firstInstallmentAmount} dan {numberOfRemainingInstallments} x {othersInstallmentAmount}} other {{firstInstallmentAmount} dan {numberOfRemainingInstallments} x {othersInstallmentAmount}}}",
1620
1620
  "payment-plan-strings.multiple-installments-same-amount": "{installmentsCount} x {totalAmount}",
1621
1621
  "payment-plan-strings.no-fee": "(gratis)"
1622
1622
  };
@@ -1703,7 +1703,9 @@ async function fetchFromApi(url = '', data, headers) {
1703
1703
 
1704
1704
  const filterELigibility = (eligibilities, configPlans) => {
1705
1705
  // Remove p1x
1706
- const filteredEligibilityPlans = eligibilities.filter(plan => !(plan.installments_count === 1 && plan.deferred_days === 0 && plan.deferred_months === 0)); // If no configPlans was provided, return eligibility response
1706
+ const filteredEligibilityPlans = eligibilities.filter(plan => !(plan.installments_count === 1 && plan.deferred_days === 0 && plan.deferred_months === 0)) // Keeps the plans that have a payment_plan property
1707
+ .filter(plan => plan.payment_plan) // Remove plans that have a reasons property
1708
+ .filter(plan => !plan.reasons); // If no configPlans was provided, return eligibility response
1707
1709
 
1708
1710
  if (!configPlans) {
1709
1711
  return filteredEligibilityPlans;
@@ -1744,8 +1746,8 @@ const useFetchEligibility = (purchaseAmount, {
1744
1746
  }, {
1745
1747
  Authorization: `Alma-Merchant-Auth ${merchantId}`
1746
1748
  }).then(res => {
1747
- setStatus(apiStatus.SUCCESS);
1748
1749
  setEligibility(res);
1750
+ setStatus(apiStatus.SUCCESS);
1749
1751
  }).catch(() => {
1750
1752
  setStatus(apiStatus.FAILED);
1751
1753
  });
@@ -1927,7 +1929,7 @@ const paymentPlanInfoText = payment => {
1927
1929
 
1928
1930
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(FormattedMessage, {
1929
1931
  id: "payment-plan-strings.multiple-installments",
1930
- defaultMessage: "{firstInstallmentAmount} puis {numberOfRemainingInstallments} x {othersInstallmentAmount}",
1932
+ defaultMessage: "{numberOfRemainingInstallments, plural, one {{firstInstallmentAmount} puis {numberOfRemainingInstallments} x {othersInstallmentAmount}} other {{firstInstallmentAmount} puis {numberOfRemainingInstallments} x {othersInstallmentAmount}}}",
1931
1933
  values: {
1932
1934
  firstInstallmentAmount: /*#__PURE__*/React.createElement(FormattedNumber, {
1933
1935
  value: priceFromCents(payment.payment_plan[0].total_amount),
@@ -2257,37 +2259,106 @@ const useButtonAnimation = (iterateValues, transitionDelay) => {
2257
2259
  };
2258
2260
  };
2259
2261
 
2260
- var s$b = {"widgetButton":"_TSkFv","logo":"_LJ4nZ","primaryContainer":"_bMClc","paymentPlans":"_17c_S","plan":"_2Kqjn","active":"_3dG_J","notEligible":"_3O1bg","info":"_25GrF","loader":"_30j1O","error":"_R0YlN","errorText":"_2kGhu","errorButton":"_73d_Y","pending":"_1ZDMS"};
2262
+ /**
2263
+ * It returns the **index** of the **first eligible plan** that matches the default installments count
2264
+ *
2265
+ * @param {number | number[]} suggestedPaymentPlan
2266
+ * @param {EligibilityPlan[]} eligibilityPlans
2267
+ * @returns number (index of the first eligible plan that matches the default installments count)
2268
+ */
2269
+ const getIndexOfActivePlan = ({
2270
+ suggestedPaymentPlan,
2271
+ eligibilityPlans
2272
+ }) => {
2273
+ const suggestedPaymentPlanArray = Array.isArray(suggestedPaymentPlan) ? suggestedPaymentPlan : [suggestedPaymentPlan];
2274
+
2275
+ for (const index in suggestedPaymentPlanArray) {
2276
+ const installmentsCount = suggestedPaymentPlanArray[index];
2277
+ const planFound = eligibilityPlans.findIndex(plan => {
2278
+ return plan.installments_count === installmentsCount && plan.eligible;
2279
+ });
2280
+
2281
+ if (planFound !== -1) {
2282
+ return planFound;
2283
+ }
2284
+ }
2285
+
2286
+ return 0;
2287
+ };
2288
+
2289
+ var s$b = {"widgetButton":"_TSkFv","logo":"_LJ4nZ","primaryContainer":"_bMClc","paymentPlans":"_17c_S","plan":"_2Kqjn","active":"_3dG_J","notEligible":"_3O1bg","info":"_25GrF","loader":"_30j1O","error":"_R0YlN","errorText":"_2kGhu","errorButton":"_73d_Y","pending":"_1ZDMS","clickable":"_UksZa","unClickable":"_1lr-q"};
2290
+
2291
+ const VERY_LONG_TIME_IN_MS = 1000 * 3600 * 24 * 365;
2292
+ const DEFAULT_TRANSITION_TIME = 5500;
2261
2293
 
2262
2294
  const PaymentPlanWidget = ({
2263
2295
  purchaseAmount,
2264
2296
  apiData,
2265
2297
  configPlans,
2266
2298
  transitionDelay,
2267
- hideIfNotEligible
2299
+ hideIfNotEligible,
2300
+ suggestedPaymentPlan
2268
2301
  }) => {
2269
2302
  const [eligibilityPlans, status] = useFetchEligibility(purchaseAmount, apiData, configPlans);
2270
2303
  const eligiblePlans = eligibilityPlans.filter(plan => plan.eligible);
2304
+ const activePlanIndex = getIndexOfActivePlan({
2305
+ eligibilityPlans,
2306
+ suggestedPaymentPlan: suggestedPaymentPlan != null ? suggestedPaymentPlan : 0
2307
+ });
2308
+ const isSuggestedPaymentPlanSpecified = suggestedPaymentPlan !== undefined; // 👈 The merchant decided to focus a tab and remove animated transition.
2309
+
2310
+ const isTransitionSpecified = transitionDelay !== undefined; // 👈 The merchant has specified a transition time
2311
+
2271
2312
  const [isOpen, setIsOpen] = useState(false);
2272
- const [initialPlanIndex, setInitialPlanIndex] = useState(0);
2273
2313
 
2274
2314
  const openModal = () => setIsOpen(true);
2275
2315
 
2276
2316
  const closeModal = () => setIsOpen(false);
2277
2317
 
2278
2318
  const eligiblePlanKeys = eligibilityPlans.reduce((acc, plan, index) => plan.eligible ? [...acc, index] : acc, []);
2319
+ /**
2320
+ * If merchand specify a suggestedPaymentPlan and no transition, we set a very long transition delay.
2321
+ * Otherwise, we set the transition delay specified by the merchant.
2322
+ * If none of those properties are specified, we set a default transition delay.
2323
+ * @returns
2324
+ */
2325
+
2326
+ const realTransitionTime = () => {
2327
+ if (isTransitionSpecified) {
2328
+ return transitionDelay != null ? transitionDelay : DEFAULT_TRANSITION_TIME;
2329
+ }
2330
+
2331
+ if (isSuggestedPaymentPlanSpecified) {
2332
+ return VERY_LONG_TIME_IN_MS;
2333
+ }
2334
+
2335
+ return DEFAULT_TRANSITION_TIME;
2336
+ };
2337
+
2279
2338
  const {
2280
2339
  current,
2281
2340
  onHover,
2282
2341
  onLeave
2283
- } = useButtonAnimation(eligiblePlanKeys, transitionDelay ? transitionDelay : 5500); // This hook is needed to update the initial plan index when useButtonAnimation
2284
- // updates the `current` value (i.e. without any hover / click callback).
2285
-
2342
+ } = useButtonAnimation(eligiblePlanKeys, realTransitionTime());
2286
2343
  useEffect(() => {
2287
- if (current !== initialPlanIndex) {
2288
- setInitialPlanIndex(current);
2344
+ // When API has given a response AND the marchand set an active plan by default.
2345
+ if (status === apiStatus.SUCCESS && isSuggestedPaymentPlanSpecified) {
2346
+ onHover(activePlanIndex); // We select the first active plan possible
2347
+
2348
+ onLeave(); // We need to call onLeave to reset the animation
2289
2349
  }
2290
- }, [current, initialPlanIndex]);
2350
+ }, [status]);
2351
+ /**
2352
+ * It takes a plan index and returns the index of that plan within the eligible plans
2353
+ *
2354
+ * @param {number} planIndex - The index of the plan that the user has selected.
2355
+ * @returns The index of the planKey in the eligiblePlanKeys array.
2356
+ */
2357
+
2358
+ const getIndexWithinEligiblePlans = planIndex => {
2359
+ const index = eligiblePlanKeys.findIndex(planKey => planKey === planIndex);
2360
+ return index === -1 ? 0 : index;
2361
+ };
2291
2362
 
2292
2363
  if (status === apiStatus.PENDING) {
2293
2364
  return /*#__PURE__*/React.createElement("div", {
@@ -2295,11 +2366,7 @@ const PaymentPlanWidget = ({
2295
2366
  }, /*#__PURE__*/React.createElement(Loader, null));
2296
2367
  }
2297
2368
 
2298
- if (hideIfNotEligible && eligiblePlans.length == 0 || eligibilityPlans.length === 0) {
2299
- return null;
2300
- }
2301
-
2302
- if (status === apiStatus.FAILED) {
2369
+ if (hideIfNotEligible && eligiblePlans.length === 0 || eligibilityPlans.length === 0 || status === apiStatus.FAILED) {
2303
2370
  return null;
2304
2371
  }
2305
2372
 
@@ -2311,19 +2378,12 @@ const PaymentPlanWidget = ({
2311
2378
  }
2312
2379
  };
2313
2380
 
2314
- const handleHoverAndClick = (key, newInitialPlanIndex) => {
2315
- // This is needed to update the initial plan index and button style when hovering (desktop) or clicking (mobile).
2316
- // The actual modal opening is triggered by a click on the highest parent div in `handleOpenModal`.
2317
- onHover(key);
2318
- setInitialPlanIndex(newInitialPlanIndex);
2319
- };
2320
-
2321
2381
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
2322
2382
  onClick: handleOpenModal,
2323
- className: s$b.widgetButton,
2324
- style: {
2325
- cursor: eligiblePlans.length > 0 ? 'pointer' : 'initial'
2326
- },
2383
+ className: cx(s$b.widgetButton, {
2384
+ [s$b.clickable]: eligiblePlans.length > 0,
2385
+ [s$b.unClickable]: eligiblePlans.length === 0
2386
+ }),
2327
2387
  "data-testid": "widget-button"
2328
2388
  }, /*#__PURE__*/React.createElement("div", {
2329
2389
  className: s$b.primaryContainer
@@ -2332,18 +2392,10 @@ const PaymentPlanWidget = ({
2332
2392
  }), /*#__PURE__*/React.createElement("div", {
2333
2393
  className: s$b.paymentPlans
2334
2394
  }, eligibilityPlans.map((eligibilityPlan, key) => {
2335
- const newInitialPlanIndex = eligiblePlanKeys.includes(key) ? eligiblePlanKeys.findIndex(planKey => planKey === key) : 0;
2336
2395
  return /*#__PURE__*/React.createElement("div", {
2337
- onMouseEnter: () => {
2338
- handleHoverAndClick(key, newInitialPlanIndex);
2339
- },
2340
- onMouseOut: () => {
2341
- onLeave();
2342
- },
2343
- onClick: () => {
2344
- handleHoverAndClick(key, newInitialPlanIndex);
2345
- },
2346
2396
  key: key,
2397
+ onMouseEnter: () => onHover(key),
2398
+ onMouseOut: onLeave,
2347
2399
  className: cx(s$b.plan, {
2348
2400
  [s$b.active]: current === key,
2349
2401
  [s$b.notEligible]: !eligibilityPlan.eligible
@@ -2354,7 +2406,7 @@ const PaymentPlanWidget = ({
2354
2406
  [s$b.notEligible]: eligibilityPlans[current] && !eligibilityPlans[current].eligible
2355
2407
  })
2356
2408
  }, eligibilityPlans.length !== 0 && paymentPlanInfoText(eligibilityPlans[current]))), isOpen && /*#__PURE__*/React.createElement(EligibilityModal, {
2357
- initialPlanIndex: initialPlanIndex,
2409
+ initialPlanIndex: getIndexWithinEligiblePlans(current),
2358
2410
  onClose: closeModal,
2359
2411
  eligibilityPlans: eligiblePlans,
2360
2412
  status: status
@@ -2380,6 +2432,7 @@ class WidgetsController {
2380
2432
  plans,
2381
2433
  transitionDelay,
2382
2434
  hideIfNotEligible,
2435
+ suggestedPaymentPlan,
2383
2436
  locale = Locale.en
2384
2437
  } = options;
2385
2438
 
@@ -2391,7 +2444,8 @@ class WidgetsController {
2391
2444
  apiData: this.apiData,
2392
2445
  configPlans: plans,
2393
2446
  transitionDelay: transitionDelay,
2394
- hideIfNotEligible: hideIfNotEligible
2447
+ hideIfNotEligible: hideIfNotEligible,
2448
+ suggestedPaymentPlan: suggestedPaymentPlan
2395
2449
  })), document.querySelector(container));
2396
2450
  }
2397
2451
  }