@medipass/checkout-sdk 3.0.0-alpha.0 → 3.0.0-alpha.1

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.
Files changed (39) hide show
  1. package/.eslintrc +40 -0
  2. package/CONTRIBUTING.md +21 -0
  3. package/dist/cjs/assets/index-e17dd0fd.css +1 -0
  4. package/dist/cjs/constants.d.ts +27 -0
  5. package/dist/cjs/index.d.ts +32 -0
  6. package/dist/cjs/initialiseWindow.d.ts +4 -0
  7. package/dist/cjs/overlay.d.ts +21 -0
  8. package/dist/cjs/requestUpdatePaymentDetails.d.ts +21 -0
  9. package/dist/cjs/updatePaymentOverlay.d.ts +21 -0
  10. package/dist/cjs/utils/object-to-css.d.ts +2 -0
  11. package/dist/esm/assets/index-e17dd0fd.css +1 -0
  12. package/dist/esm/constants.d.ts +27 -0
  13. package/dist/esm/index.d.ts +32 -0
  14. package/dist/esm/index.js +9 -0
  15. package/dist/esm/initialiseWindow.d.ts +4 -0
  16. package/dist/esm/overlay.d.ts +21 -0
  17. package/dist/esm/requestUpdatePaymentDetails.d.ts +21 -0
  18. package/dist/esm/updatePaymentOverlay.d.ts +21 -0
  19. package/dist/esm/utils/object-to-css.d.ts +2 -0
  20. package/dist/umd/assets/index.min-e17dd0fd.css +1 -0
  21. package/dist/umd/constants.d.ts +27 -0
  22. package/dist/umd/index.d.ts +32 -0
  23. package/dist/umd/index.min.js +17 -0
  24. package/dist/umd/initialiseWindow.d.ts +4 -0
  25. package/dist/umd/overlay.d.ts +21 -0
  26. package/dist/umd/requestUpdatePaymentDetails.d.ts +21 -0
  27. package/dist/umd/updatePaymentOverlay.d.ts +21 -0
  28. package/dist/umd/utils/object-to-css.d.ts +2 -0
  29. package/package.json +1 -6
  30. package/rollup.config.mjs +35 -0
  31. package/src/constants.ts +31 -0
  32. package/src/index.ts +244 -0
  33. package/src/initialiseWindow.ts +46 -0
  34. package/src/overlay.ts +272 -0
  35. package/src/requestUpdatePaymentDetails.ts +190 -0
  36. package/src/style.css +1 -0
  37. package/src/updatePaymentOverlay.ts +247 -0
  38. package/src/utils/object-to-css.ts +5 -0
  39. package/tsconfig.json +32 -0
@@ -0,0 +1,4 @@
1
+ declare function initialiseWindow({ url }: {
2
+ url: string;
3
+ }): Window | null | undefined;
4
+ export default initialiseWindow;
@@ -0,0 +1,21 @@
1
+ interface Overlay {
2
+ contentElement: HTMLElement | null;
3
+ removeOverlay: () => void;
4
+ createOverlay: ({ window, onClickRelaunch, onClickCancel, }: {
5
+ window: Window;
6
+ onClickRelaunch: () => void;
7
+ onClickCancel: () => void;
8
+ }) => void;
9
+ createSubHeading: ({ window, onClickRelaunch, onClickCancel, }: {
10
+ window: Window;
11
+ onClickRelaunch: () => void;
12
+ onClickCancel: () => void;
13
+ }) => HTMLElement | null;
14
+ updateSubHeading: ({ window, onClickRelaunch, onClickCancel, }: {
15
+ window: Window;
16
+ onClickRelaunch: () => void;
17
+ onClickCancel: () => void;
18
+ }) => void;
19
+ }
20
+ declare const overlay: Overlay;
21
+ export default overlay;
@@ -0,0 +1,21 @@
1
+ import { ENVS } from './constants';
2
+ interface UpdatePaymentDetailsBase {
3
+ patientRefId: string;
4
+ env: typeof ENVS[keyof typeof ENVS];
5
+ onSuccess: () => void;
6
+ onFailure: () => void;
7
+ onCancel: () => void;
8
+ onClose: () => void;
9
+ callbackOrigin: string;
10
+ }
11
+ interface UpdatePaymentDetailsWithApiKey extends UpdatePaymentDetailsBase {
12
+ apiKey: string;
13
+ token?: never;
14
+ }
15
+ interface UpdatePaymentDetailsWithToken extends UpdatePaymentDetailsBase {
16
+ token: string;
17
+ apiKey?: never;
18
+ }
19
+ export type UpdatePaymentDetails = UpdatePaymentDetailsWithApiKey | UpdatePaymentDetailsWithToken;
20
+ declare const updatePaymentDetails: ({ apiKey, token, patientRefId, env, onSuccess, onFailure, onCancel, onClose, callbackOrigin, }: UpdatePaymentDetails) => Promise<void>;
21
+ export default updatePaymentDetails;
@@ -0,0 +1,21 @@
1
+ interface Overlay {
2
+ contentElement: HTMLElement | null;
3
+ removeOverlay: () => void;
4
+ createOverlay: ({ window, onClickRelaunch, onClickCancel, }: {
5
+ window: Window;
6
+ onClickRelaunch: () => void;
7
+ onClickCancel: () => void;
8
+ }) => void;
9
+ createSubHeading: ({ window, onClickRelaunch, onClickCancel, }: {
10
+ window: Window;
11
+ onClickRelaunch: () => void;
12
+ onClickCancel: () => void;
13
+ }) => HTMLElement | null;
14
+ updateSubHeading: ({ window, onClickRelaunch, onClickCancel, }: {
15
+ window: Window;
16
+ onClickRelaunch: () => void;
17
+ onClickCancel: () => void;
18
+ }) => void;
19
+ }
20
+ declare const overlay: Overlay;
21
+ export default overlay;
@@ -0,0 +1,2 @@
1
+ declare const toCss: (style: Record<string, string>) => string;
2
+ export default toCss;
package/package.json CHANGED
@@ -1,14 +1,9 @@
1
1
  {
2
2
  "name": "@medipass/checkout-sdk",
3
- "version": "3.0.0-alpha.0",
3
+ "version": "3.0.0-alpha.1",
4
4
  "description": "Describe medipass-checkout-sdk here",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
7
- "files": [
8
- "es",
9
- "lib",
10
- "umd"
11
- ],
12
7
  "scripts": {
13
8
  "build": "yarn rollup -c",
14
9
  "build:types": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
@@ -0,0 +1,35 @@
1
+ import json from '@rollup/plugin-json';
2
+ import terser from '@rollup/plugin-terser';
3
+ import typescript from '@rollup/plugin-typescript';
4
+ import commonjs from '@rollup/plugin-commonjs';
5
+ import { nodeResolve } from '@rollup/plugin-node-resolve';
6
+ import nodePolyfills from 'rollup-plugin-polyfill-node';
7
+ import css from 'rollup-plugin-import-css';
8
+
9
+ export default {
10
+ input: './src/index.ts',
11
+ output: [
12
+ {
13
+ file: 'dist/cjs/index.js',
14
+ format: 'cjs',
15
+ },
16
+ {
17
+ file: 'dist/esm/index.js',
18
+ format: 'es',
19
+ },
20
+ {
21
+ file: 'dist/umd/index.min.js',
22
+ format: 'umd',
23
+ name: 'MedipassCheckoutSDK',
24
+ },
25
+ ],
26
+ plugins: [
27
+ json(),
28
+ terser(),
29
+ typescript(),
30
+ commonjs({ include: /node_modules/ }),
31
+ nodeResolve(),
32
+ nodePolyfills(),
33
+ css(),
34
+ ],
35
+ };
@@ -0,0 +1,31 @@
1
+ export const ENVS = {
2
+ LOCAL: 'local',
3
+ DEV: 'dev',
4
+ STG: 'stg',
5
+ PROD_BLUE: 'prod-blue',
6
+ PROD: 'prod',
7
+ } as const;
8
+
9
+ export const ORIGINS = {
10
+ [ENVS.LOCAL]: 'http://localhost:3001',
11
+ [ENVS.DEV]: 'https://dev-my.medipass.io',
12
+ [ENVS.STG]: 'https://stg-my.medipass.io',
13
+ [ENVS.PROD_BLUE]: 'https://my-blue.medipass.io',
14
+ [ENVS.PROD]: 'https://my.medipass.io',
15
+ } as const;
16
+
17
+ export const EVENTS = {
18
+ SUCCESS: 'success',
19
+ fAILURE: 'failure',
20
+ CANCEL: 'cancel',
21
+ } as const;
22
+
23
+ export const ERROR_MESSAGES = {
24
+ NO_API_KEY_OR_NO_TOKEN: 'apiKey or token is not provided',
25
+ NO_PATIENT_REF_ID: 'patientRefId is not provided',
26
+ NO_ENVIROMENT_SET: 'environment must be set',
27
+ NO_CALLBACK_ORIGIN: 'callbackOrigin must be set',
28
+ GENERAL_ERROR: 'Please ensure that all required values are passed',
29
+ } as const;
30
+
31
+ export const ROOT_ELEMENT_ID = 'medipass-checkout-sdk-root' as const;
package/src/index.ts ADDED
@@ -0,0 +1,244 @@
1
+ import _get from 'lodash/get';
2
+ import overlay from './overlay';
3
+ import { ORIGINS, ENVS, EVENTS } from './constants';
4
+ import './style.css';
5
+ import initialiseWindow from './initialiseWindow';
6
+ import updatePaymentDetails, { UpdatePaymentDetails } from './requestUpdatePaymentDetails';
7
+
8
+ ////////////////////////////////////////////////////////////
9
+
10
+ let _windowReferenceObject: Window | null | undefined = null;
11
+
12
+ ////////////////////////////////////////////////////////////
13
+
14
+ interface CheckoutSdk {
15
+ ENVS: typeof ENVS;
16
+ isCheckoutInitiated: boolean;
17
+ isCheckoutComplete: boolean | null;
18
+ env: typeof ENVS[keyof typeof ENVS] | null;
19
+ onSuccess: ((args: { transactionId: string }) => void) | null;
20
+ onFailure: ((args: { transactionId: string }) => void) | null;
21
+ onCancel: ((args: { transactionId: string }) => void) | null;
22
+ onClose: (() => void) | null;
23
+ init: (args: {
24
+ env: typeof ENVS[keyof typeof ENVS];
25
+ onSuccess: () => void;
26
+ onFailure: () => void;
27
+ onCancel: () => void;
28
+ onClose: () => void;
29
+ }) => void;
30
+ createCheckout: (args: { paymentRequestUrl: string }) => void;
31
+ requestUpdatePaymentDetails: (args: UpdatePaymentDetails) => void;
32
+ }
33
+
34
+ const checkoutSDK: CheckoutSdk = {
35
+ ENVS,
36
+ isCheckoutInitiated: false,
37
+ isCheckoutComplete: null,
38
+ env: null,
39
+ onSuccess: null,
40
+ onFailure: null,
41
+ onCancel: null,
42
+ onClose: null,
43
+
44
+ init({ env, onSuccess, onFailure, onCancel, onClose }) {
45
+ if (!env) return;
46
+
47
+ this.env = env;
48
+ this.onSuccess = onSuccess;
49
+ this.onFailure = onFailure;
50
+ this.onCancel = onCancel;
51
+ this.onClose = onClose;
52
+
53
+ // Open a blank window
54
+ _windowReferenceObject = initialiseWindow({ url: '' });
55
+
56
+ const handleClose = () => {
57
+ overlay.removeOverlay();
58
+ onClose && onClose();
59
+ if (!_windowReferenceObject) return;
60
+ _windowReferenceObject.close();
61
+ };
62
+
63
+ const onClickRelaunch = () => {
64
+ if (!_windowReferenceObject) {
65
+ _windowReferenceObject = initialiseWindow({ url: '' });
66
+ return;
67
+ }
68
+ _windowReferenceObject.focus();
69
+ };
70
+
71
+ const checkWindowClosed = () => {
72
+ if (this.isCheckoutInitiated) {
73
+ clearInterval(timer);
74
+ return;
75
+ }
76
+ if (_get(_windowReferenceObject, 'closed')) {
77
+ clearInterval(timer);
78
+ handleClose();
79
+ }
80
+ };
81
+
82
+ const onClickCancel = () => {
83
+ overlay.removeOverlay();
84
+ if (_windowReferenceObject) {
85
+ _windowReferenceObject.close();
86
+ }
87
+ clearInterval(timer);
88
+ onClose && onClose();
89
+ };
90
+
91
+ // This creates the gray overlay covering the client's screen while payment is in progress.
92
+ overlay.createOverlay({ window, onClickRelaunch, onClickCancel });
93
+
94
+ // Check the window every 0.5 seconds to see if it has been closed.
95
+ const timer = setInterval(checkWindowClosed, 500);
96
+ },
97
+
98
+ createCheckout({ paymentRequestUrl }: { paymentRequestUrl: string }) {
99
+ if (!paymentRequestUrl || !window) return;
100
+
101
+ const env = this.env;
102
+ const onSuccess = this.onSuccess;
103
+ const onFailure = this.onFailure;
104
+ const onCancel = this.onCancel;
105
+ const onClose = this.onClose;
106
+
107
+ ////////////////////////////////////////////////////////////
108
+
109
+ const checkWindowClosed = () => {
110
+ if (_get(_windowReferenceObject, 'closed')) {
111
+ clearInterval(timer);
112
+ handleClose();
113
+ }
114
+ };
115
+
116
+ // Check the window every 0.5 seconds to see if it has been closed.
117
+ const timer = setInterval(checkWindowClosed, 500);
118
+ this.isCheckoutInitiated = true;
119
+
120
+ ////////////////////////////////////////////////////////////
121
+
122
+ const openWindow = () => {
123
+ // windowReferenceObject may not be defined if browser blocks the pop-up.
124
+ if (!_windowReferenceObject) {
125
+ _windowReferenceObject = initialiseWindow({ url: paymentRequestUrl });
126
+ } else {
127
+ _windowReferenceObject.location.replace(paymentRequestUrl);
128
+ }
129
+
130
+ if (!_windowReferenceObject) {
131
+ return;
132
+ }
133
+
134
+ // Start listening for incoming messages
135
+ window.addEventListener('message', e => onReceiveMessage(e));
136
+
137
+ const onReceiveMessage = (e: MessageEvent<any>) => {
138
+ if (!e) return;
139
+ const transactionId = getMessage(e);
140
+ if (transactionId) {
141
+ this.isCheckoutComplete = true;
142
+ }
143
+ };
144
+
145
+ const getMessage = (e: MessageEvent<any>) => {
146
+ if (!env) return;
147
+
148
+ const origin = ORIGINS?.[env];
149
+
150
+ if (!e || !origin) return;
151
+
152
+ // Ensure the message is coming from the correct origin.
153
+ if (_get(e, 'origin') !== origin) return;
154
+
155
+ const event = _get(e, 'data.event');
156
+ const transactionId = _get(e, 'data.transactionId');
157
+ const receiptAutoSent = _get(e, 'data.receiptAutoSent');
158
+
159
+ if (!event || !transactionId) return;
160
+
161
+ if (event === EVENTS.SUCCESS) {
162
+ if (receiptAutoSent) {
163
+ // Give 1.5 seconds for the user to see the success page before auto-closing the pop-up.
164
+ setTimeout(() => {
165
+ onSuccess && onSuccess({ transactionId });
166
+ if (_windowReferenceObject) {
167
+ _windowReferenceObject.close();
168
+ }
169
+ }, 1500);
170
+ } else {
171
+ onSuccess && onSuccess({ transactionId });
172
+ }
173
+ return transactionId;
174
+ }
175
+ if (event === EVENTS.fAILURE) {
176
+ onFailure && onFailure({ transactionId });
177
+ return transactionId;
178
+ }
179
+ if (event === EVENTS.CANCEL) {
180
+ // Give 1.5 seconds for the user to see the reject page before auto-closing the pop-up.
181
+ setTimeout(() => {
182
+ onCancel && onCancel({ transactionId });
183
+ if (_windowReferenceObject) {
184
+ _windowReferenceObject.close();
185
+ }
186
+ }, 1500);
187
+ return transactionId;
188
+ }
189
+ };
190
+
191
+ return _windowReferenceObject;
192
+ };
193
+
194
+ ////////////////////////////////////////////////////////////
195
+
196
+ // open the pop-up
197
+ openWindow();
198
+
199
+ ////////////////////////////////////////////////////////////
200
+
201
+ const handleClose = () => {
202
+ // We need to remove the gray overlay covering the client's screen.
203
+ overlay.removeOverlay();
204
+ // If the pop-up has been closed before a payment action has been taken out, then we
205
+ // need to invoke the onClose callback.
206
+ if (!this.isCheckoutComplete) {
207
+ onClose && onClose();
208
+ }
209
+ if (!_windowReferenceObject) return;
210
+ _windowReferenceObject.close();
211
+ };
212
+
213
+ ////////////////////////////////////////////////////////////
214
+
215
+ const onClickRelaunch = () => {
216
+ if (!_windowReferenceObject) {
217
+ _windowReferenceObject = openWindow();
218
+ return;
219
+ }
220
+ _windowReferenceObject.focus();
221
+ };
222
+
223
+ const onClickCancel = () => {
224
+ if (_windowReferenceObject) {
225
+ _windowReferenceObject.close();
226
+ } else {
227
+ clearInterval(timer);
228
+ }
229
+
230
+ overlay.removeOverlay();
231
+ onClose && onClose();
232
+ };
233
+
234
+ // Reset the relaunch and cancel functions on the subheading
235
+ overlay.updateSubHeading({ window, onClickRelaunch, onClickCancel });
236
+
237
+ ////////////////////////////////////////////////////////////
238
+ },
239
+ requestUpdatePaymentDetails(args) {
240
+ updatePaymentDetails(args);
241
+ },
242
+ };
243
+
244
+ export default checkoutSDK;
@@ -0,0 +1,46 @@
1
+ import _get from 'lodash/get';
2
+
3
+ const POPUP_WIDTH = 450;
4
+
5
+ const getWindowFeatures = ({
6
+ height,
7
+ width,
8
+ left,
9
+ top,
10
+ }: {
11
+ height: number;
12
+ width: number;
13
+ left: number;
14
+ top: number;
15
+ }) =>
16
+ `menubar=no, location=no, resizable=no, scrollbars=yes, status=no, height=${height}, width=${width}, left=${left}, top=${top}`;
17
+
18
+ function initialiseWindow({ url }: { url: string }) {
19
+ if (!window) return;
20
+
21
+ // The target window could either be in an iframe, or just a normal standalone window.
22
+ // We need to grab the correct window height and width for calculating dimensions.
23
+ const windowHeight = _get(window, 'outerHeight') || _get(window, 'innerHeight');
24
+ const windowWidth = _get(window, 'outerWidth') || _get(window, 'innerWidth');
25
+
26
+ const popupHeight = windowHeight * 0.8;
27
+ const popupWidth = windowWidth > POPUP_WIDTH ? POPUP_WIDTH : windowWidth * 0.25;
28
+
29
+ const xPosition = windowWidth / 2 - popupWidth / 2;
30
+ const yPosition = windowHeight / 2 - popupHeight / 2;
31
+
32
+ const windowRef = window.open(
33
+ url,
34
+ 'Medipass Checkout',
35
+ getWindowFeatures({
36
+ height: popupHeight,
37
+ width: popupWidth,
38
+ left: xPosition,
39
+ top: yPosition,
40
+ }),
41
+ );
42
+
43
+ return windowRef;
44
+ }
45
+
46
+ export default initialiseWindow;