@virgodev/iap 1.0.1 → 1.0.3
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/components/StripeCheckout.vue +92 -55
- package/components/StripePopup.vue +20 -34
- package/{main.ts → index.ts} +12 -0
- package/package.json +6 -5
- package/stores/iap.ts +48 -9
- package/utils.ts +35 -0
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<Message
|
|
3
|
+
v-if="!sessionResponse && messageText"
|
|
4
|
+
id="payment-message"
|
|
5
|
+
:class="{ hidden: !messageText }"
|
|
6
|
+
class="p-1 message"
|
|
7
|
+
severity="error"
|
|
8
|
+
>
|
|
9
|
+
<b>Failed to create payment session. Please try again later.</b>
|
|
10
|
+
<div>{{ messageText }}</div>
|
|
11
|
+
</Message>
|
|
12
|
+
<div v-else-if="!sessionResponse" id="payment-form p-4">Loading...</div>
|
|
3
13
|
<form
|
|
4
14
|
v-else
|
|
5
15
|
id="payment-form"
|
|
6
|
-
class="p-3-t flex-
|
|
16
|
+
class="p-3-t flex-wrap gap-2"
|
|
17
|
+
:class="{
|
|
18
|
+
'flex-row': !props.vertical,
|
|
19
|
+
'flex-column': props.vertical,
|
|
20
|
+
}"
|
|
7
21
|
@submit.prevent="handleSubmit"
|
|
8
22
|
>
|
|
9
|
-
<
|
|
10
|
-
v-if="
|
|
23
|
+
<Message
|
|
24
|
+
v-if="messageText"
|
|
11
25
|
id="payment-message"
|
|
12
|
-
:class="{ hidden: !showMessage }"
|
|
13
26
|
class="message"
|
|
27
|
+
severity="error"
|
|
14
28
|
>
|
|
15
29
|
{{ messageText }}
|
|
16
|
-
</
|
|
30
|
+
</Message>
|
|
17
31
|
|
|
18
32
|
<div class="cart flex-column flex-stretch p-1">
|
|
19
33
|
<div v-for="item in cart.items" :key="item.id" class="flex-column p-1">
|
|
@@ -48,11 +62,11 @@
|
|
|
48
62
|
<!-- Stripe.js injects the Payment Element -->
|
|
49
63
|
</div>
|
|
50
64
|
|
|
51
|
-
<slot name="
|
|
52
|
-
<div class="flex-row justify-
|
|
53
|
-
<
|
|
65
|
+
<slot name="default">
|
|
66
|
+
<div class="flex-row justify-right p-2">
|
|
67
|
+
<Button id="submit" :disabled="isLoading" type="submit">
|
|
54
68
|
Pay Now
|
|
55
|
-
</
|
|
69
|
+
</Button>
|
|
56
70
|
</div>
|
|
57
71
|
</slot>
|
|
58
72
|
</div>
|
|
@@ -65,62 +79,43 @@ import type {
|
|
|
65
79
|
StripeCheckoutLoadActionsResult,
|
|
66
80
|
} from "@stripe/stripe-js";
|
|
67
81
|
import api from "@virgodev/bazaar/functions/api";
|
|
68
|
-
import { onMounted, ref } from "vue";
|
|
69
|
-
import { ProductType, useIapStore } from "../
|
|
82
|
+
import { onMounted, ref, watch, nextTick } from "vue";
|
|
83
|
+
import { ProductType, useIapStore } from "../index";
|
|
70
84
|
import type { StripeCart } from "../stores/iap";
|
|
85
|
+
import Message from "primevue/message";
|
|
86
|
+
import Button from "primevue/button";
|
|
71
87
|
|
|
72
88
|
const props = defineProps<{
|
|
73
89
|
cart: StripeCart;
|
|
74
90
|
returnUrl: string;
|
|
91
|
+
email: string;
|
|
92
|
+
vertical: false;
|
|
75
93
|
}>();
|
|
76
94
|
|
|
77
95
|
const iap = useIapStore();
|
|
78
96
|
|
|
79
97
|
const isLoading = ref<boolean>(false);
|
|
80
|
-
const showMessage = ref(false);
|
|
81
98
|
const messageText = ref("");
|
|
82
99
|
const sessionResponse = ref<any>();
|
|
83
100
|
|
|
84
101
|
let checkout: StripeCheckout | null = null;
|
|
85
102
|
let loadActionsResult: StripeCheckoutLoadActionsResult | null = null;
|
|
103
|
+
let paymentElement = undefined;
|
|
86
104
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
setTimeout(() => {
|
|
92
|
-
showMessage.value = false;
|
|
93
|
-
messageText.value = "";
|
|
94
|
-
}, 4000);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const setLoading = (loading: boolean) => {
|
|
98
|
-
isLoading.value = loading;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const handleSubmit = async () => {
|
|
102
|
-
setLoading(true);
|
|
103
|
-
|
|
104
|
-
if (loadActionsResult?.type === "success") {
|
|
105
|
-
const result = await loadActionsResult.actions.confirm({
|
|
106
|
-
returnUrl:
|
|
107
|
-
props.returnUrl + "?stripe_session_id=" + sessionResponse.value.id,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
if (result.type === "error") {
|
|
111
|
-
showPaymentMessage(`${result.error.code}: ${result.error.message}`);
|
|
112
|
-
} else {
|
|
113
|
-
// TODO: verify with server
|
|
114
|
-
// TODO: connect purchaseItem with a promise resolve function
|
|
115
|
-
}
|
|
105
|
+
watch(
|
|
106
|
+
() => props.cart,
|
|
107
|
+
() => {
|
|
108
|
+
getSession();
|
|
116
109
|
}
|
|
117
|
-
|
|
118
|
-
setLoading(false);
|
|
119
|
-
};
|
|
110
|
+
);
|
|
120
111
|
|
|
121
112
|
onMounted(async () => {
|
|
122
|
-
|
|
123
|
-
|
|
113
|
+
getSession();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
async function getSession() {
|
|
117
|
+
if (iap.stripe.client) {
|
|
118
|
+
try {
|
|
124
119
|
// Fetch client secret from backend
|
|
125
120
|
const clientSecretResponse = await api({
|
|
126
121
|
url: "purchases/session/",
|
|
@@ -135,7 +130,7 @@ onMounted(async () => {
|
|
|
135
130
|
if (clientSecretResponse.ok) {
|
|
136
131
|
sessionResponse.value = clientSecretResponse.body;
|
|
137
132
|
|
|
138
|
-
checkout = await iap.stripe.initCheckout({
|
|
133
|
+
checkout = await iap.stripe.client.initCheckout({
|
|
139
134
|
clientSecret: sessionResponse.value.client_secret,
|
|
140
135
|
elementsOptions: { appearance: { theme: "stripe" } },
|
|
141
136
|
});
|
|
@@ -151,21 +146,63 @@ onMounted(async () => {
|
|
|
151
146
|
showPaymentMessage("Failed to load payment actions");
|
|
152
147
|
}
|
|
153
148
|
|
|
154
|
-
|
|
149
|
+
if (paymentElement) {
|
|
150
|
+
await paymentElement.destroy();
|
|
151
|
+
await nextTick();
|
|
152
|
+
}
|
|
153
|
+
paymentElement = checkout.createPaymentElement();
|
|
155
154
|
paymentElement.mount("#payment-element");
|
|
155
|
+
} else {
|
|
156
|
+
const errorContent = clientSecretResponse.body.error;
|
|
157
|
+
iap.stripe.error = new Error(errorContent);
|
|
158
|
+
messageText.value = errorContent;
|
|
156
159
|
}
|
|
160
|
+
} catch (error) {
|
|
161
|
+
iap.stripe.error = error;
|
|
162
|
+
console.error("Error initializing checkout:", error);
|
|
163
|
+
showPaymentMessage("Failed to initialize payment form");
|
|
157
164
|
}
|
|
158
|
-
} catch (error) {
|
|
159
|
-
console.error("Error initializing checkout:", error);
|
|
160
|
-
showPaymentMessage("Failed to initialize payment form");
|
|
161
165
|
}
|
|
162
|
-
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function showPaymentMessage(messageContent: string) {
|
|
169
|
+
messageText.value = messageContent;
|
|
170
|
+
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
messageText.value = "";
|
|
173
|
+
}, 8000);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function setLoading(loading: boolean) {
|
|
177
|
+
isLoading.value = loading;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function handleSubmit() {
|
|
181
|
+
setLoading(true);
|
|
182
|
+
|
|
183
|
+
if (loadActionsResult?.type === "success") {
|
|
184
|
+
const result = await loadActionsResult.actions.confirm({
|
|
185
|
+
email: props.email,
|
|
186
|
+
returnUrl:
|
|
187
|
+
props.returnUrl + "?stripe_session_id=" + sessionResponse.value.id,
|
|
188
|
+
});
|
|
189
|
+
if (result.type === "error") {
|
|
190
|
+
showPaymentMessage(`${result.error.code}: ${result.error.message}`);
|
|
191
|
+
} else {
|
|
192
|
+
// TODO: verify with server
|
|
193
|
+
// TODO: connect purchaseItem with a promise resolve function
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
setLoading(false);
|
|
198
|
+
}
|
|
163
199
|
</script>
|
|
164
200
|
|
|
165
201
|
<style scoped>
|
|
166
202
|
#payment-form {
|
|
167
|
-
min-width:
|
|
168
|
-
|
|
203
|
+
min-width: 300px;
|
|
204
|
+
width: 600px;
|
|
205
|
+
flex: 1 1 600px;
|
|
169
206
|
}
|
|
170
207
|
.cart {
|
|
171
208
|
min-width: 250px;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Dialog
|
|
3
|
-
v-if="iap.
|
|
4
|
-
:visible="!!iap.
|
|
3
|
+
v-if="iap.stripe.status && iap.stripe.cart"
|
|
4
|
+
:visible="!!iap.stripe.cart"
|
|
5
5
|
:dismissable-mask="true"
|
|
6
6
|
:modal="true"
|
|
7
7
|
:show-header="false"
|
|
8
8
|
@update:visible="closeDialog"
|
|
9
9
|
>
|
|
10
10
|
<div
|
|
11
|
-
v-if="iap.
|
|
11
|
+
v-if="iap.stripe.status === 'verified' && iap.stripe.cart"
|
|
12
12
|
class="complete flex-column justify-center align-items-center p-3"
|
|
13
13
|
>
|
|
14
14
|
<h2 class="text-center p-1">Payment Complete!</h2>
|
|
15
15
|
<i class="pi pi-check-circle text-success p-2 text-center" />
|
|
16
16
|
<div class="cart p-3-x p-1-y">
|
|
17
|
-
<div v-for="item of iap.
|
|
17
|
+
<div v-for="item of iap.stripe.cart.items" class="flex-row">
|
|
18
18
|
<div class="flex-stretch">
|
|
19
19
|
<b>{{ item.product?.name }}</b>
|
|
20
20
|
</div>
|
|
@@ -22,7 +22,12 @@
|
|
|
22
22
|
</div>
|
|
23
23
|
</div>
|
|
24
24
|
</div>
|
|
25
|
-
<StripeCheckout
|
|
25
|
+
<StripeCheckout
|
|
26
|
+
v-else
|
|
27
|
+
:cart="iap.stripe.cart"
|
|
28
|
+
:return-url="returnUrl"
|
|
29
|
+
:email="props.email"
|
|
30
|
+
>
|
|
26
31
|
<template #button>
|
|
27
32
|
<div class="flex-row justify-stretch p-1-y">
|
|
28
33
|
<Button type="submit" class="flex-stretch">Pay Now</Button>
|
|
@@ -43,43 +48,24 @@ const router = useRouter();
|
|
|
43
48
|
const iap = useIapStore();
|
|
44
49
|
const visible = ref(false);
|
|
45
50
|
|
|
51
|
+
const props = defineProps<{ email: string }>();
|
|
52
|
+
|
|
46
53
|
const returnUrl = computed(() => {
|
|
47
54
|
return `${location.protocol}//${location.host}${router.currentRoute.value.fullPath}`;
|
|
48
55
|
});
|
|
49
56
|
|
|
50
|
-
router.beforeResolve(async (to, from, next) => {
|
|
51
|
-
if (to.query.stripe_session_id) {
|
|
52
|
-
const cart = iap.stripeCart;
|
|
53
|
-
await nextTick();
|
|
54
|
-
if (cart && cart.items.length > 0) {
|
|
55
|
-
const item = cart.items[0];
|
|
56
|
-
const result = await iap.verify({
|
|
57
|
-
products: [{ id: item.product.id }],
|
|
58
|
-
platform: Platform.STRIPE,
|
|
59
|
-
transactionId: `${to.query.stripe_session_id}`,
|
|
60
|
-
purchaseId: item.product.id,
|
|
61
|
-
finish: function (): void {},
|
|
62
|
-
});
|
|
63
|
-
if (result) {
|
|
64
|
-
iap.stripeStatus = "verified";
|
|
65
|
-
delete to.query.stripe_session_id;
|
|
66
|
-
}
|
|
67
|
-
next(to);
|
|
68
|
-
} else {
|
|
69
|
-
console.warn("Found stripe session, but cart is empty");
|
|
70
|
-
next();
|
|
71
|
-
}
|
|
72
|
-
} else {
|
|
73
|
-
next();
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
57
|
onMounted(() => {});
|
|
78
58
|
|
|
79
59
|
function closeDialog(v: boolean): void {
|
|
80
60
|
if (v === false) {
|
|
81
|
-
iap.
|
|
82
|
-
|
|
61
|
+
if (iap.stripe.callback) {
|
|
62
|
+
iap.stripe.callback(undefined);
|
|
63
|
+
}
|
|
64
|
+
iap.stripe.callback = undefined;
|
|
65
|
+
iap.stripe.result = undefined;
|
|
66
|
+
iap.stripe.cart = undefined;
|
|
67
|
+
iap.stripe.status = undefined;
|
|
68
|
+
iap.stripe.error = undefined;
|
|
83
69
|
visible.value = false;
|
|
84
70
|
}
|
|
85
71
|
}
|
package/{main.ts → index.ts}
RENAMED
|
@@ -3,3 +3,15 @@ export { Platform, ProductType, useIapStore } from "./stores/iap";
|
|
|
3
3
|
export { default as StripeCheckout } from "./components/StripeCheckout.vue";
|
|
4
4
|
export { default as StripeComplete } from "./components/StripeComplete.vue";
|
|
5
5
|
export { default as StripePopup } from "./components/StripePopup.vue";
|
|
6
|
+
|
|
7
|
+
import { catchVerifiedPayments } from "./utils";
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
install(app, options) {
|
|
11
|
+
if (!options.router) {
|
|
12
|
+
console.error("Vue Router is required for the IAP plugin.");
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
catchVerifiedPayments(options.router);
|
|
16
|
+
},
|
|
17
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@virgodev/iap",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"main": "./
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"main": "./index.ts",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
7
|
},
|
|
@@ -10,14 +10,15 @@
|
|
|
10
10
|
"description": "",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@stripe/stripe-js": "^8.2.0",
|
|
13
|
+
"@virgodev/iap": "^1.0.1",
|
|
13
14
|
"cordova-plugin-purchase": "^13.12.1"
|
|
14
15
|
},
|
|
15
16
|
"peerDependencies": {
|
|
16
|
-
"@virgodev/bazaar": "^1.2.7",
|
|
17
17
|
"@capacitor/app": "^7.1.0",
|
|
18
18
|
"@capacitor/device": "^7.0.2",
|
|
19
|
-
"
|
|
19
|
+
"@virgodev/bazaar": "^1.2.7",
|
|
20
|
+
"pinia": "^3.0.3",
|
|
20
21
|
"primevue": "^4.4.1",
|
|
21
|
-
"
|
|
22
|
+
"vue-router": "^4.6.3"
|
|
22
23
|
}
|
|
23
24
|
}
|
package/stores/iap.ts
CHANGED
|
@@ -6,7 +6,7 @@ import api from "@virgodev/bazaar/functions/api";
|
|
|
6
6
|
import { localRef } from "@virgodev/bazaar/functions/localstorage/localRef";
|
|
7
7
|
import { createStore } from "@virgodev/vue-models/utils/create_store";
|
|
8
8
|
import { defineStore } from "pinia";
|
|
9
|
-
import { computed, ref, shallowRef } from "vue";
|
|
9
|
+
import { computed, ref, shallowRef, watch } from "vue";
|
|
10
10
|
import { useRouter } from "vue-router";
|
|
11
11
|
|
|
12
12
|
export enum ProductType {
|
|
@@ -125,6 +125,10 @@ export const useIapStore = defineStore("iap", () => {
|
|
|
125
125
|
const stripeLoaded = ref(false);
|
|
126
126
|
const stripeCart = localRef<StripeCart | undefined>("stripe-cart", undefined);
|
|
127
127
|
const stripeStatus = ref<undefined | "cart" | "verified">();
|
|
128
|
+
const stripeResult = ref<undefined | Transaction>();
|
|
129
|
+
const stripeCallback =
|
|
130
|
+
ref<(t: Transaction | undefined) => Transaction | undefined>();
|
|
131
|
+
const stripeError = ref<undefined | string>();
|
|
128
132
|
|
|
129
133
|
const storePlatform = computed(() => {
|
|
130
134
|
if (platform.value === "android") {
|
|
@@ -134,6 +138,14 @@ export const useIapStore = defineStore("iap", () => {
|
|
|
134
138
|
}
|
|
135
139
|
});
|
|
136
140
|
|
|
141
|
+
watch(stripeResult, () => {
|
|
142
|
+
if (stripeCallback.value) {
|
|
143
|
+
stripeCallback.value(stripeResult.value);
|
|
144
|
+
stripeCallback.value = undefined;
|
|
145
|
+
stripeResult.value = undefined;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
137
149
|
async function initialize(loadProducts: IapProduct[]) {
|
|
138
150
|
products.value = loadProducts;
|
|
139
151
|
|
|
@@ -162,11 +174,12 @@ export const useIapStore = defineStore("iap", () => {
|
|
|
162
174
|
|
|
163
175
|
store.initialize();
|
|
164
176
|
} else {
|
|
165
|
-
console.
|
|
177
|
+
console.debug("CdvPurchase not found, skipping ios/android payments");
|
|
178
|
+
isReady.value = true;
|
|
166
179
|
}
|
|
167
180
|
}
|
|
168
181
|
|
|
169
|
-
async function purchaseItem(code: string) {
|
|
182
|
+
async function purchaseItem(code: string): Promise<any | undefined> {
|
|
170
183
|
const product = products.value.find((p) => p.id === code);
|
|
171
184
|
if (product) {
|
|
172
185
|
if (product.platform === Platform.STRIPE) {
|
|
@@ -174,6 +187,9 @@ export const useIapStore = defineStore("iap", () => {
|
|
|
174
187
|
stripeCart.value = {
|
|
175
188
|
items: [{ product, price: product.stripePrice, quantity: 1 }],
|
|
176
189
|
};
|
|
190
|
+
return await new Promise<Transaction | undefined>((resolve) => {
|
|
191
|
+
stripeCallback.value = resolve;
|
|
192
|
+
});
|
|
177
193
|
// this should trigger the <StripePopup /> component
|
|
178
194
|
} else if (
|
|
179
195
|
product.platform === Platform.GOOGLE_PLAY ||
|
|
@@ -218,6 +234,8 @@ export const useIapStore = defineStore("iap", () => {
|
|
|
218
234
|
}
|
|
219
235
|
|
|
220
236
|
async function verify(p: Transaction) {
|
|
237
|
+
await ready();
|
|
238
|
+
|
|
221
239
|
let productId = p.products[0].id;
|
|
222
240
|
const product = products.value.find((p) => p.id === productId);
|
|
223
241
|
if (product) {
|
|
@@ -254,7 +272,22 @@ export const useIapStore = defineStore("iap", () => {
|
|
|
254
272
|
return store.products;
|
|
255
273
|
}
|
|
256
274
|
|
|
275
|
+
function ready(): boolean {
|
|
276
|
+
return new Promise((resolve) => {
|
|
277
|
+
watch(
|
|
278
|
+
isReady,
|
|
279
|
+
(ready) => {
|
|
280
|
+
if (isReady.value) {
|
|
281
|
+
resolve(ready);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
{ immediate: true }
|
|
285
|
+
);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
257
289
|
return {
|
|
290
|
+
products,
|
|
258
291
|
platform,
|
|
259
292
|
storePlatform,
|
|
260
293
|
initialize,
|
|
@@ -263,12 +296,18 @@ export const useIapStore = defineStore("iap", () => {
|
|
|
263
296
|
findPurchases,
|
|
264
297
|
verify,
|
|
265
298
|
purchases,
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
stripe
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
299
|
+
ready,
|
|
300
|
+
|
|
301
|
+
stripe: {
|
|
302
|
+
key: STRIP_KEY,
|
|
303
|
+
client: stripe,
|
|
304
|
+
loaded: stripeLoaded,
|
|
305
|
+
cart: stripeCart,
|
|
306
|
+
status: stripeStatus,
|
|
307
|
+
result: stripeResult,
|
|
308
|
+
callback: stripeCallback,
|
|
309
|
+
error: stripeError,
|
|
310
|
+
},
|
|
272
311
|
};
|
|
273
312
|
});
|
|
274
313
|
|
package/utils.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useRouter } from "vue-router";
|
|
2
|
+
import { useIapStore, Platform } from "./stores/iap";
|
|
3
|
+
import { nextTick } from "vue";
|
|
4
|
+
|
|
5
|
+
export function catchVerifiedPayments(router) {
|
|
6
|
+
router.beforeResolve(async (to, from, next) => {
|
|
7
|
+
if (to.query.stripe_session_id) {
|
|
8
|
+
const iap = useIapStore();
|
|
9
|
+
const cart = iap.stripe.cart;
|
|
10
|
+
await nextTick();
|
|
11
|
+
if (cart && cart.items.length > 0) {
|
|
12
|
+
const item = cart.items[0];
|
|
13
|
+
const transaction = {
|
|
14
|
+
products: [{ id: item.product.id }],
|
|
15
|
+
platform: Platform.STRIPE,
|
|
16
|
+
transactionId: `${to.query.stripe_session_id}`,
|
|
17
|
+
purchaseId: item.product.id,
|
|
18
|
+
finish: function (): void {},
|
|
19
|
+
};
|
|
20
|
+
const result = await iap.verify(transaction);
|
|
21
|
+
if (result) {
|
|
22
|
+
iap.stripe.result = transaction;
|
|
23
|
+
iap.stripe.status = "verified";
|
|
24
|
+
delete to.query.stripe_session_id;
|
|
25
|
+
}
|
|
26
|
+
next(to);
|
|
27
|
+
} else {
|
|
28
|
+
console.warn("Found stripe session, but cart is empty");
|
|
29
|
+
next();
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
next();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|