@kiva/kv-shop 1.5.2 → 1.6.0

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getCheckoutStatus,
3
3
  pollForFinishedCheckout
4
- } from "./chunk-PC4WUPYU.js";
4
+ } from "./chunk-UIWDTSJN.js";
5
5
  import "./chunk-TPJPGUO7.js";
6
6
  import "./chunk-LZ4UMRCV.js";
7
7
  export {
@@ -0,0 +1,154 @@
1
+ import {
2
+ getVisitorID
3
+ } from "./chunk-TPJPGUO7.js";
4
+
5
+ // src/receipt.ts
6
+ import { gql } from "@apollo/client/core";
7
+ async function getFTDStatus(apollo) {
8
+ const result = await apollo.query({
9
+ query: gql`
10
+ query ftdStatus {
11
+ my {
12
+ id
13
+ userAccount {
14
+ id
15
+ isFirstTimeDepositor
16
+ }
17
+ }
18
+ }
19
+ `
20
+ });
21
+ return result.data?.my?.userAccount?.isFirstTimeDepositor ?? false;
22
+ }
23
+ async function getReceiptItems(apollo, checkoutId) {
24
+ return new Promise((resolve, reject) => {
25
+ const limit = 100;
26
+ let offset = 0;
27
+ const observer = apollo.watchQuery({
28
+ query: gql`
29
+ query receiptItems($checkoutId: String, $visitorId: String, $limit: Int, $offset: Int) {
30
+ shop {
31
+ id
32
+ receipt(checkoutId: $checkoutId, visitorId: $visitorId) {
33
+ id
34
+ items(limit: $limit, offset: $offset) {
35
+ totalCount
36
+ values {
37
+ id
38
+ price
39
+ __typename
40
+
41
+ ... on Donation {
42
+ id
43
+ isTip
44
+ isUserEdited
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ `,
52
+ variables: {
53
+ checkoutId,
54
+ visitorId: getVisitorID(),
55
+ limit,
56
+ offset
57
+ }
58
+ });
59
+ let items = [];
60
+ const handleResult = async (result) => {
61
+ const total = result.data?.shop?.receipt?.items?.totalCount;
62
+ items = items.concat(result.data?.shop?.receipt?.items?.values);
63
+ if (total > offset + limit) {
64
+ offset += limit;
65
+ const nextResult = await observer.fetchMore({
66
+ variables: {
67
+ offset
68
+ }
69
+ });
70
+ try {
71
+ handleResult(nextResult);
72
+ } catch (e) {
73
+ reject(e);
74
+ }
75
+ } else {
76
+ resolve(items);
77
+ }
78
+ };
79
+ observer.subscribe({
80
+ next: handleResult,
81
+ error: (error) => {
82
+ reject(error);
83
+ }
84
+ });
85
+ });
86
+ }
87
+ async function getReceiptTotals(apollo, checkoutId) {
88
+ const result = await apollo.query({
89
+ query: gql`
90
+ query receiptTotals($checkoutId: Int, $visitorId: String) {
91
+ shop {
92
+ id
93
+ receipt(checkoutId: $checkoutId, visitorId: $visitorId) {
94
+ id
95
+ totals {
96
+ loanReservationTotal
97
+ donationTotal
98
+ kivaCardTotal
99
+ itemTotal
100
+ kivaCreditAppliedTotal
101
+ depositTotals {
102
+ depositTotal
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ `,
109
+ variables: {
110
+ checkoutId,
111
+ visitorId: getVisitorID()
112
+ }
113
+ });
114
+ return result.data?.shop?.receipt?.totals;
115
+ }
116
+ async function getCheckoutTrackingData(apollo, checkoutId, paymentType) {
117
+ const [isFTD, items, totals] = await Promise.all([
118
+ getFTDStatus(apollo),
119
+ getReceiptItems(apollo, checkoutId),
120
+ getReceiptTotals(apollo, checkoutId)
121
+ ]);
122
+ const loans = items.filter((item) => item.__typename === "LoanReservation");
123
+ const donations = items.filter((item) => item.__typename === "Donation");
124
+ const kivaCards = items.filter((item) => item.__typename === "KivaCard");
125
+ return {
126
+ transactionId: checkoutId,
127
+ itemTotal: totals.itemTotal,
128
+ // Loan reservations
129
+ loans,
130
+ loanCount: loans.length,
131
+ loanTotal: totals.loanReservationTotal,
132
+ // Donations
133
+ donations: donations.map(({ id, price, __typename }) => ({ id, price, __typename })),
134
+ donationTotal: totals.donationTotal,
135
+ isTip: donations.every((donation) => donation.isTip),
136
+ isUserEdited: donations.some((donation) => donation.isUserEdited),
137
+ // Kiva Cards
138
+ kivaCards,
139
+ kivaCardCount: kivaCards.length,
140
+ kivaCardTotal: totals.kivaCardTotal,
141
+ // Credit & deposit
142
+ kivaCreditAppliedTotal: totals.kivaCreditAppliedTotal,
143
+ depositTotal: totals.depositTotals?.depositTotal ?? "0.00",
144
+ paymentType,
145
+ isFTD
146
+ };
147
+ }
148
+
149
+ export {
150
+ getFTDStatus,
151
+ getReceiptItems,
152
+ getReceiptTotals,
153
+ getCheckoutTrackingData
154
+ };
@@ -1,3 +1,6 @@
1
+ import {
2
+ getCheckoutTrackingData
3
+ } from "./chunk-5V5F6M6B.js";
1
4
  import {
2
5
  validatePreCheckout
3
6
  } from "./chunk-JBQ2KNMP.js";
@@ -10,14 +13,16 @@ import {
10
13
  parseShopError
11
14
  } from "./chunk-4ODZGLWK.js";
12
15
  import {
13
- pollForFinishedCheckout
14
- } from "./chunk-PC4WUPYU.js";
16
+ pollForFinishedCheckout,
17
+ wait
18
+ } from "./chunk-UIWDTSJN.js";
15
19
  import {
16
20
  getVisitorID
17
21
  } from "./chunk-TPJPGUO7.js";
18
22
 
19
23
  // src/oneTimeCheckout.ts
20
24
  import { gql } from "@apollo/client/core";
25
+ import { trackTransaction } from "@kiva/kv-analytics";
21
26
  import numeral from "numeral";
22
27
  async function creditAmountNeeded(apollo) {
23
28
  const data = await callShopQuery(apollo, {
@@ -90,22 +95,34 @@ async function depositCheckout({
90
95
  "No payment method returned from braintree dropin"
91
96
  );
92
97
  }
93
- const { nonce, deviceData } = paymentMethod;
94
- return callShopMutation(apollo, {
95
- mutation: depositCheckoutMutation,
96
- variables: {
97
- nonce,
98
- amount,
99
- savePaymentMethod: false,
100
- // save payment methods handled by braintree drop in UI
101
- deviceData,
102
- visitorId: getVisitorID()
103
- }
104
- }, 0);
98
+ const { nonce, deviceData, type } = paymentMethod;
99
+ return {
100
+ paymentType: type,
101
+ mutation: callShopMutation(apollo, {
102
+ mutation: depositCheckoutMutation,
103
+ variables: {
104
+ nonce,
105
+ amount,
106
+ savePaymentMethod: false,
107
+ // save payment methods handled by braintree drop in UI
108
+ deviceData,
109
+ visitorId: getVisitorID()
110
+ }
111
+ }, 0)
112
+ };
105
113
  } catch (e) {
106
114
  throw parseShopError(e);
107
115
  }
108
116
  }
117
+ async function trackSuccess(apollo, checkoutId, paymentType) {
118
+ const transactionData = await getCheckoutTrackingData(
119
+ apollo,
120
+ checkoutId,
121
+ paymentType
122
+ );
123
+ trackTransaction(transactionData);
124
+ await wait(800);
125
+ }
109
126
  async function executeOneTimeCheckout({
110
127
  apollo,
111
128
  braintree,
@@ -122,11 +139,19 @@ async function executeOneTimeCheckout({
122
139
  if (creditRequired && !braintree) {
123
140
  throw new ShopError({ code: "shop.dropinRequired" }, "Braintree dropin required for credit deposit checkout");
124
141
  }
125
- const data = creditRequired ? await depositCheckout({
126
- apollo,
127
- braintree,
128
- amount: creditNeeded
129
- }) : await creditCheckout(apollo);
142
+ let data;
143
+ let paymentType = "";
144
+ if (creditRequired) {
145
+ const checkoutResult = await depositCheckout({
146
+ apollo,
147
+ braintree,
148
+ amount: creditNeeded
149
+ });
150
+ paymentType = checkoutResult.paymentType;
151
+ data = await checkoutResult.mutation;
152
+ } else {
153
+ data = await creditCheckout(apollo);
154
+ }
130
155
  const transactionId = data?.shop?.transactionId;
131
156
  const result = await pollForFinishedCheckout({
132
157
  apollo,
@@ -138,6 +163,7 @@ async function executeOneTimeCheckout({
138
163
  throw parseShopError(result.errors[0]);
139
164
  }
140
165
  const checkoutId = result.data?.checkoutStatus?.receipt?.checkoutId;
166
+ await trackSuccess(apollo, checkoutId, paymentType);
141
167
  window.location.href = `/checkout/post-purchase?kiva_transaction_id=${checkoutId}`;
142
168
  }
143
169
 
@@ -73,6 +73,7 @@ async function pollForFinishedCheckout({
73
73
  }
74
74
 
75
75
  export {
76
+ wait,
76
77
  getCheckoutStatus,
77
78
  pollForFinishedCheckout
78
79
  };
package/dist/index.cjs CHANGED
@@ -42,7 +42,11 @@ __export(src_exports, {
42
42
  executeOneTimeCheckout: () => executeOneTimeCheckout,
43
43
  getBasketID: () => getBasketID,
44
44
  getCheckoutStatus: () => getCheckoutStatus,
45
+ getCheckoutTrackingData: () => getCheckoutTrackingData,
45
46
  getClientToken: () => getClientToken,
47
+ getFTDStatus: () => getFTDStatus,
48
+ getReceiptItems: () => getReceiptItems,
49
+ getReceiptTotals: () => getReceiptTotals,
46
50
  hasBasketExpired: () => hasBasketExpired,
47
51
  isBasketVerified: () => isBasketVerified,
48
52
  parseShopError: () => parseShopError,
@@ -455,7 +459,8 @@ async function pollForFinishedCheckout({
455
459
  }
456
460
 
457
461
  // src/oneTimeCheckout.ts
458
- var import_core7 = require("@apollo/client/core");
462
+ var import_core8 = require("@apollo/client/core");
463
+ var import_kv_analytics = require("@kiva/kv-analytics");
459
464
  var import_numeral2 = __toESM(require("numeral"), 1);
460
465
 
461
466
  // src/validatePreCheckout.ts
@@ -493,10 +498,154 @@ async function validatePreCheckout({
493
498
  }
494
499
  }
495
500
 
501
+ // src/receipt.ts
502
+ var import_core7 = require("@apollo/client/core");
503
+ async function getFTDStatus(apollo) {
504
+ const result = await apollo.query({
505
+ query: import_core7.gql`
506
+ query ftdStatus {
507
+ my {
508
+ id
509
+ userAccount {
510
+ id
511
+ isFirstTimeDepositor
512
+ }
513
+ }
514
+ }
515
+ `
516
+ });
517
+ return result.data?.my?.userAccount?.isFirstTimeDepositor ?? false;
518
+ }
519
+ async function getReceiptItems(apollo, checkoutId) {
520
+ return new Promise((resolve, reject) => {
521
+ const limit = 100;
522
+ let offset = 0;
523
+ const observer = apollo.watchQuery({
524
+ query: import_core7.gql`
525
+ query receiptItems($checkoutId: String, $visitorId: String, $limit: Int, $offset: Int) {
526
+ shop {
527
+ id
528
+ receipt(checkoutId: $checkoutId, visitorId: $visitorId) {
529
+ id
530
+ items(limit: $limit, offset: $offset) {
531
+ totalCount
532
+ values {
533
+ id
534
+ price
535
+ __typename
536
+
537
+ ... on Donation {
538
+ id
539
+ isTip
540
+ isUserEdited
541
+ }
542
+ }
543
+ }
544
+ }
545
+ }
546
+ }
547
+ `,
548
+ variables: {
549
+ checkoutId,
550
+ visitorId: getVisitorID(),
551
+ limit,
552
+ offset
553
+ }
554
+ });
555
+ let items = [];
556
+ const handleResult = async (result) => {
557
+ const total = result.data?.shop?.receipt?.items?.totalCount;
558
+ items = items.concat(result.data?.shop?.receipt?.items?.values);
559
+ if (total > offset + limit) {
560
+ offset += limit;
561
+ const nextResult = await observer.fetchMore({
562
+ variables: {
563
+ offset
564
+ }
565
+ });
566
+ try {
567
+ handleResult(nextResult);
568
+ } catch (e) {
569
+ reject(e);
570
+ }
571
+ } else {
572
+ resolve(items);
573
+ }
574
+ };
575
+ observer.subscribe({
576
+ next: handleResult,
577
+ error: (error) => {
578
+ reject(error);
579
+ }
580
+ });
581
+ });
582
+ }
583
+ async function getReceiptTotals(apollo, checkoutId) {
584
+ const result = await apollo.query({
585
+ query: import_core7.gql`
586
+ query receiptTotals($checkoutId: Int, $visitorId: String) {
587
+ shop {
588
+ id
589
+ receipt(checkoutId: $checkoutId, visitorId: $visitorId) {
590
+ id
591
+ totals {
592
+ loanReservationTotal
593
+ donationTotal
594
+ kivaCardTotal
595
+ itemTotal
596
+ kivaCreditAppliedTotal
597
+ depositTotals {
598
+ depositTotal
599
+ }
600
+ }
601
+ }
602
+ }
603
+ }
604
+ `,
605
+ variables: {
606
+ checkoutId,
607
+ visitorId: getVisitorID()
608
+ }
609
+ });
610
+ return result.data?.shop?.receipt?.totals;
611
+ }
612
+ async function getCheckoutTrackingData(apollo, checkoutId, paymentType) {
613
+ const [isFTD, items, totals] = await Promise.all([
614
+ getFTDStatus(apollo),
615
+ getReceiptItems(apollo, checkoutId),
616
+ getReceiptTotals(apollo, checkoutId)
617
+ ]);
618
+ const loans = items.filter((item) => item.__typename === "LoanReservation");
619
+ const donations = items.filter((item) => item.__typename === "Donation");
620
+ const kivaCards = items.filter((item) => item.__typename === "KivaCard");
621
+ return {
622
+ transactionId: checkoutId,
623
+ itemTotal: totals.itemTotal,
624
+ // Loan reservations
625
+ loans,
626
+ loanCount: loans.length,
627
+ loanTotal: totals.loanReservationTotal,
628
+ // Donations
629
+ donations: donations.map(({ id, price, __typename }) => ({ id, price, __typename })),
630
+ donationTotal: totals.donationTotal,
631
+ isTip: donations.every((donation) => donation.isTip),
632
+ isUserEdited: donations.some((donation) => donation.isUserEdited),
633
+ // Kiva Cards
634
+ kivaCards,
635
+ kivaCardCount: kivaCards.length,
636
+ kivaCardTotal: totals.kivaCardTotal,
637
+ // Credit & deposit
638
+ kivaCreditAppliedTotal: totals.kivaCreditAppliedTotal,
639
+ depositTotal: totals.depositTotals?.depositTotal ?? "0.00",
640
+ paymentType,
641
+ isFTD
642
+ };
643
+ }
644
+
496
645
  // src/oneTimeCheckout.ts
497
646
  async function creditAmountNeeded(apollo) {
498
647
  const data = await callShopQuery(apollo, {
499
- query: import_core7.gql`
648
+ query: import_core8.gql`
500
649
  query creditAmountNeeded($basketId: String) {
501
650
  shop (basketId: $basketId) {
502
651
  id
@@ -512,7 +661,7 @@ async function creditAmountNeeded(apollo) {
512
661
  }, 0);
513
662
  return data?.shop?.basket?.totals?.creditAmountNeeded;
514
663
  }
515
- var creditCheckoutMutation = import_core7.gql`
664
+ var creditCheckoutMutation = import_core8.gql`
516
665
  mutation creditCheckout(
517
666
  $basketId: String,
518
667
  $visitorId: String
@@ -523,7 +672,7 @@ var creditCheckoutMutation = import_core7.gql`
523
672
  }
524
673
  }
525
674
  `;
526
- var depositCheckoutMutation = import_core7.gql`
675
+ var depositCheckoutMutation = import_core8.gql`
527
676
  mutation depositCheckout(
528
677
  $basketId: String,
529
678
  $amount: Money!,
@@ -565,22 +714,34 @@ async function depositCheckout({
565
714
  "No payment method returned from braintree dropin"
566
715
  );
567
716
  }
568
- const { nonce, deviceData } = paymentMethod;
569
- return callShopMutation(apollo, {
570
- mutation: depositCheckoutMutation,
571
- variables: {
572
- nonce,
573
- amount,
574
- savePaymentMethod: false,
575
- // save payment methods handled by braintree drop in UI
576
- deviceData,
577
- visitorId: getVisitorID()
578
- }
579
- }, 0);
717
+ const { nonce, deviceData, type } = paymentMethod;
718
+ return {
719
+ paymentType: type,
720
+ mutation: callShopMutation(apollo, {
721
+ mutation: depositCheckoutMutation,
722
+ variables: {
723
+ nonce,
724
+ amount,
725
+ savePaymentMethod: false,
726
+ // save payment methods handled by braintree drop in UI
727
+ deviceData,
728
+ visitorId: getVisitorID()
729
+ }
730
+ }, 0)
731
+ };
580
732
  } catch (e) {
581
733
  throw parseShopError(e);
582
734
  }
583
735
  }
736
+ async function trackSuccess(apollo, checkoutId, paymentType) {
737
+ const transactionData = await getCheckoutTrackingData(
738
+ apollo,
739
+ checkoutId,
740
+ paymentType
741
+ );
742
+ (0, import_kv_analytics.trackTransaction)(transactionData);
743
+ await wait(800);
744
+ }
584
745
  async function executeOneTimeCheckout({
585
746
  apollo,
586
747
  braintree,
@@ -597,11 +758,19 @@ async function executeOneTimeCheckout({
597
758
  if (creditRequired && !braintree) {
598
759
  throw new ShopError({ code: "shop.dropinRequired" }, "Braintree dropin required for credit deposit checkout");
599
760
  }
600
- const data = creditRequired ? await depositCheckout({
601
- apollo,
602
- braintree,
603
- amount: creditNeeded
604
- }) : await creditCheckout(apollo);
761
+ let data;
762
+ let paymentType = "";
763
+ if (creditRequired) {
764
+ const checkoutResult = await depositCheckout({
765
+ apollo,
766
+ braintree,
767
+ amount: creditNeeded
768
+ });
769
+ paymentType = checkoutResult.paymentType;
770
+ data = await checkoutResult.mutation;
771
+ } else {
772
+ data = await creditCheckout(apollo);
773
+ }
605
774
  const transactionId = data?.shop?.transactionId;
606
775
  const result = await pollForFinishedCheckout({
607
776
  apollo,
@@ -613,14 +782,15 @@ async function executeOneTimeCheckout({
613
782
  throw parseShopError(result.errors[0]);
614
783
  }
615
784
  const checkoutId = result.data?.checkoutStatus?.receipt?.checkoutId;
785
+ await trackSuccess(apollo, checkoutId, paymentType);
616
786
  window.location.href = `/checkout/post-purchase?kiva_transaction_id=${checkoutId}`;
617
787
  }
618
788
 
619
789
  // src/subscriptionCheckout.ts
620
- var import_core8 = require("@apollo/client/core");
790
+ var import_core9 = require("@apollo/client/core");
621
791
  async function checkSubscriptionStatus(apollo) {
622
792
  const { data: subsData } = await apollo.query({
623
- query: import_core8.gql`query subscriptionStatus{
793
+ query: import_core9.gql`query subscriptionStatus{
624
794
  my {
625
795
  id
626
796
  subscriptions {
@@ -670,7 +840,7 @@ async function executeNewSubscriptionCheckout({
670
840
  donateAmount,
671
841
  dayOfMonth
672
842
  },
673
- mutation: import_core8.gql`mutation createAutoDepositSubscription(
843
+ mutation: import_core9.gql`mutation createAutoDepositSubscription(
674
844
  $nonce: String!,
675
845
  $deviceData: String,
676
846
  $amount: Money!,
@@ -714,13 +884,13 @@ async function executeNewSubscriptionCheckout({
714
884
  }
715
885
 
716
886
  // src/useBraintreeDropIn.ts
717
- var import_core9 = require("@apollo/client/core");
887
+ var import_core10 = require("@apollo/client/core");
718
888
  var import_numeral3 = __toESM(require("numeral"), 1);
719
889
  var import_vue_demi = require("vue-demi");
720
890
  var defaultPaymentTypes = ["paypal", "card", "applePay", "googlePay"];
721
891
  async function getClientToken(apollo) {
722
892
  const { data, error, errors } = await apollo.query({
723
- query: import_core9.gql`query getClientToken {
893
+ query: import_core10.gql`query getClientToken {
724
894
  shop {
725
895
  id
726
896
  getClientToken(useCustomerId: true)
@@ -884,7 +1054,11 @@ function useBraintreeDropIn(key = "default") {
884
1054
  executeOneTimeCheckout,
885
1055
  getBasketID,
886
1056
  getCheckoutStatus,
1057
+ getCheckoutTrackingData,
887
1058
  getClientToken,
1059
+ getFTDStatus,
1060
+ getReceiptItems,
1061
+ getReceiptTotals,
888
1062
  hasBasketExpired,
889
1063
  isBasketVerified,
890
1064
  parseShopError,
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export { BasketTotalsData, basketTotalsQuery, watchBasketTotals } from './basket
5
5
  export { VerificationState, isBasketVerified } from './basketVerification.js';
6
6
  export { CheckoutStatusQueryResult, GetCheckoutStatusOptions, PollForCheckoutStatusOptions, getCheckoutStatus, pollForFinishedCheckout } from './checkoutStatus.js';
7
7
  export { OneTimeCheckoutOptions, executeOneTimeCheckout } from './oneTimeCheckout.js';
8
+ export { getCheckoutTrackingData, getFTDStatus, getReceiptItems, getReceiptTotals } from './receipt.js';
8
9
  export { ShopError, ShopErrorOptions, parseShopError } from './shopError.js';
9
10
  export { callShopMutation, callShopQuery, watchShopQuery } from './shopQueries.js';
10
11
  export { SubscriptionCheckoutOptions, checkSubscriptionStatus, executeNewSubscriptionCheckout } from './subscriptionCheckout.js';
@@ -12,5 +13,6 @@ export { DropInInitOptions, DropInWrapper, PayPalFlowType, PaymentType, defaultP
12
13
  export { ValidatePreCheckoutData, ValidatePreCheckoutOptions, validatePreCheckout, validatePreCheckoutMutation } from './validatePreCheckout.js';
13
14
  import '@apollo/client/core';
14
15
  import 'graphql/language/ast';
16
+ import '@kiva/kv-analytics';
15
17
  import 'braintree-web-drop-in';
16
18
  import 'vue-demi';
package/dist/index.js CHANGED
@@ -24,7 +24,13 @@ import {
24
24
  } from "./chunk-FCAOCO7O.js";
25
25
  import {
26
26
  executeOneTimeCheckout
27
- } from "./chunk-YKNBQR27.js";
27
+ } from "./chunk-6BO6KDZ5.js";
28
+ import {
29
+ getCheckoutTrackingData,
30
+ getFTDStatus,
31
+ getReceiptItems,
32
+ getReceiptTotals
33
+ } from "./chunk-5V5F6M6B.js";
28
34
  import {
29
35
  validatePreCheckout,
30
36
  validatePreCheckoutMutation
@@ -47,7 +53,7 @@ import {
47
53
  import {
48
54
  getCheckoutStatus,
49
55
  pollForFinishedCheckout
50
- } from "./chunk-PC4WUPYU.js";
56
+ } from "./chunk-UIWDTSJN.js";
51
57
  import "./chunk-TPJPGUO7.js";
52
58
  import "./chunk-LZ4UMRCV.js";
53
59
  export {
@@ -64,7 +70,11 @@ export {
64
70
  executeOneTimeCheckout,
65
71
  getBasketID,
66
72
  getCheckoutStatus,
73
+ getCheckoutTrackingData,
67
74
  getClientToken,
75
+ getFTDStatus,
76
+ getReceiptItems,
77
+ getReceiptTotals,
68
78
  hasBasketExpired,
69
79
  isBasketVerified,
70
80
  parseShopError,
@@ -32,7 +32,8 @@ __export(oneTimeCheckout_exports, {
32
32
  executeOneTimeCheckout: () => executeOneTimeCheckout
33
33
  });
34
34
  module.exports = __toCommonJS(oneTimeCheckout_exports);
35
- var import_core4 = require("@apollo/client/core");
35
+ var import_core5 = require("@apollo/client/core");
36
+ var import_kv_analytics = require("@kiva/kv-analytics");
36
37
  var import_numeral = __toESM(require("numeral"), 1);
37
38
 
38
39
  // src/checkoutStatus.ts
@@ -310,10 +311,154 @@ async function validatePreCheckout({
310
311
  }
311
312
  }
312
313
 
314
+ // src/receipt.ts
315
+ var import_core4 = require("@apollo/client/core");
316
+ async function getFTDStatus(apollo) {
317
+ const result = await apollo.query({
318
+ query: import_core4.gql`
319
+ query ftdStatus {
320
+ my {
321
+ id
322
+ userAccount {
323
+ id
324
+ isFirstTimeDepositor
325
+ }
326
+ }
327
+ }
328
+ `
329
+ });
330
+ return result.data?.my?.userAccount?.isFirstTimeDepositor ?? false;
331
+ }
332
+ async function getReceiptItems(apollo, checkoutId) {
333
+ return new Promise((resolve, reject) => {
334
+ const limit = 100;
335
+ let offset = 0;
336
+ const observer = apollo.watchQuery({
337
+ query: import_core4.gql`
338
+ query receiptItems($checkoutId: String, $visitorId: String, $limit: Int, $offset: Int) {
339
+ shop {
340
+ id
341
+ receipt(checkoutId: $checkoutId, visitorId: $visitorId) {
342
+ id
343
+ items(limit: $limit, offset: $offset) {
344
+ totalCount
345
+ values {
346
+ id
347
+ price
348
+ __typename
349
+
350
+ ... on Donation {
351
+ id
352
+ isTip
353
+ isUserEdited
354
+ }
355
+ }
356
+ }
357
+ }
358
+ }
359
+ }
360
+ `,
361
+ variables: {
362
+ checkoutId,
363
+ visitorId: getVisitorID(),
364
+ limit,
365
+ offset
366
+ }
367
+ });
368
+ let items = [];
369
+ const handleResult = async (result) => {
370
+ const total = result.data?.shop?.receipt?.items?.totalCount;
371
+ items = items.concat(result.data?.shop?.receipt?.items?.values);
372
+ if (total > offset + limit) {
373
+ offset += limit;
374
+ const nextResult = await observer.fetchMore({
375
+ variables: {
376
+ offset
377
+ }
378
+ });
379
+ try {
380
+ handleResult(nextResult);
381
+ } catch (e) {
382
+ reject(e);
383
+ }
384
+ } else {
385
+ resolve(items);
386
+ }
387
+ };
388
+ observer.subscribe({
389
+ next: handleResult,
390
+ error: (error) => {
391
+ reject(error);
392
+ }
393
+ });
394
+ });
395
+ }
396
+ async function getReceiptTotals(apollo, checkoutId) {
397
+ const result = await apollo.query({
398
+ query: import_core4.gql`
399
+ query receiptTotals($checkoutId: Int, $visitorId: String) {
400
+ shop {
401
+ id
402
+ receipt(checkoutId: $checkoutId, visitorId: $visitorId) {
403
+ id
404
+ totals {
405
+ loanReservationTotal
406
+ donationTotal
407
+ kivaCardTotal
408
+ itemTotal
409
+ kivaCreditAppliedTotal
410
+ depositTotals {
411
+ depositTotal
412
+ }
413
+ }
414
+ }
415
+ }
416
+ }
417
+ `,
418
+ variables: {
419
+ checkoutId,
420
+ visitorId: getVisitorID()
421
+ }
422
+ });
423
+ return result.data?.shop?.receipt?.totals;
424
+ }
425
+ async function getCheckoutTrackingData(apollo, checkoutId, paymentType) {
426
+ const [isFTD, items, totals] = await Promise.all([
427
+ getFTDStatus(apollo),
428
+ getReceiptItems(apollo, checkoutId),
429
+ getReceiptTotals(apollo, checkoutId)
430
+ ]);
431
+ const loans = items.filter((item) => item.__typename === "LoanReservation");
432
+ const donations = items.filter((item) => item.__typename === "Donation");
433
+ const kivaCards = items.filter((item) => item.__typename === "KivaCard");
434
+ return {
435
+ transactionId: checkoutId,
436
+ itemTotal: totals.itemTotal,
437
+ // Loan reservations
438
+ loans,
439
+ loanCount: loans.length,
440
+ loanTotal: totals.loanReservationTotal,
441
+ // Donations
442
+ donations: donations.map(({ id, price, __typename }) => ({ id, price, __typename })),
443
+ donationTotal: totals.donationTotal,
444
+ isTip: donations.every((donation) => donation.isTip),
445
+ isUserEdited: donations.some((donation) => donation.isUserEdited),
446
+ // Kiva Cards
447
+ kivaCards,
448
+ kivaCardCount: kivaCards.length,
449
+ kivaCardTotal: totals.kivaCardTotal,
450
+ // Credit & deposit
451
+ kivaCreditAppliedTotal: totals.kivaCreditAppliedTotal,
452
+ depositTotal: totals.depositTotals?.depositTotal ?? "0.00",
453
+ paymentType,
454
+ isFTD
455
+ };
456
+ }
457
+
313
458
  // src/oneTimeCheckout.ts
314
459
  async function creditAmountNeeded(apollo) {
315
460
  const data = await callShopQuery(apollo, {
316
- query: import_core4.gql`
461
+ query: import_core5.gql`
317
462
  query creditAmountNeeded($basketId: String) {
318
463
  shop (basketId: $basketId) {
319
464
  id
@@ -329,7 +474,7 @@ async function creditAmountNeeded(apollo) {
329
474
  }, 0);
330
475
  return data?.shop?.basket?.totals?.creditAmountNeeded;
331
476
  }
332
- var creditCheckoutMutation = import_core4.gql`
477
+ var creditCheckoutMutation = import_core5.gql`
333
478
  mutation creditCheckout(
334
479
  $basketId: String,
335
480
  $visitorId: String
@@ -340,7 +485,7 @@ var creditCheckoutMutation = import_core4.gql`
340
485
  }
341
486
  }
342
487
  `;
343
- var depositCheckoutMutation = import_core4.gql`
488
+ var depositCheckoutMutation = import_core5.gql`
344
489
  mutation depositCheckout(
345
490
  $basketId: String,
346
491
  $amount: Money!,
@@ -382,22 +527,34 @@ async function depositCheckout({
382
527
  "No payment method returned from braintree dropin"
383
528
  );
384
529
  }
385
- const { nonce, deviceData } = paymentMethod;
386
- return callShopMutation(apollo, {
387
- mutation: depositCheckoutMutation,
388
- variables: {
389
- nonce,
390
- amount,
391
- savePaymentMethod: false,
392
- // save payment methods handled by braintree drop in UI
393
- deviceData,
394
- visitorId: getVisitorID()
395
- }
396
- }, 0);
530
+ const { nonce, deviceData, type } = paymentMethod;
531
+ return {
532
+ paymentType: type,
533
+ mutation: callShopMutation(apollo, {
534
+ mutation: depositCheckoutMutation,
535
+ variables: {
536
+ nonce,
537
+ amount,
538
+ savePaymentMethod: false,
539
+ // save payment methods handled by braintree drop in UI
540
+ deviceData,
541
+ visitorId: getVisitorID()
542
+ }
543
+ }, 0)
544
+ };
397
545
  } catch (e) {
398
546
  throw parseShopError(e);
399
547
  }
400
548
  }
549
+ async function trackSuccess(apollo, checkoutId, paymentType) {
550
+ const transactionData = await getCheckoutTrackingData(
551
+ apollo,
552
+ checkoutId,
553
+ paymentType
554
+ );
555
+ (0, import_kv_analytics.trackTransaction)(transactionData);
556
+ await wait(800);
557
+ }
401
558
  async function executeOneTimeCheckout({
402
559
  apollo,
403
560
  braintree,
@@ -414,11 +571,19 @@ async function executeOneTimeCheckout({
414
571
  if (creditRequired && !braintree) {
415
572
  throw new ShopError({ code: "shop.dropinRequired" }, "Braintree dropin required for credit deposit checkout");
416
573
  }
417
- const data = creditRequired ? await depositCheckout({
418
- apollo,
419
- braintree,
420
- amount: creditNeeded
421
- }) : await creditCheckout(apollo);
574
+ let data;
575
+ let paymentType = "";
576
+ if (creditRequired) {
577
+ const checkoutResult = await depositCheckout({
578
+ apollo,
579
+ braintree,
580
+ amount: creditNeeded
581
+ });
582
+ paymentType = checkoutResult.paymentType;
583
+ data = await checkoutResult.mutation;
584
+ } else {
585
+ data = await creditCheckout(apollo);
586
+ }
422
587
  const transactionId = data?.shop?.transactionId;
423
588
  const result = await pollForFinishedCheckout({
424
589
  apollo,
@@ -430,6 +595,7 @@ async function executeOneTimeCheckout({
430
595
  throw parseShopError(result.errors[0]);
431
596
  }
432
597
  const checkoutId = result.data?.checkoutStatus?.receipt?.checkoutId;
598
+ await trackSuccess(apollo, checkoutId, paymentType);
433
599
  window.location.href = `/checkout/post-purchase?kiva_transaction_id=${checkoutId}`;
434
600
  }
435
601
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  executeOneTimeCheckout
3
- } from "./chunk-YKNBQR27.js";
3
+ } from "./chunk-6BO6KDZ5.js";
4
+ import "./chunk-5V5F6M6B.js";
4
5
  import "./chunk-JBQ2KNMP.js";
5
6
  import "./chunk-CBJJUUVR.js";
6
7
  import "./chunk-2NC7LGGO.js";
7
8
  import "./chunk-4ODZGLWK.js";
8
- import "./chunk-PC4WUPYU.js";
9
+ import "./chunk-UIWDTSJN.js";
9
10
  import "./chunk-TPJPGUO7.js";
10
11
  import "./chunk-LZ4UMRCV.js";
11
12
  export {
@@ -0,0 +1,190 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/receipt.ts
20
+ var receipt_exports = {};
21
+ __export(receipt_exports, {
22
+ getCheckoutTrackingData: () => getCheckoutTrackingData,
23
+ getFTDStatus: () => getFTDStatus,
24
+ getReceiptItems: () => getReceiptItems,
25
+ getReceiptTotals: () => getReceiptTotals
26
+ });
27
+ module.exports = __toCommonJS(receipt_exports);
28
+ var import_core = require("@apollo/client/core");
29
+
30
+ // src/util/cookie.ts
31
+ var getCookieValue = (name) => {
32
+ if (typeof document !== void 0) {
33
+ return decodeURIComponent(document.cookie.match(`(^|;)\\s*${name}\\s*=\\s*([^;]+)`)?.pop() || "");
34
+ }
35
+ };
36
+
37
+ // src/util/visitorId.ts
38
+ function getVisitorID() {
39
+ return getCookieValue("uiv");
40
+ }
41
+
42
+ // src/receipt.ts
43
+ async function getFTDStatus(apollo) {
44
+ const result = await apollo.query({
45
+ query: import_core.gql`
46
+ query ftdStatus {
47
+ my {
48
+ id
49
+ userAccount {
50
+ id
51
+ isFirstTimeDepositor
52
+ }
53
+ }
54
+ }
55
+ `
56
+ });
57
+ return result.data?.my?.userAccount?.isFirstTimeDepositor ?? false;
58
+ }
59
+ async function getReceiptItems(apollo, checkoutId) {
60
+ return new Promise((resolve, reject) => {
61
+ const limit = 100;
62
+ let offset = 0;
63
+ const observer = apollo.watchQuery({
64
+ query: import_core.gql`
65
+ query receiptItems($checkoutId: String, $visitorId: String, $limit: Int, $offset: Int) {
66
+ shop {
67
+ id
68
+ receipt(checkoutId: $checkoutId, visitorId: $visitorId) {
69
+ id
70
+ items(limit: $limit, offset: $offset) {
71
+ totalCount
72
+ values {
73
+ id
74
+ price
75
+ __typename
76
+
77
+ ... on Donation {
78
+ id
79
+ isTip
80
+ isUserEdited
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ `,
88
+ variables: {
89
+ checkoutId,
90
+ visitorId: getVisitorID(),
91
+ limit,
92
+ offset
93
+ }
94
+ });
95
+ let items = [];
96
+ const handleResult = async (result) => {
97
+ const total = result.data?.shop?.receipt?.items?.totalCount;
98
+ items = items.concat(result.data?.shop?.receipt?.items?.values);
99
+ if (total > offset + limit) {
100
+ offset += limit;
101
+ const nextResult = await observer.fetchMore({
102
+ variables: {
103
+ offset
104
+ }
105
+ });
106
+ try {
107
+ handleResult(nextResult);
108
+ } catch (e) {
109
+ reject(e);
110
+ }
111
+ } else {
112
+ resolve(items);
113
+ }
114
+ };
115
+ observer.subscribe({
116
+ next: handleResult,
117
+ error: (error) => {
118
+ reject(error);
119
+ }
120
+ });
121
+ });
122
+ }
123
+ async function getReceiptTotals(apollo, checkoutId) {
124
+ const result = await apollo.query({
125
+ query: import_core.gql`
126
+ query receiptTotals($checkoutId: Int, $visitorId: String) {
127
+ shop {
128
+ id
129
+ receipt(checkoutId: $checkoutId, visitorId: $visitorId) {
130
+ id
131
+ totals {
132
+ loanReservationTotal
133
+ donationTotal
134
+ kivaCardTotal
135
+ itemTotal
136
+ kivaCreditAppliedTotal
137
+ depositTotals {
138
+ depositTotal
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ `,
145
+ variables: {
146
+ checkoutId,
147
+ visitorId: getVisitorID()
148
+ }
149
+ });
150
+ return result.data?.shop?.receipt?.totals;
151
+ }
152
+ async function getCheckoutTrackingData(apollo, checkoutId, paymentType) {
153
+ const [isFTD, items, totals] = await Promise.all([
154
+ getFTDStatus(apollo),
155
+ getReceiptItems(apollo, checkoutId),
156
+ getReceiptTotals(apollo, checkoutId)
157
+ ]);
158
+ const loans = items.filter((item) => item.__typename === "LoanReservation");
159
+ const donations = items.filter((item) => item.__typename === "Donation");
160
+ const kivaCards = items.filter((item) => item.__typename === "KivaCard");
161
+ return {
162
+ transactionId: checkoutId,
163
+ itemTotal: totals.itemTotal,
164
+ // Loan reservations
165
+ loans,
166
+ loanCount: loans.length,
167
+ loanTotal: totals.loanReservationTotal,
168
+ // Donations
169
+ donations: donations.map(({ id, price, __typename }) => ({ id, price, __typename })),
170
+ donationTotal: totals.donationTotal,
171
+ isTip: donations.every((donation) => donation.isTip),
172
+ isUserEdited: donations.some((donation) => donation.isUserEdited),
173
+ // Kiva Cards
174
+ kivaCards,
175
+ kivaCardCount: kivaCards.length,
176
+ kivaCardTotal: totals.kivaCardTotal,
177
+ // Credit & deposit
178
+ kivaCreditAppliedTotal: totals.kivaCreditAppliedTotal,
179
+ depositTotal: totals.depositTotals?.depositTotal ?? "0.00",
180
+ paymentType,
181
+ isFTD
182
+ };
183
+ }
184
+ // Annotate the CommonJS export names for ESM import in node:
185
+ 0 && (module.exports = {
186
+ getCheckoutTrackingData,
187
+ getFTDStatus,
188
+ getReceiptItems,
189
+ getReceiptTotals
190
+ });
@@ -0,0 +1,16 @@
1
+ import { ApolloClient } from '@apollo/client/core';
2
+ import { TransactionData } from '@kiva/kv-analytics';
3
+
4
+ declare function getFTDStatus(apollo: ApolloClient<any>): Promise<any>;
5
+ interface ReceiptItem {
6
+ id: string;
7
+ price: string;
8
+ __typename: string;
9
+ isTip?: boolean;
10
+ isUserEdited?: boolean;
11
+ }
12
+ declare function getReceiptItems(apollo: ApolloClient<any>, checkoutId: string): Promise<ReceiptItem[]>;
13
+ declare function getReceiptTotals(apollo: ApolloClient<any>, checkoutId: string): Promise<any>;
14
+ declare function getCheckoutTrackingData(apollo: ApolloClient<any>, checkoutId: string, paymentType: string): Promise<TransactionData>;
15
+
16
+ export { getCheckoutTrackingData, getFTDStatus, getReceiptItems, getReceiptTotals };
@@ -0,0 +1,14 @@
1
+ import {
2
+ getCheckoutTrackingData,
3
+ getFTDStatus,
4
+ getReceiptItems,
5
+ getReceiptTotals
6
+ } from "./chunk-5V5F6M6B.js";
7
+ import "./chunk-TPJPGUO7.js";
8
+ import "./chunk-LZ4UMRCV.js";
9
+ export {
10
+ getCheckoutTrackingData,
11
+ getFTDStatus,
12
+ getReceiptItems,
13
+ getReceiptTotals
14
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kiva/kv-shop",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -38,6 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@apollo/client": "^3.7.14",
41
+ "@kiva/kv-analytics": "^1.2.2",
41
42
  "@kiva/kv-components": "^3.48.1",
42
43
  "@types/braintree-web-drop-in": "^1.34.2",
43
44
  "braintree-web-drop-in": "^1.37.0",
@@ -53,5 +54,5 @@
53
54
  "optional": true
54
55
  }
55
56
  },
56
- "gitHead": "b4fd4b1a39ead26cca9aed076f47b8ffcbc5872a"
57
+ "gitHead": "1cc98bc5e5ce05ad8fb3b0a2c7e42101ab9ffbb5"
57
58
  }