@amwaljs/magento-react-button 0.1.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.
package/README.md ADDED
@@ -0,0 +1,216 @@
1
+ # Amwal Magento React Button
2
+
3
+ A React component for integrating Amwal checkout functionality with Magento. This component provides a seamless checkout experience that works in conjunction with the Amwal Magento API Backend.
4
+
5
+ ## Prerequisites
6
+
7
+ Before using this component, ensure you have the [Amwal Magento Backend](https://docs.amwal.tech/docs/magento-installation) installed and configured.
8
+
9
+ ## Installation
10
+
11
+ Install the React component in your project:
12
+
13
+ ```bash
14
+ npm install @amwaljs/magento-react-button
15
+ ```
16
+
17
+ ## Basic Usage
18
+
19
+ ### Import the Component
20
+
21
+ ```javascript
22
+ import AmwalMagentoReactButton from '@amwaljs/magento-react-button'
23
+ ```
24
+
25
+ ### Product Page Implementation
26
+
27
+ For product pages, you'll need to handle adding items to cart before checkout:
28
+
29
+ ```javascript
30
+ const ProductPage = () => {
31
+ const submitAddToCart = async (): Promise<void> => {
32
+ if (!formSelector) return
33
+
34
+ const cartForm = document.querySelector(formSelector)
35
+ if (cartForm == null) throw new Error('Product form not found')
36
+
37
+ const formURL = cartForm.getAttribute('action') ?? window.location.href
38
+ if (!formURL) throw new Error('Product form URL not found')
39
+
40
+ await fetch(formURL, {
41
+ method: 'POST',
42
+ body: new FormData(cartForm as HTMLFormElement),
43
+ headers: {
44
+ 'X-Requested-With': 'XMLHttpRequest'
45
+ }
46
+ })
47
+ }
48
+
49
+ return (
50
+ <AmwalMagentoReactButton
51
+ triggerContext="product-page"
52
+ locale="en"
53
+ preCheckoutTask={submitAddToCart}
54
+ extraHeaders={{
55
+ 'x-access-token': 'your-access-token'
56
+ }}
57
+ buttonId="amwal-checkout-product"
58
+ redirectURL="/checkout/success"
59
+ />
60
+ )
61
+ }
62
+ ```
63
+
64
+ ### Cart/Mini-Cart Implementation
65
+
66
+ For cart or mini-cart pages, omit the `preCheckoutTask` since items are already in the cart:
67
+
68
+ ```javascript
69
+ const CartPage = () => {
70
+ return (
71
+ <AmwalMagentoReactButton
72
+ triggerContext="cart-page"
73
+ locale="en"
74
+ buttonId="amwal-checkout-cart"
75
+ overrideCartId={cartId}
76
+ redirectURL="/checkout/success"
77
+ />
78
+ )
79
+ }
80
+ ```
81
+
82
+ ## API Reference
83
+
84
+ ### Component Properties
85
+
86
+ #### Required Properties
87
+
88
+ | Property | Type | Description |
89
+ |----------|------|-------------|
90
+ | `triggerContext` | `string` | Context where the button is instantiated. Values: `product-page`, `cart-page`, `mini-cart`, `regular-checkout`, etc. |
91
+ | `buttonId` | `string` | Unique identifier for the button element. Required when multiple buttons exist on the same page. |
92
+
93
+ #### Optional Properties
94
+
95
+ ##### Localization & Configuration
96
+ | Property | Type | Default | Description |
97
+ |----------|------|---------|-------------|
98
+ | `locale` | `string` | `"en"` | The locale for rendering the button text and interface. |
99
+ | `baseUrl` | `string` | `"/rest/V1"` | Base URL for the Magento backend API endpoints. |
100
+ | `extraHeaders` | `Record<string, string>` | `{}` | Additional headers to include in API requests (e.g., authentication tokens). |
101
+ | `debug` | `boolean` | `false` | Enable debug logging in the browser console. |
102
+
103
+ ##### Cart & Checkout Behavior
104
+ | Property | Type | Description |
105
+ |----------|------|-------------|
106
+ | `overrideCartId` | `string` | Provide a specific cart ID instead of using the default session cart. |
107
+ | `emptyCartOnCancellation` | `boolean` | Whether to empty the cart when the user cancels checkout. |
108
+
109
+ ##### Callback Functions
110
+ | Property | Type | Description |
111
+ |----------|------|-------------|
112
+ | `preCheckoutTask` | `() => Promise<string \| undefined>` | Async function executed before checkout (e.g., add to cart). Can return a new cart ID. |
113
+ | `onSuccessTask` | `(info: ISuccessInfo) => Promise<void>` | Async function executed after successful transaction. |
114
+ | `onCancelTask` | `() => Promise<void>` | Async function executed when user cancels checkout. |
115
+
116
+ ##### Navigation & Redirects
117
+ | Property | Type | Description |
118
+ |----------|------|-------------|
119
+ | `redirectURL` | `string` | URL to redirect to after successful checkout (only if `performSuccessRedirection` is not provided). |
120
+ | `performSuccessRedirection` | `(orderId: string, incrementId: string) => void` | Custom function to handle post-checkout redirection with order details. |
121
+
122
+ ## Advanced Usage
123
+
124
+ ### Custom Success Handling
125
+
126
+ ```javascript
127
+ const handleSuccess = async (info) => {
128
+ console.log('Order completed:', info)
129
+ // Custom success logic here
130
+ }
131
+
132
+ const handleCustomRedirect = (orderId, incrementId) => {
133
+ window.location.href = `/order/success/${incrementId}`
134
+ }
135
+
136
+ <AmwalMagentoReactButton
137
+ triggerContext="cart-page"
138
+ buttonId="amwal-checkout-advanced"
139
+ onSuccessTask={handleSuccess}
140
+ performSuccessRedirection={handleCustomRedirect}
141
+ debug={true}
142
+ />
143
+ ```
144
+
145
+ ### With Authentication Headers
146
+
147
+ ```javascript
148
+ <AmwalMagentoReactButton
149
+ triggerContext="product-page"
150
+ buttonId="amwal-checkout-auth"
151
+ extraHeaders={{
152
+ 'Authorization': 'Bearer your-jwt-token',
153
+ 'X-Customer-ID': 'customer-id'
154
+ }}
155
+ baseUrl="/custom/api/v1"
156
+ />
157
+ ```
158
+
159
+ ## TypeScript Support
160
+
161
+ This component is written in TypeScript and includes type definitions. The `ISuccessInfo` interface provides type safety for success callbacks:
162
+
163
+ ```typescript
164
+ interface ISuccessInfo {
165
+ orderId: string
166
+ incrementId: string
167
+ // Additional success information
168
+ }
169
+ ```
170
+
171
+ ## Troubleshooting
172
+
173
+ ### Common Issues
174
+
175
+ #### Button Not Rendering
176
+ - Ensure the Amwal Magento Backend is properly installed and configured
177
+ - Check that the `buttonId` is unique on the page
178
+ - Verify API endpoints are accessible from your frontend
179
+
180
+ #### Checkout Not Working
181
+ - Confirm `triggerContext` matches your implementation context
182
+ - For product pages, ensure `preCheckoutTask` successfully adds items to cart
183
+ - Check browser console for errors when `debug` is enabled
184
+
185
+ #### Authentication Errors
186
+ - Verify `extraHeaders` contain valid authentication tokens
187
+ - Ensure your Magento backend accepts the provided headers
188
+ - Check API permissions for the authenticated user
189
+
190
+ ### Debug Mode
191
+
192
+ Enable debug mode to get detailed console logging:
193
+
194
+ ```javascript
195
+ <AmwalMagentoReactButton
196
+ triggerContext="cart-page"
197
+ buttonId="amwal-checkout-debug"
198
+ debug={true}
199
+ />
200
+ ```
201
+
202
+ ## Browser Compatibility
203
+
204
+ This component supports modern browsers with ES2017+ features:
205
+ - Chrome 60+
206
+ - Firefox 55+
207
+ - Safari 10.1+
208
+ - Edge 79+
209
+
210
+ ## License
211
+
212
+ This component is licensed under the same terms as the Amwal Magento extension.
213
+
214
+ ## Support
215
+
216
+ For support and documentation, visit [Amwal Documentation](https://docs.amwal.tech/) or contact the Amwal support team.
@@ -0,0 +1,22 @@
1
+ import { type ISuccessInfo } from './IAmwalButtonConfig';
2
+ interface AmwalMagentoReactButtonProps {
3
+ triggerContext: string;
4
+ locale?: string;
5
+ scopeCode?: string;
6
+ productId?: string;
7
+ buttonId?: string;
8
+ preCheckoutTask?: () => Promise<string | undefined>;
9
+ onSuccessTask?: (Info: ISuccessInfo) => Promise<void>;
10
+ onCancelTask?: () => Promise<void>;
11
+ emptyCartOnCancellation?: boolean;
12
+ baseUrl?: string;
13
+ extraHeaders?: Record<string, string>;
14
+ overrideCartId?: string;
15
+ redirectURL?: string;
16
+ performSuccessRedirection?: (orderId: string, IncrementId: string) => void;
17
+ debug?: boolean;
18
+ applePayCheckout?: boolean;
19
+ paymentMethod?: string;
20
+ }
21
+ declare const AmwalMagentoReactButton: ({ triggerContext, locale, scopeCode, productId, buttonId, preCheckoutTask, onSuccessTask, onCancelTask, emptyCartOnCancellation, baseUrl, extraHeaders, overrideCartId, redirectURL, performSuccessRedirection, debug, applePayCheckout, paymentMethod }: AmwalMagentoReactButtonProps) => JSX.Element;
22
+ export default AmwalMagentoReactButton;
@@ -0,0 +1,402 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ var jsx_runtime_1 = require("react/jsx-runtime");
54
+ var checkout_button_react_1 = require("@amwaljs/checkout-button-react");
55
+ var react_1 = __importDefault(require("react"));
56
+ var AmwalMagentoReactButton = function (_a) {
57
+ var triggerContext = _a.triggerContext, locale = _a.locale, scopeCode = _a.scopeCode, productId = _a.productId, buttonId = _a.buttonId, preCheckoutTask = _a.preCheckoutTask, onSuccessTask = _a.onSuccessTask, onCancelTask = _a.onCancelTask, _b = _a.emptyCartOnCancellation, emptyCartOnCancellation = _b === void 0 ? triggerContext === 'product-listing-page' || triggerContext === 'product-detail-page' || triggerContext === 'product-list-widget' || triggerContext === 'amwal-widget' : _b, _c = _a.baseUrl, baseUrl = _c === void 0 ? scopeCode ? "/rest/".concat(scopeCode, "/V1") : '/rest/V1' : _c, extraHeaders = _a.extraHeaders, overrideCartId = _a.overrideCartId, _d = _a.redirectURL, redirectURL = _d === void 0 ? '/checkout/onepage/success' : _d, _e = _a.performSuccessRedirection, performSuccessRedirection = _e === void 0 ? function () { window.location.href = redirectURL; } : _e, debug = _a.debug, applePayCheckout = _a.applePayCheckout, _f = _a.paymentMethod, paymentMethod = _f === void 0 ? 'amwal_payments' : _f;
58
+ var buttonRef = react_1.default.useRef(null);
59
+ var _g = react_1.default.useState(undefined), config = _g[0], setConfig = _g[1];
60
+ var _h = react_1.default.useState(0), amount = _h[0], setAmount = _h[1];
61
+ var _j = react_1.default.useState(0), taxes = _j[0], setTaxes = _j[1];
62
+ var _k = react_1.default.useState(0), discount = _k[0], setDiscount = _k[1];
63
+ var _l = react_1.default.useState(0), fees = _l[0], setFees = _l[1];
64
+ var _m = react_1.default.useState(''), feesDescription = _m[0], setFeesDescription = _m[1];
65
+ var _o = react_1.default.useState(undefined), cartId = _o[0], setCartId = _o[1];
66
+ var _p = react_1.default.useState([]), shippingMethods = _p[0], setShippingMethods = _p[1];
67
+ var _q = react_1.default.useState(undefined), placedOrderId = _q[0], setPlacedOrderId = _q[1];
68
+ var _r = react_1.default.useState(false), finishedUpdatingOrder = _r[0], setFinishedUpdatingOrder = _r[1];
69
+ var _s = react_1.default.useState(false), receivedSuccess = _s[0], setReceivedSuccess = _s[1];
70
+ var _t = react_1.default.useState(undefined), refIdData = _t[0], setRefIdData = _t[1];
71
+ var _u = react_1.default.useState(false), triggerPreCheckoutAck = _u[0], setTriggerPreCheckoutAck = _u[1];
72
+ var _v = react_1.default.useState(undefined), IncrementId = _v[0], setIncrementId = _v[1];
73
+ var paymentMethodLabels = {
74
+ amwal_payments: 'Quick Checkout',
75
+ amwal_payments_apple_pay: 'Pay with Apple Pay',
76
+ amwal_payments_bank_installments: 'Bank Installments'
77
+ };
78
+ var applyButtonConfig = function (data) {
79
+ var _a, _b, _c;
80
+ setConfig(data);
81
+ setAmount(data.amount);
82
+ setDiscount((_a = data.discount) !== null && _a !== void 0 ? _a : 0);
83
+ setTaxes((_b = data.tax) !== null && _b !== void 0 ? _b : 0);
84
+ setFees((_c = data.fees) !== null && _c !== void 0 ? _c : 0);
85
+ if (data.cart_id)
86
+ setCartId(data.cart_id);
87
+ };
88
+ react_1.default.useEffect(function () {
89
+ var initalRefIdData = {
90
+ identifier: '100',
91
+ customer_id: '0',
92
+ timestamp: Date.now()
93
+ };
94
+ setRefIdData(initalRefIdData);
95
+ fetch("".concat(baseUrl, "/amwal/button/cart"), {
96
+ method: 'POST',
97
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
98
+ body: JSON.stringify({
99
+ refIdData: initalRefIdData,
100
+ triggerContext: triggerContext,
101
+ cartId: overrideCartId !== null && overrideCartId !== void 0 ? overrideCartId : cartId,
102
+ productId: productId,
103
+ locale: locale
104
+ })
105
+ })
106
+ .then(function (response) { return __awaiter(void 0, void 0, void 0, function () {
107
+ var data;
108
+ return __generator(this, function (_a) {
109
+ switch (_a.label) {
110
+ case 0: return [4 /*yield*/, response.json()];
111
+ case 1:
112
+ data = _a.sent();
113
+ if (!response.ok)
114
+ throw new Error(data);
115
+ return [2 /*return*/, data];
116
+ }
117
+ });
118
+ }); })
119
+ .then(function (data) { applyButtonConfig(data); })
120
+ .catch(function (err) { console.error(err); });
121
+ }, []);
122
+ var getQuote = function (addressData) { return __awaiter(void 0, void 0, void 0, function () {
123
+ var response, data, quote, subtotal;
124
+ var _a;
125
+ return __generator(this, function (_b) {
126
+ switch (_b.label) {
127
+ case 0: return [4 /*yield*/, fetch("".concat(baseUrl, "/amwal/get-quote"), {
128
+ method: 'POST',
129
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
130
+ body: JSON.stringify({
131
+ ref_id: config === null || config === void 0 ? void 0 : config.ref_id,
132
+ address_data: addressData,
133
+ is_pre_checkout: false,
134
+ trigger_context: triggerContext,
135
+ ref_id_data: refIdData,
136
+ order_items: [],
137
+ cartId: overrideCartId !== null && overrideCartId !== void 0 ? overrideCartId : cartId,
138
+ productId: productId
139
+ })
140
+ })];
141
+ case 1:
142
+ response = _b.sent();
143
+ return [4 /*yield*/, response.json()];
144
+ case 2:
145
+ data = _b.sent();
146
+ if (!response.ok)
147
+ throw new Error((_a = data.message) !== null && _a !== void 0 ? _a : response.statusText);
148
+ if (data instanceof Array && data.length > 0) {
149
+ quote = data[0];
150
+ setCartId(quote.cart_id);
151
+ subtotal = parseFloat(quote.amount) -
152
+ parseFloat(quote.tax_amount) -
153
+ parseFloat(quote.shipping_amount) +
154
+ parseFloat(quote.discount_amount);
155
+ setAmount(subtotal);
156
+ setTaxes(quote.tax_amount);
157
+ setDiscount(quote.discount_amount);
158
+ setFees(quote.additional_fee_amount);
159
+ setFeesDescription(quote.additional_fee_description);
160
+ setShippingMethods(Object.entries(quote.available_rates).map(function (_a) {
161
+ var id = _a[0], rate = _a[1];
162
+ return {
163
+ id: id,
164
+ label: rate.carrier_title,
165
+ price: rate.price
166
+ };
167
+ }));
168
+ return [2 /*return*/, quote];
169
+ }
170
+ throw new Error("Unexpected get-quote result ".concat(JSON.stringify(data)));
171
+ }
172
+ });
173
+ }); };
174
+ var handleAmwalAddressUpdate = function (event) {
175
+ getQuote(event.detail)
176
+ .catch(function (err) {
177
+ var _a;
178
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalAddressTriggerError', {
179
+ detail: {
180
+ description: err === null || err === void 0 ? void 0 : err.toString(),
181
+ error: err === null || err === void 0 ? void 0 : err.toString()
182
+ }
183
+ }));
184
+ console.error(err);
185
+ });
186
+ };
187
+ react_1.default.useEffect(function () {
188
+ var _a;
189
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new Event('amwalAddressAck'));
190
+ }, [shippingMethods]);
191
+ var completeOrder = function (amwalOrderId) {
192
+ fetch("".concat(baseUrl, "/amwal/pay-order"), {
193
+ method: 'POST',
194
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
195
+ body: JSON.stringify({
196
+ order_id: placedOrderId,
197
+ amwal_order_id: amwalOrderId
198
+ })
199
+ })
200
+ .then(function (response) {
201
+ if (!response.ok)
202
+ return;
203
+ window.dispatchEvent(new CustomEvent('cartUpdateNeeded'));
204
+ if (onSuccessTask) {
205
+ onSuccessTask({ order_id: placedOrderId, amwal_transaction_id: amwalOrderId })
206
+ .catch(function (err) {
207
+ console.error(err);
208
+ })
209
+ .finally(function () {
210
+ setFinishedUpdatingOrder(true);
211
+ });
212
+ }
213
+ else {
214
+ setFinishedUpdatingOrder(true);
215
+ }
216
+ })
217
+ .catch(function (err) {
218
+ console.error(err);
219
+ });
220
+ };
221
+ var handleAmwalDismissed = function (event) {
222
+ var _a;
223
+ if (!event.detail.orderId)
224
+ return;
225
+ if (event.detail.paymentSuccessful) {
226
+ if (placedOrderId) {
227
+ completeOrder(event.detail.orderId);
228
+ }
229
+ }
230
+ else if (onCancelTask) {
231
+ onCancelTask()
232
+ .catch(function (err) {
233
+ console.error(err);
234
+ });
235
+ }
236
+ else if (emptyCartOnCancellation) {
237
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.setAttribute('disabled', 'true');
238
+ fetch("".concat(baseUrl, "/amwal/clean-quote"), {
239
+ method: 'POST',
240
+ headers: __assign(__assign({}, extraHeaders), { 'X-Requested-With': 'XMLHttpRequest' })
241
+ }).finally(function () {
242
+ var _a;
243
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.removeAttribute('disabled');
244
+ window.dispatchEvent(new CustomEvent('cartUpdateNeeded'));
245
+ });
246
+ }
247
+ };
248
+ var handleUpdateOrderOnPaymentsuccess = function (event) {
249
+ completeOrder(event.detail.orderId);
250
+ };
251
+ var handleAmwalCheckoutSuccess = function (_event) {
252
+ setReceivedSuccess(true); // coordinate with the updateOrderOnPaymentsuccess event
253
+ };
254
+ react_1.default.useEffect(function () {
255
+ var _a;
256
+ if (finishedUpdatingOrder && receivedSuccess) {
257
+ if (placedOrderId && IncrementId) {
258
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dismissModal().finally(function () {
259
+ performSuccessRedirection(placedOrderId, IncrementId);
260
+ });
261
+ }
262
+ else {
263
+ console.error('Unexpected state. placedOrderId is undefined after finished updating order and receiving success');
264
+ }
265
+ }
266
+ }, [finishedUpdatingOrder, receivedSuccess]);
267
+ var asyncHandleAmwalPrePayTrigger = function (event) { return __awaiter(void 0, void 0, void 0, function () {
268
+ var response, data;
269
+ var _a, _b, _c, _d;
270
+ return __generator(this, function (_e) {
271
+ switch (_e.label) {
272
+ case 0: return [4 /*yield*/, fetch("".concat(baseUrl, "/amwal/place-order"), {
273
+ method: 'POST',
274
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
275
+ body: JSON.stringify({
276
+ ref_id: config === null || config === void 0 ? void 0 : config.ref_id,
277
+ address_data: event.detail,
278
+ cartId: overrideCartId !== null && overrideCartId !== void 0 ? overrideCartId : cartId,
279
+ amwal_order_id: event.detail.id,
280
+ ref_id_data: refIdData,
281
+ trigger_context: triggerContext,
282
+ has_amwal_address: !(triggerContext === 'regular-checkout'),
283
+ card_bin: event.detail.card_bin,
284
+ payment_method: paymentMethod
285
+ })
286
+ })];
287
+ case 1:
288
+ response = _e.sent();
289
+ return [4 /*yield*/, response.json()];
290
+ case 2:
291
+ data = _e.sent();
292
+ if (response.ok) {
293
+ setPlacedOrderId(data.entity_id);
294
+ setIncrementId(data.increment_id);
295
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalPrePayTriggerAck', {
296
+ detail: __assign(__assign({ order_id: data.entity_id, order_total_amount: data.total_due }, (data.discount_description && { card_bin_additional_discount_message: data.discount_description })), (((_b = data.extension_attributes) === null || _b === void 0 ? void 0 : _b.amwal_card_bin_additional_discount) && { card_bin_additional_discount: data.extension_attributes.amwal_card_bin_additional_discount }))
297
+ }));
298
+ }
299
+ else {
300
+ (_c = buttonRef.current) === null || _c === void 0 ? void 0 : _c.dispatchEvent(new CustomEvent('amwalPrePayTriggerError', {
301
+ detail: {
302
+ description: "".concat((_d = data.message) !== null && _d !== void 0 ? _d : data).concat(data.parameters ? " ".concat(data.parameters.join(', ')) : '')
303
+ }
304
+ }));
305
+ }
306
+ return [2 /*return*/];
307
+ }
308
+ });
309
+ }); };
310
+ var handleAmwalPrePayTrigger = function (event) {
311
+ asyncHandleAmwalPrePayTrigger(event)
312
+ .catch(function (err) {
313
+ var _a;
314
+ console.error(err);
315
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalPrePayTriggerError', {
316
+ detail: {
317
+ description: err === null || err === void 0 ? void 0 : err.toString()
318
+ }
319
+ }));
320
+ });
321
+ };
322
+ var handleAmwalPreCheckoutTrigger = function (_event) {
323
+ var getConfig = function (preCheckoutCartId) { return __awaiter(void 0, void 0, void 0, function () {
324
+ var _a;
325
+ return __generator(this, function (_b) {
326
+ switch (_b.label) {
327
+ case 0: return [4 /*yield*/, fetch("".concat(baseUrl, "/amwal/button/cart"), {
328
+ method: 'POST',
329
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
330
+ body: JSON.stringify({
331
+ refIdData: refIdData,
332
+ triggerContext: triggerContext,
333
+ locale: locale,
334
+ cartId: (_a = preCheckoutCartId !== null && preCheckoutCartId !== void 0 ? preCheckoutCartId : overrideCartId) !== null && _a !== void 0 ? _a : cartId
335
+ })
336
+ })];
337
+ case 1: return [2 /*return*/, _b.sent()];
338
+ }
339
+ });
340
+ }); };
341
+ var preCheckoutPromise = (preCheckoutTask != null)
342
+ ? preCheckoutTask().then(function (preCheckoutCartId) { return __awaiter(void 0, void 0, void 0, function () {
343
+ var response;
344
+ return __generator(this, function (_a) {
345
+ switch (_a.label) {
346
+ case 0: return [4 /*yield*/, getConfig(preCheckoutCartId)];
347
+ case 1:
348
+ response = _a.sent();
349
+ if (preCheckoutCartId) {
350
+ setCartId(preCheckoutCartId);
351
+ }
352
+ return [2 /*return*/, response];
353
+ }
354
+ });
355
+ }); })
356
+ : getConfig();
357
+ preCheckoutPromise
358
+ .then(function (response) { return __awaiter(void 0, void 0, void 0, function () {
359
+ var data;
360
+ return __generator(this, function (_a) {
361
+ switch (_a.label) {
362
+ case 0: return [4 /*yield*/, response.json()];
363
+ case 1:
364
+ data = _a.sent();
365
+ if (!response.ok)
366
+ throw new Error(data);
367
+ return [2 /*return*/, data];
368
+ }
369
+ });
370
+ }); })
371
+ .then(function (data) {
372
+ applyButtonConfig(data);
373
+ setTriggerPreCheckoutAck(true);
374
+ })
375
+ .catch(function (err) {
376
+ var _a;
377
+ console.error(err);
378
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalPrePayTriggerError', {
379
+ detail: {
380
+ description: err === null || err === void 0 ? void 0 : err.toString()
381
+ }
382
+ }));
383
+ });
384
+ };
385
+ react_1.default.useEffect(function () {
386
+ var _a, _b;
387
+ if (triggerPreCheckoutAck) {
388
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalPreCheckoutTriggerAck', {
389
+ detail: {
390
+ order_content: config === null || config === void 0 ? void 0 : config.order_content,
391
+ order_position: triggerContext,
392
+ plugin_version: 'Magento ' + ((_b = config === null || config === void 0 ? void 0 : config.plugin_version) !== null && _b !== void 0 ? _b : '')
393
+ }
394
+ }));
395
+ setTriggerPreCheckoutAck(false);
396
+ }
397
+ }, [triggerPreCheckoutAck]);
398
+ return (config != null)
399
+ ? (0, jsx_runtime_1.jsx)(checkout_button_react_1.AmwalCheckoutButton, { ref: buttonRef, id: buttonId, amount: amount, taxes: taxes, discount: discount, fees: fees, feesDescription: feesDescription, shippingMethods: shippingMethods, merchantId: config.merchant_id, countryCode: config.country_code, darkMode: config.dark_mode, emailRequired: config.email_required, addressRequired: applePayCheckout ? false : config.address_required, refId: config.ref_id, label: paymentMethodLabels[paymentMethod] || 'Quick Checkout', showPaymentBrands: config.show_payment_brands, initialEmail: config.initial_email, initialPhoneNumber: config.initial_phone, initialAddress: config.initial_address, allowedAddressCities: config.allowed_address_cities, allowedAddressStates: config.allowed_address_states, allowedAddressCountries: JSON.stringify(config.allowed_address_countries), addressHandshake: true, sendExtraAddressFields: true, onAmwalAddressUpdate: handleAmwalAddressUpdate, onAmwalDismissed: handleAmwalDismissed, onAmwalCheckoutSuccess: handleAmwalCheckoutSuccess, enablePrePayTrigger: config.enable_pre_pay_trigger, onAmwalPrePayTrigger: handleAmwalPrePayTrigger, enablePreCheckoutTrigger: config.enable_pre_checkout_trigger, onAmwalPreCheckoutTrigger: handleAmwalPreCheckoutTrigger, onUpdateOrderOnPaymentsuccess: handleUpdateOrderOnPaymentsuccess, postcodeOptionalCountries: JSON.stringify(config.post_code_optional_countries), initialFirstName: config.initial_first_name, initialLastName: config.initial_last_name, showDiscountRibbon: config.show_discount_ribbon, installmentOptionsUrl: config.installment_options_url, locale: locale, debug: debug, onlyShowBankInstallment: paymentMethod === 'amwal_payments_bank_installments', enableAppleCheckout: applePayCheckout, timelineStyle: config.timeline_style, footerMessage: config.footer_message, apiUrl: config.api_url, payUrl: config.pay_url })
400
+ : (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {});
401
+ };
402
+ exports.default = AmwalMagentoReactButton;
@@ -0,0 +1,49 @@
1
+ import { type CitySpecs, type IAddress, type StateSpecs } from '@amwaljs/checkout-button';
2
+ import { type CountryCode } from 'libphonenumber-js';
3
+ export interface IAmwalButtonConfig {
4
+ merchant_id: string;
5
+ amount: number;
6
+ discount?: number;
7
+ fees?: number;
8
+ tax?: number;
9
+ country_code: CountryCode;
10
+ dark_mode: 'on' | 'off' | 'auto';
11
+ email_required: boolean;
12
+ address_required: boolean;
13
+ address_handshake: boolean;
14
+ ref_id: string;
15
+ label: 'Quick Checkout' | 'Pay with Apple Pay';
16
+ disabled: boolean;
17
+ show_payment_brands: boolean;
18
+ enable_pre_checkout_trigger: boolean;
19
+ enable_pre_pay_trigger: boolean;
20
+ id: string;
21
+ allowed_address_states: Record<string, StateSpecs>;
22
+ allowed_address_cities: Record<string, CitySpecs>;
23
+ allowed_address_countries: string[];
24
+ post_code_optional_countries: string[];
25
+ initial_address: IAddress;
26
+ initial_email: string;
27
+ initial_phone: string;
28
+ plugin_version: string;
29
+ initial_first_name: string;
30
+ initial_last_name: string;
31
+ installment_options_url: string;
32
+ cart_id: string;
33
+ show_discount_ribbon: boolean;
34
+ order_content: string[];
35
+ enable_bank_installments: boolean;
36
+ timeline_style: 'default' | 'simple';
37
+ footer_message: string;
38
+ api_url: string;
39
+ pay_url: string;
40
+ }
41
+ export interface IRefIdData {
42
+ identifier: string;
43
+ customer_id: string;
44
+ timestamp: number;
45
+ }
46
+ export interface ISuccessInfo {
47
+ order_id?: string;
48
+ amwal_transaction_id: string;
49
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ import AmwalMagentoReactButton from './AmwalMagentoReactButton';
2
+ export default AmwalMagentoReactButton;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ var AmwalMagentoReactButton_1 = __importDefault(require("./AmwalMagentoReactButton"));
7
+ exports.default = AmwalMagentoReactButton_1.default;
@@ -0,0 +1,22 @@
1
+ import { type ISuccessInfo } from './IAmwalButtonConfig';
2
+ interface AmwalMagentoReactButtonProps {
3
+ triggerContext: string;
4
+ locale?: string;
5
+ scopeCode?: string;
6
+ productId?: string;
7
+ buttonId?: string;
8
+ preCheckoutTask?: () => Promise<string | undefined>;
9
+ onSuccessTask?: (Info: ISuccessInfo) => Promise<void>;
10
+ onCancelTask?: () => Promise<void>;
11
+ emptyCartOnCancellation?: boolean;
12
+ baseUrl?: string;
13
+ extraHeaders?: Record<string, string>;
14
+ overrideCartId?: string;
15
+ redirectURL?: string;
16
+ performSuccessRedirection?: (orderId: string, IncrementId: string) => void;
17
+ debug?: boolean;
18
+ applePayCheckout?: boolean;
19
+ paymentMethod?: string;
20
+ }
21
+ declare const AmwalMagentoReactButton: ({ triggerContext, locale, scopeCode, productId, buttonId, preCheckoutTask, onSuccessTask, onCancelTask, emptyCartOnCancellation, baseUrl, extraHeaders, overrideCartId, redirectURL, performSuccessRedirection, debug, applePayCheckout, paymentMethod }: AmwalMagentoReactButtonProps) => JSX.Element;
22
+ export default AmwalMagentoReactButton;
@@ -0,0 +1,397 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
21
+ var __generator = (this && this.__generator) || function (thisArg, body) {
22
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
23
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24
+ function verb(n) { return function (v) { return step([n, v]); }; }
25
+ function step(op) {
26
+ if (f) throw new TypeError("Generator is already executing.");
27
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
28
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
29
+ if (y = 0, t) op = [op[0] & 2, t.value];
30
+ switch (op[0]) {
31
+ case 0: case 1: t = op; break;
32
+ case 4: _.label++; return { value: op[1], done: false };
33
+ case 5: _.label++; y = op[1]; op = [0]; continue;
34
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
35
+ default:
36
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40
+ if (t[2]) _.ops.pop();
41
+ _.trys.pop(); continue;
42
+ }
43
+ op = body.call(thisArg, _);
44
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
+ }
47
+ };
48
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
49
+ import { AmwalCheckoutButton } from '@amwaljs/checkout-button-react';
50
+ import React from 'react';
51
+ var AmwalMagentoReactButton = function (_a) {
52
+ var triggerContext = _a.triggerContext, locale = _a.locale, scopeCode = _a.scopeCode, productId = _a.productId, buttonId = _a.buttonId, preCheckoutTask = _a.preCheckoutTask, onSuccessTask = _a.onSuccessTask, onCancelTask = _a.onCancelTask, _b = _a.emptyCartOnCancellation, emptyCartOnCancellation = _b === void 0 ? triggerContext === 'product-listing-page' || triggerContext === 'product-detail-page' || triggerContext === 'product-list-widget' || triggerContext === 'amwal-widget' : _b, _c = _a.baseUrl, baseUrl = _c === void 0 ? scopeCode ? "/rest/".concat(scopeCode, "/V1") : '/rest/V1' : _c, extraHeaders = _a.extraHeaders, overrideCartId = _a.overrideCartId, _d = _a.redirectURL, redirectURL = _d === void 0 ? '/checkout/onepage/success' : _d, _e = _a.performSuccessRedirection, performSuccessRedirection = _e === void 0 ? function () { window.location.href = redirectURL; } : _e, debug = _a.debug, applePayCheckout = _a.applePayCheckout, _f = _a.paymentMethod, paymentMethod = _f === void 0 ? 'amwal_payments' : _f;
53
+ var buttonRef = React.useRef(null);
54
+ var _g = React.useState(undefined), config = _g[0], setConfig = _g[1];
55
+ var _h = React.useState(0), amount = _h[0], setAmount = _h[1];
56
+ var _j = React.useState(0), taxes = _j[0], setTaxes = _j[1];
57
+ var _k = React.useState(0), discount = _k[0], setDiscount = _k[1];
58
+ var _l = React.useState(0), fees = _l[0], setFees = _l[1];
59
+ var _m = React.useState(''), feesDescription = _m[0], setFeesDescription = _m[1];
60
+ var _o = React.useState(undefined), cartId = _o[0], setCartId = _o[1];
61
+ var _p = React.useState([]), shippingMethods = _p[0], setShippingMethods = _p[1];
62
+ var _q = React.useState(undefined), placedOrderId = _q[0], setPlacedOrderId = _q[1];
63
+ var _r = React.useState(false), finishedUpdatingOrder = _r[0], setFinishedUpdatingOrder = _r[1];
64
+ var _s = React.useState(false), receivedSuccess = _s[0], setReceivedSuccess = _s[1];
65
+ var _t = React.useState(undefined), refIdData = _t[0], setRefIdData = _t[1];
66
+ var _u = React.useState(false), triggerPreCheckoutAck = _u[0], setTriggerPreCheckoutAck = _u[1];
67
+ var _v = React.useState(undefined), IncrementId = _v[0], setIncrementId = _v[1];
68
+ var paymentMethodLabels = {
69
+ amwal_payments: 'Quick Checkout',
70
+ amwal_payments_apple_pay: 'Pay with Apple Pay',
71
+ amwal_payments_bank_installments: 'Bank Installments'
72
+ };
73
+ var applyButtonConfig = function (data) {
74
+ var _a, _b, _c;
75
+ setConfig(data);
76
+ setAmount(data.amount);
77
+ setDiscount((_a = data.discount) !== null && _a !== void 0 ? _a : 0);
78
+ setTaxes((_b = data.tax) !== null && _b !== void 0 ? _b : 0);
79
+ setFees((_c = data.fees) !== null && _c !== void 0 ? _c : 0);
80
+ if (data.cart_id)
81
+ setCartId(data.cart_id);
82
+ };
83
+ React.useEffect(function () {
84
+ var initalRefIdData = {
85
+ identifier: '100',
86
+ customer_id: '0',
87
+ timestamp: Date.now()
88
+ };
89
+ setRefIdData(initalRefIdData);
90
+ fetch("".concat(baseUrl, "/amwal/button/cart"), {
91
+ method: 'POST',
92
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
93
+ body: JSON.stringify({
94
+ refIdData: initalRefIdData,
95
+ triggerContext: triggerContext,
96
+ cartId: overrideCartId !== null && overrideCartId !== void 0 ? overrideCartId : cartId,
97
+ productId: productId,
98
+ locale: locale
99
+ })
100
+ })
101
+ .then(function (response) { return __awaiter(void 0, void 0, void 0, function () {
102
+ var data;
103
+ return __generator(this, function (_a) {
104
+ switch (_a.label) {
105
+ case 0: return [4 /*yield*/, response.json()];
106
+ case 1:
107
+ data = _a.sent();
108
+ if (!response.ok)
109
+ throw new Error(data);
110
+ return [2 /*return*/, data];
111
+ }
112
+ });
113
+ }); })
114
+ .then(function (data) { applyButtonConfig(data); })
115
+ .catch(function (err) { console.error(err); });
116
+ }, []);
117
+ var getQuote = function (addressData) { return __awaiter(void 0, void 0, void 0, function () {
118
+ var response, data, quote, subtotal;
119
+ var _a;
120
+ return __generator(this, function (_b) {
121
+ switch (_b.label) {
122
+ case 0: return [4 /*yield*/, fetch("".concat(baseUrl, "/amwal/get-quote"), {
123
+ method: 'POST',
124
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
125
+ body: JSON.stringify({
126
+ ref_id: config === null || config === void 0 ? void 0 : config.ref_id,
127
+ address_data: addressData,
128
+ is_pre_checkout: false,
129
+ trigger_context: triggerContext,
130
+ ref_id_data: refIdData,
131
+ order_items: [],
132
+ cartId: overrideCartId !== null && overrideCartId !== void 0 ? overrideCartId : cartId,
133
+ productId: productId
134
+ })
135
+ })];
136
+ case 1:
137
+ response = _b.sent();
138
+ return [4 /*yield*/, response.json()];
139
+ case 2:
140
+ data = _b.sent();
141
+ if (!response.ok)
142
+ throw new Error((_a = data.message) !== null && _a !== void 0 ? _a : response.statusText);
143
+ if (data instanceof Array && data.length > 0) {
144
+ quote = data[0];
145
+ setCartId(quote.cart_id);
146
+ subtotal = parseFloat(quote.amount) -
147
+ parseFloat(quote.tax_amount) -
148
+ parseFloat(quote.shipping_amount) +
149
+ parseFloat(quote.discount_amount);
150
+ setAmount(subtotal);
151
+ setTaxes(quote.tax_amount);
152
+ setDiscount(quote.discount_amount);
153
+ setFees(quote.additional_fee_amount);
154
+ setFeesDescription(quote.additional_fee_description);
155
+ setShippingMethods(Object.entries(quote.available_rates).map(function (_a) {
156
+ var id = _a[0], rate = _a[1];
157
+ return {
158
+ id: id,
159
+ label: rate.carrier_title,
160
+ price: rate.price
161
+ };
162
+ }));
163
+ return [2 /*return*/, quote];
164
+ }
165
+ throw new Error("Unexpected get-quote result ".concat(JSON.stringify(data)));
166
+ }
167
+ });
168
+ }); };
169
+ var handleAmwalAddressUpdate = function (event) {
170
+ getQuote(event.detail)
171
+ .catch(function (err) {
172
+ var _a;
173
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalAddressTriggerError', {
174
+ detail: {
175
+ description: err === null || err === void 0 ? void 0 : err.toString(),
176
+ error: err === null || err === void 0 ? void 0 : err.toString()
177
+ }
178
+ }));
179
+ console.error(err);
180
+ });
181
+ };
182
+ React.useEffect(function () {
183
+ var _a;
184
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new Event('amwalAddressAck'));
185
+ }, [shippingMethods]);
186
+ var completeOrder = function (amwalOrderId) {
187
+ fetch("".concat(baseUrl, "/amwal/pay-order"), {
188
+ method: 'POST',
189
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
190
+ body: JSON.stringify({
191
+ order_id: placedOrderId,
192
+ amwal_order_id: amwalOrderId
193
+ })
194
+ })
195
+ .then(function (response) {
196
+ if (!response.ok)
197
+ return;
198
+ window.dispatchEvent(new CustomEvent('cartUpdateNeeded'));
199
+ if (onSuccessTask) {
200
+ onSuccessTask({ order_id: placedOrderId, amwal_transaction_id: amwalOrderId })
201
+ .catch(function (err) {
202
+ console.error(err);
203
+ })
204
+ .finally(function () {
205
+ setFinishedUpdatingOrder(true);
206
+ });
207
+ }
208
+ else {
209
+ setFinishedUpdatingOrder(true);
210
+ }
211
+ })
212
+ .catch(function (err) {
213
+ console.error(err);
214
+ });
215
+ };
216
+ var handleAmwalDismissed = function (event) {
217
+ var _a;
218
+ if (!event.detail.orderId)
219
+ return;
220
+ if (event.detail.paymentSuccessful) {
221
+ if (placedOrderId) {
222
+ completeOrder(event.detail.orderId);
223
+ }
224
+ }
225
+ else if (onCancelTask) {
226
+ onCancelTask()
227
+ .catch(function (err) {
228
+ console.error(err);
229
+ });
230
+ }
231
+ else if (emptyCartOnCancellation) {
232
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.setAttribute('disabled', 'true');
233
+ fetch("".concat(baseUrl, "/amwal/clean-quote"), {
234
+ method: 'POST',
235
+ headers: __assign(__assign({}, extraHeaders), { 'X-Requested-With': 'XMLHttpRequest' })
236
+ }).finally(function () {
237
+ var _a;
238
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.removeAttribute('disabled');
239
+ window.dispatchEvent(new CustomEvent('cartUpdateNeeded'));
240
+ });
241
+ }
242
+ };
243
+ var handleUpdateOrderOnPaymentsuccess = function (event) {
244
+ completeOrder(event.detail.orderId);
245
+ };
246
+ var handleAmwalCheckoutSuccess = function (_event) {
247
+ setReceivedSuccess(true); // coordinate with the updateOrderOnPaymentsuccess event
248
+ };
249
+ React.useEffect(function () {
250
+ var _a;
251
+ if (finishedUpdatingOrder && receivedSuccess) {
252
+ if (placedOrderId && IncrementId) {
253
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dismissModal().finally(function () {
254
+ performSuccessRedirection(placedOrderId, IncrementId);
255
+ });
256
+ }
257
+ else {
258
+ console.error('Unexpected state. placedOrderId is undefined after finished updating order and receiving success');
259
+ }
260
+ }
261
+ }, [finishedUpdatingOrder, receivedSuccess]);
262
+ var asyncHandleAmwalPrePayTrigger = function (event) { return __awaiter(void 0, void 0, void 0, function () {
263
+ var response, data;
264
+ var _a, _b, _c, _d;
265
+ return __generator(this, function (_e) {
266
+ switch (_e.label) {
267
+ case 0: return [4 /*yield*/, fetch("".concat(baseUrl, "/amwal/place-order"), {
268
+ method: 'POST',
269
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
270
+ body: JSON.stringify({
271
+ ref_id: config === null || config === void 0 ? void 0 : config.ref_id,
272
+ address_data: event.detail,
273
+ cartId: overrideCartId !== null && overrideCartId !== void 0 ? overrideCartId : cartId,
274
+ amwal_order_id: event.detail.id,
275
+ ref_id_data: refIdData,
276
+ trigger_context: triggerContext,
277
+ has_amwal_address: !(triggerContext === 'regular-checkout'),
278
+ card_bin: event.detail.card_bin,
279
+ payment_method: paymentMethod
280
+ })
281
+ })];
282
+ case 1:
283
+ response = _e.sent();
284
+ return [4 /*yield*/, response.json()];
285
+ case 2:
286
+ data = _e.sent();
287
+ if (response.ok) {
288
+ setPlacedOrderId(data.entity_id);
289
+ setIncrementId(data.increment_id);
290
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalPrePayTriggerAck', {
291
+ detail: __assign(__assign({ order_id: data.entity_id, order_total_amount: data.total_due }, (data.discount_description && { card_bin_additional_discount_message: data.discount_description })), (((_b = data.extension_attributes) === null || _b === void 0 ? void 0 : _b.amwal_card_bin_additional_discount) && { card_bin_additional_discount: data.extension_attributes.amwal_card_bin_additional_discount }))
292
+ }));
293
+ }
294
+ else {
295
+ (_c = buttonRef.current) === null || _c === void 0 ? void 0 : _c.dispatchEvent(new CustomEvent('amwalPrePayTriggerError', {
296
+ detail: {
297
+ description: "".concat((_d = data.message) !== null && _d !== void 0 ? _d : data).concat(data.parameters ? " ".concat(data.parameters.join(', ')) : '')
298
+ }
299
+ }));
300
+ }
301
+ return [2 /*return*/];
302
+ }
303
+ });
304
+ }); };
305
+ var handleAmwalPrePayTrigger = function (event) {
306
+ asyncHandleAmwalPrePayTrigger(event)
307
+ .catch(function (err) {
308
+ var _a;
309
+ console.error(err);
310
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalPrePayTriggerError', {
311
+ detail: {
312
+ description: err === null || err === void 0 ? void 0 : err.toString()
313
+ }
314
+ }));
315
+ });
316
+ };
317
+ var handleAmwalPreCheckoutTrigger = function (_event) {
318
+ var getConfig = function (preCheckoutCartId) { return __awaiter(void 0, void 0, void 0, function () {
319
+ var _a;
320
+ return __generator(this, function (_b) {
321
+ switch (_b.label) {
322
+ case 0: return [4 /*yield*/, fetch("".concat(baseUrl, "/amwal/button/cart"), {
323
+ method: 'POST',
324
+ headers: __assign(__assign({}, extraHeaders), { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }),
325
+ body: JSON.stringify({
326
+ refIdData: refIdData,
327
+ triggerContext: triggerContext,
328
+ locale: locale,
329
+ cartId: (_a = preCheckoutCartId !== null && preCheckoutCartId !== void 0 ? preCheckoutCartId : overrideCartId) !== null && _a !== void 0 ? _a : cartId
330
+ })
331
+ })];
332
+ case 1: return [2 /*return*/, _b.sent()];
333
+ }
334
+ });
335
+ }); };
336
+ var preCheckoutPromise = (preCheckoutTask != null)
337
+ ? preCheckoutTask().then(function (preCheckoutCartId) { return __awaiter(void 0, void 0, void 0, function () {
338
+ var response;
339
+ return __generator(this, function (_a) {
340
+ switch (_a.label) {
341
+ case 0: return [4 /*yield*/, getConfig(preCheckoutCartId)];
342
+ case 1:
343
+ response = _a.sent();
344
+ if (preCheckoutCartId) {
345
+ setCartId(preCheckoutCartId);
346
+ }
347
+ return [2 /*return*/, response];
348
+ }
349
+ });
350
+ }); })
351
+ : getConfig();
352
+ preCheckoutPromise
353
+ .then(function (response) { return __awaiter(void 0, void 0, void 0, function () {
354
+ var data;
355
+ return __generator(this, function (_a) {
356
+ switch (_a.label) {
357
+ case 0: return [4 /*yield*/, response.json()];
358
+ case 1:
359
+ data = _a.sent();
360
+ if (!response.ok)
361
+ throw new Error(data);
362
+ return [2 /*return*/, data];
363
+ }
364
+ });
365
+ }); })
366
+ .then(function (data) {
367
+ applyButtonConfig(data);
368
+ setTriggerPreCheckoutAck(true);
369
+ })
370
+ .catch(function (err) {
371
+ var _a;
372
+ console.error(err);
373
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalPrePayTriggerError', {
374
+ detail: {
375
+ description: err === null || err === void 0 ? void 0 : err.toString()
376
+ }
377
+ }));
378
+ });
379
+ };
380
+ React.useEffect(function () {
381
+ var _a, _b;
382
+ if (triggerPreCheckoutAck) {
383
+ (_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new CustomEvent('amwalPreCheckoutTriggerAck', {
384
+ detail: {
385
+ order_content: config === null || config === void 0 ? void 0 : config.order_content,
386
+ order_position: triggerContext,
387
+ plugin_version: 'Magento ' + ((_b = config === null || config === void 0 ? void 0 : config.plugin_version) !== null && _b !== void 0 ? _b : '')
388
+ }
389
+ }));
390
+ setTriggerPreCheckoutAck(false);
391
+ }
392
+ }, [triggerPreCheckoutAck]);
393
+ return (config != null)
394
+ ? _jsx(AmwalCheckoutButton, { ref: buttonRef, id: buttonId, amount: amount, taxes: taxes, discount: discount, fees: fees, feesDescription: feesDescription, shippingMethods: shippingMethods, merchantId: config.merchant_id, countryCode: config.country_code, darkMode: config.dark_mode, emailRequired: config.email_required, addressRequired: applePayCheckout ? false : config.address_required, refId: config.ref_id, label: paymentMethodLabels[paymentMethod] || 'Quick Checkout', showPaymentBrands: config.show_payment_brands, initialEmail: config.initial_email, initialPhoneNumber: config.initial_phone, initialAddress: config.initial_address, allowedAddressCities: config.allowed_address_cities, allowedAddressStates: config.allowed_address_states, allowedAddressCountries: JSON.stringify(config.allowed_address_countries), addressHandshake: true, sendExtraAddressFields: true, onAmwalAddressUpdate: handleAmwalAddressUpdate, onAmwalDismissed: handleAmwalDismissed, onAmwalCheckoutSuccess: handleAmwalCheckoutSuccess, enablePrePayTrigger: config.enable_pre_pay_trigger, onAmwalPrePayTrigger: handleAmwalPrePayTrigger, enablePreCheckoutTrigger: config.enable_pre_checkout_trigger, onAmwalPreCheckoutTrigger: handleAmwalPreCheckoutTrigger, onUpdateOrderOnPaymentsuccess: handleUpdateOrderOnPaymentsuccess, postcodeOptionalCountries: JSON.stringify(config.post_code_optional_countries), initialFirstName: config.initial_first_name, initialLastName: config.initial_last_name, showDiscountRibbon: config.show_discount_ribbon, installmentOptionsUrl: config.installment_options_url, locale: locale, debug: debug, onlyShowBankInstallment: paymentMethod === 'amwal_payments_bank_installments', enableAppleCheckout: applePayCheckout, timelineStyle: config.timeline_style, footerMessage: config.footer_message, apiUrl: config.api_url, payUrl: config.pay_url })
395
+ : _jsx(_Fragment, {});
396
+ };
397
+ export default AmwalMagentoReactButton;
@@ -0,0 +1,49 @@
1
+ import { type CitySpecs, type IAddress, type StateSpecs } from '@amwaljs/checkout-button';
2
+ import { type CountryCode } from 'libphonenumber-js';
3
+ export interface IAmwalButtonConfig {
4
+ merchant_id: string;
5
+ amount: number;
6
+ discount?: number;
7
+ fees?: number;
8
+ tax?: number;
9
+ country_code: CountryCode;
10
+ dark_mode: 'on' | 'off' | 'auto';
11
+ email_required: boolean;
12
+ address_required: boolean;
13
+ address_handshake: boolean;
14
+ ref_id: string;
15
+ label: 'Quick Checkout' | 'Pay with Apple Pay';
16
+ disabled: boolean;
17
+ show_payment_brands: boolean;
18
+ enable_pre_checkout_trigger: boolean;
19
+ enable_pre_pay_trigger: boolean;
20
+ id: string;
21
+ allowed_address_states: Record<string, StateSpecs>;
22
+ allowed_address_cities: Record<string, CitySpecs>;
23
+ allowed_address_countries: string[];
24
+ post_code_optional_countries: string[];
25
+ initial_address: IAddress;
26
+ initial_email: string;
27
+ initial_phone: string;
28
+ plugin_version: string;
29
+ initial_first_name: string;
30
+ initial_last_name: string;
31
+ installment_options_url: string;
32
+ cart_id: string;
33
+ show_discount_ribbon: boolean;
34
+ order_content: string[];
35
+ enable_bank_installments: boolean;
36
+ timeline_style: 'default' | 'simple';
37
+ footer_message: string;
38
+ api_url: string;
39
+ pay_url: string;
40
+ }
41
+ export interface IRefIdData {
42
+ identifier: string;
43
+ customer_id: string;
44
+ timestamp: number;
45
+ }
46
+ export interface ISuccessInfo {
47
+ order_id?: string;
48
+ amwal_transaction_id: string;
49
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import AmwalMagentoReactButton from './AmwalMagentoReactButton';
2
+ export default AmwalMagentoReactButton;
@@ -0,0 +1,2 @@
1
+ import AmwalMagentoReactButton from './AmwalMagentoReactButton';
2
+ export default AmwalMagentoReactButton;
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@amwaljs/magento-react-button",
3
+ "sideEffects": false,
4
+ "version": "0.1.0",
5
+ "description": "Amwal Magento Headless React Button",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/amwal-tech/amwal-magento"
9
+ },
10
+ "scripts": {
11
+ "build": "npm run clean && npm run compile",
12
+ "clean": "rm -rf dist",
13
+ "compile:cjs": "tsc --project tsconfig.cjs.json",
14
+ "compile:esm": "tsc --project tsconfig.esm.json",
15
+ "compile": "npm run compile:cjs && npm run compile:esm",
16
+ "rollup": "rollup -c"
17
+ },
18
+ "main": "./dist/cjs/index.js",
19
+ "module": "./dist/esm/index.js",
20
+ "types": "./dist/esm/index.d.ts",
21
+ "files": [
22
+ "dist/"
23
+ ],
24
+ "devDependencies": {
25
+ "@types/react": "^18.2.15",
26
+ "@typescript-eslint/eslint-plugin": "^5.62.0",
27
+ "eslint": "^8.45.0",
28
+ "eslint-config-standard-with-typescript": "^37.0.0",
29
+ "eslint-plugin-import": "^2.27.5",
30
+ "eslint-plugin-n": "^16.0.1",
31
+ "eslint-plugin-promise": "^6.1.1",
32
+ "eslint-plugin-react": "^7.33.0",
33
+ "react": "^18.2.0",
34
+ "react-dom": "^18.2.0",
35
+ "typescript": "^5.1.6"
36
+ },
37
+ "peerDependencies": {
38
+ "react": "*",
39
+ "react-dom": "*"
40
+ },
41
+ "dependencies": {
42
+ "@amwaljs/checkout-button": "^0.2.9",
43
+ "@amwaljs/checkout-button-react": "^0.2.9"
44
+ }
45
+ }