@parafin/react 6.0.0-alpha.1 → 6.0.0-alpha.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/out/index.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { WidgetProps, OptInFields } from '@parafin/widget';
2
+ declare const ParafinWidget: (props: WidgetProps) => import("react/jsx-runtime").JSX.Element;
3
+ export { ParafinWidget };
4
+ export type { OptInFields };
package/out/index.js ADDED
@@ -0,0 +1,146 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useRef, useEffect } from 'react';
3
+
4
+ const openParafinDashboard = (props) => {
5
+ try {
6
+ const { origin, searchParams } = new URL(
7
+ // @ts-ignore
8
+ props.dashboardUrlOverride ?? 'https://app.parafin.com');
9
+ const route = 'route' in props ? props.route : '/';
10
+ const query = {
11
+ product: props.product,
12
+ referrer: 'partner',
13
+ ...('token' in props && { token: props.token }),
14
+ ...('externalBusinessId' in props && {
15
+ externalBusinessId: props.externalBusinessId,
16
+ }),
17
+ ...('orderId' in props && { orderId: props.orderId }),
18
+ ...('orderAmount' in props && {
19
+ orderAmount: props.orderAmount.toString(),
20
+ }),
21
+ ...('additionalQueryParams' in props && props.additionalQueryParams),
22
+ ...Object.fromEntries(searchParams),
23
+ };
24
+ const url = `${origin}${route}?${new URLSearchParams(query).toString()}`;
25
+ if ('openInNewTab' in props && props.openInNewTab) {
26
+ window.open(url, '_blank');
27
+ return;
28
+ }
29
+ const existingParafinDashboard = document.getElementById('parafin-dashboard');
30
+ if (existingParafinDashboard) {
31
+ document.removeChild(existingParafinDashboard);
32
+ }
33
+ const frame = document.createElement('iframe');
34
+ frame.id = 'parafin-dashboard';
35
+ frame.style.position = 'fixed';
36
+ frame.style.top = '0';
37
+ frame.style.left = '0';
38
+ frame.style.width = '100%';
39
+ frame.style.height = '100%';
40
+ frame.style.border = 'none';
41
+ frame.style.zIndex = '2147483647';
42
+ frame.style.backgroundColor = '#fff';
43
+ frame.style.opacity = '0';
44
+ frame.style.transition = 'opacity 0.2s';
45
+ frame.src = url;
46
+ frame.allow = 'accelerometer; gyroscope; clipboard-read; clipboard-write';
47
+ const parse = (message) => (message ? JSON.parse(message) : undefined);
48
+ const closeParafinDashboard = (e) => {
49
+ if (e.origin === origin && e.data?.message === 'close-dashboard') {
50
+ if (props.product === 'bnpl' && props.flow === 'checkout') {
51
+ props.onExit(parse(e.data.order));
52
+ }
53
+ else {
54
+ props.onExit?.();
55
+ }
56
+ window.removeEventListener('message', closeParafinDashboard);
57
+ frame.style.opacity = '0';
58
+ setTimeout(() => document.body.removeChild(frame), 200);
59
+ }
60
+ };
61
+ window.addEventListener('message', closeParafinDashboard);
62
+ document.body.appendChild(frame);
63
+ setTimeout(() => (frame.style.opacity = '1'), 1);
64
+ }
65
+ catch (error) {
66
+ console.error('Error loading Parafin dashboard', error);
67
+ }
68
+ };
69
+
70
+ const initializeWidget = (iframe, props) => {
71
+ // @ts-ignore
72
+ const url = new URL(props.widgetUrlOverride ?? 'https://widget.parafin.com');
73
+ const query = {
74
+ token: props.token,
75
+ product: props.product,
76
+ hasOptIn: props.onOptIn ? 'true' : 'false',
77
+ host: window.location.origin,
78
+ externalBusinessId: props.externalBusinessId ?? '',
79
+ ...Object.fromEntries(url.searchParams),
80
+ };
81
+ iframe.id = `parafin-${props.product}-widget`;
82
+ iframe.src = `${url.origin}?${new URLSearchParams(query).toString()}`;
83
+ const resetIframe = () => {
84
+ iframe.src = `${url.origin}?${new URLSearchParams(query).toString()}`;
85
+ };
86
+ // Message handler
87
+ const messageListener = async ({ data, origin }) => {
88
+ if (origin === url.origin && data?.product === props.product) {
89
+ switch (data?.message) {
90
+ case 'set-border':
91
+ if (data?.borderColor) {
92
+ iframe.style.border = `1px solid ${data.borderColor}`;
93
+ }
94
+ if (data?.borderRadius) {
95
+ iframe.style.borderRadius = data.borderRadius;
96
+ }
97
+ break;
98
+ case 'open-dashboard':
99
+ openParafinDashboard({
100
+ ...props,
101
+ route: data?.route,
102
+ onExit: () => {
103
+ resetIframe();
104
+ props.onExit?.();
105
+ },
106
+ });
107
+ break;
108
+ case 'opt-in':
109
+ if (props.onOptIn) {
110
+ const optInFields = await props.onOptIn();
111
+ iframe.contentWindow?.postMessage({ message: 'opt-in', optInFields }, url.origin);
112
+ }
113
+ break;
114
+ case 'set-height':
115
+ if (data?.height) {
116
+ iframe.style.height = data.height;
117
+ }
118
+ break;
119
+ }
120
+ }
121
+ };
122
+ window.addEventListener('message', messageListener);
123
+ return () => window.removeEventListener('message', messageListener);
124
+ };
125
+ const defaultWidgetStyles = {
126
+ width: '100%',
127
+ height: '258px',
128
+ backgroundColor: '#fff',
129
+ border: '1px solid #E8E8E8',
130
+ borderRadius: '16px',
131
+ transition: 'border 0.2s, border-radius 0.2s',
132
+ boxSizing: 'border-box',
133
+ };
134
+
135
+ const ParafinWidget = (props) => {
136
+ const frameRef = useRef(null);
137
+ useEffect(() => {
138
+ if (frameRef.current) {
139
+ const cleanup = initializeWidget(frameRef.current, props);
140
+ return cleanup;
141
+ }
142
+ }, [props]);
143
+ return jsx("iframe", { ref: frameRef, style: defaultWidgetStyles });
144
+ };
145
+
146
+ export { ParafinWidget };
package/package.json CHANGED
@@ -1,24 +1,27 @@
1
1
  {
2
2
  "name": "@parafin/react",
3
- "version": "6.0.0-alpha.1",
3
+ "version": "6.0.0-alpha.3",
4
4
  "description": "Parafin React widget",
5
5
  "author": "Parafin (https://www.parafin.com)",
6
6
  "module": "out/index.js",
7
7
  "types": "out/index.d.ts",
8
8
  "type": "module",
9
9
  "license": "MIT",
10
+ "files": [
11
+ "out"
12
+ ],
10
13
  "scripts": {
11
14
  "build": "npx rollup -c",
12
- "dev": "npx rollup -c -w"
15
+ "dev": "npx rollup -c -w",
16
+ "prepublishOnly": "yarn build"
13
17
  },
14
18
  "peerDependencies": {
15
19
  "react": ">=16.8.0"
16
20
  },
17
21
  "devDependencies": {
18
22
  "@types/react": ">=16.8.0",
19
- "typescript": "^4.9.5"
20
- },
21
- "dependencies": {
23
+ "typescript": "^4.9.5",
22
24
  "@parafin/widget": "*"
23
- }
25
+ },
26
+ "dependencies": {}
24
27
  }
package/index.tsx DELETED
@@ -1,23 +0,0 @@
1
- import { useEffect, useRef } from 'react'
2
- import {
3
- initializeWidget,
4
- defaultWidgetStyles,
5
- WidgetProps,
6
- OptInFields,
7
- } from '@parafin/widget'
8
-
9
- const ParafinWidget = (props: WidgetProps) => {
10
- const frameRef = useRef<HTMLIFrameElement>(null)
11
-
12
- useEffect(() => {
13
- if (frameRef.current) {
14
- const cleanup = initializeWidget(frameRef.current, props)
15
- return cleanup
16
- }
17
- }, [props])
18
-
19
- return <iframe ref={frameRef} style={defaultWidgetStyles} />
20
- }
21
-
22
- export { ParafinWidget }
23
- export type { OptInFields }
package/rollup.config.js DELETED
@@ -1,34 +0,0 @@
1
- import resolve from '@rollup/plugin-node-resolve'
2
- import commonjs from '@rollup/plugin-commonjs'
3
- import typescript from '@rollup/plugin-typescript'
4
- import peerDepsExternal from 'rollup-plugin-peer-deps-external'
5
- import { fileURLToPath } from 'url'
6
- import { dirname } from 'path'
7
-
8
- const __filename = fileURLToPath(import.meta.url)
9
- const __dirname = dirname(__filename)
10
-
11
- export default {
12
- input: './index.tsx',
13
- output: [
14
- {
15
- file: './out/index.js',
16
- format: 'esm',
17
- sourcemap: false,
18
- },
19
- ],
20
- external: ['react', 'react-dom'],
21
- plugins: [
22
- peerDepsExternal(),
23
- resolve({
24
- extensions: ['.ts', '.tsx', '.js', '.jsx'],
25
- }),
26
- commonjs(),
27
- typescript({
28
- tsconfig: `${__dirname}/tsconfig.json`,
29
- declaration: true,
30
- declarationDir: './out',
31
- rootDir: './',
32
- }),
33
- ],
34
- }
package/tsconfig.json DELETED
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "esnext",
4
- "module": "esnext",
5
- "moduleResolution": "node",
6
- "jsx": "react-jsx",
7
- "esModuleInterop": true,
8
- "skipLibCheck": true,
9
- "forceConsistentCasingInFileNames": true,
10
- "declaration": true,
11
- "outDir": "./out",
12
- "declarationDir": "./out",
13
- "isolatedModules": true,
14
- "allowSyntheticDefaultImports": true,
15
- "resolveJsonModule": true,
16
- "strict": true
17
- },
18
- "include": ["./index.tsx"]
19
- }