@parafin/core 2.3.0 → 3.0.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/index.ts +148 -24
- package/out/index.d.ts +22 -1
- package/out/index.js +127 -24
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -34,23 +34,31 @@ export const openParafinDashboard = (
|
|
|
34
34
|
)
|
|
35
35
|
const route = 'route' in props ? props.route : '/'
|
|
36
36
|
|
|
37
|
-
const addPropIfExists = (key: string) => {
|
|
38
|
-
if (key in props && props[key] !== undefined && props[key] !== null) {
|
|
39
|
-
return { [key]: props[key] }
|
|
40
|
-
} else {
|
|
41
|
-
return {}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
37
|
const query = {
|
|
46
38
|
product: props.product,
|
|
47
39
|
referrer: 'partner',
|
|
48
|
-
...
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
...
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
...('token' in props &&
|
|
41
|
+
props.token !== undefined &&
|
|
42
|
+
props.token !== null && { token: props.token }),
|
|
43
|
+
...('partner' in props &&
|
|
44
|
+
props.partner !== undefined &&
|
|
45
|
+
props.partner !== null && { partner: props.partner }),
|
|
46
|
+
...('externalBusinessId' in props &&
|
|
47
|
+
props.externalBusinessId !== undefined &&
|
|
48
|
+
props.externalBusinessId !== null && {
|
|
49
|
+
externalBusinessId: props.externalBusinessId,
|
|
50
|
+
}),
|
|
51
|
+
...('orderId' in props &&
|
|
52
|
+
props.orderId !== undefined &&
|
|
53
|
+
props.orderId !== null && { orderId: props.orderId }),
|
|
54
|
+
...('lineOfCreditApplicationId' in props &&
|
|
55
|
+
props.lineOfCreditApplicationId !== undefined &&
|
|
56
|
+
props.lineOfCreditApplicationId !== null && {
|
|
57
|
+
lineOfCreditApplicationId: props.lineOfCreditApplicationId,
|
|
58
|
+
}),
|
|
59
|
+
...('inWebView' in props &&
|
|
60
|
+
props.inWebView !== undefined &&
|
|
61
|
+
props.inWebView !== null && { inWebView: props.inWebView.toString() }),
|
|
54
62
|
...Object.fromEntries(searchParams),
|
|
55
63
|
}
|
|
56
64
|
|
|
@@ -58,12 +66,12 @@ export const openParafinDashboard = (
|
|
|
58
66
|
|
|
59
67
|
if ('openInNewTab' in props && props.openInNewTab) {
|
|
60
68
|
window.open(url, '_blank')
|
|
61
|
-
return
|
|
69
|
+
return () => {} // noop
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
if ('mode' in props && props.mode === 'redirect') {
|
|
65
73
|
window.location.href = url
|
|
66
|
-
return
|
|
74
|
+
return () => {} // noop
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
const existingParafinDashboard =
|
|
@@ -107,17 +115,26 @@ export const openParafinDashboard = (
|
|
|
107
115
|
}
|
|
108
116
|
}
|
|
109
117
|
|
|
118
|
+
let cleanedUp = false
|
|
119
|
+
const cleanup = ({ withOnExit }: { withOnExit: boolean }) => {
|
|
120
|
+
if (cleanedUp) return // noop
|
|
121
|
+
cleanedUp = true
|
|
122
|
+
|
|
123
|
+
window.removeEventListener('message', messageListener)
|
|
124
|
+
frame.style.opacity = '0'
|
|
125
|
+
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
if (withOnExit) onExit()
|
|
128
|
+
dashboardTargetElement.removeChild(frame)
|
|
129
|
+
document.body.style.removeProperty('overflow')
|
|
130
|
+
}, 200)
|
|
131
|
+
}
|
|
132
|
+
|
|
110
133
|
const messageListener = async (event: MessageEvent) => {
|
|
111
134
|
if (event.origin === origin) {
|
|
112
135
|
switch (event.data?.message) {
|
|
113
136
|
case 'close-dashboard':
|
|
114
|
-
|
|
115
|
-
frame.style.opacity = '0'
|
|
116
|
-
setTimeout(() => {
|
|
117
|
-
onExit()
|
|
118
|
-
dashboardTargetElement.removeChild(frame)
|
|
119
|
-
document.body.style.removeProperty('overflow')
|
|
120
|
-
}, 200)
|
|
137
|
+
cleanup({ withOnExit: true })
|
|
121
138
|
break
|
|
122
139
|
case 'link-opened':
|
|
123
140
|
if (props.onLinkOpened && event.data?.url && event.data?.metadata) {
|
|
@@ -133,8 +150,115 @@ export const openParafinDashboard = (
|
|
|
133
150
|
setTimeout(() => {
|
|
134
151
|
frame.style.opacity = '1'
|
|
135
152
|
document.body.style.overflow = 'hidden'
|
|
136
|
-
},
|
|
153
|
+
}, 0)
|
|
154
|
+
|
|
155
|
+
return () => cleanup({ withOnExit: false })
|
|
137
156
|
} catch (error) {
|
|
138
157
|
console.error('Error loading Parafin dashboard', error)
|
|
158
|
+
return () => {} // noop
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const defaultWidgetStyles = {
|
|
163
|
+
width: '100%',
|
|
164
|
+
height: '258px',
|
|
165
|
+
backgroundColor: '#fff',
|
|
166
|
+
border: '1px solid #E8E8E8',
|
|
167
|
+
borderRadius: '16px',
|
|
168
|
+
transition: 'border 0.2s, border-radius 0.2s',
|
|
169
|
+
boxSizing: 'border-box' as const,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export type WidgetEvent = 'opted_in' | 'opted_out'
|
|
173
|
+
|
|
174
|
+
export type WidgetProps = {
|
|
175
|
+
token: string
|
|
176
|
+
product: 'capital' | 'spend_card' | 'cash_account'
|
|
177
|
+
externalBusinessId?: string
|
|
178
|
+
onEvent?: (eventType: WidgetEvent) => Promise<void> | void
|
|
179
|
+
onExit?: () => void
|
|
180
|
+
openInNewTab?: boolean
|
|
181
|
+
onLinkOpened?: (url: string, metadata: LinkOpenedMetadata) => void
|
|
182
|
+
inWebView?: boolean
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export const initializeParafinWidget = (
|
|
186
|
+
iframe: HTMLIFrameElement,
|
|
187
|
+
props: WidgetProps
|
|
188
|
+
) => {
|
|
189
|
+
// @ts-ignore
|
|
190
|
+
const url = new URL(props.widgetUrlOverride ?? 'https://widget.parafin.com')
|
|
191
|
+
const query = {
|
|
192
|
+
token: props.token,
|
|
193
|
+
product: props.product,
|
|
194
|
+
host: window.location.origin,
|
|
195
|
+
externalBusinessId: props.externalBusinessId ?? '',
|
|
196
|
+
...Object.fromEntries(url.searchParams),
|
|
197
|
+
}
|
|
198
|
+
const iframeSrc = `${url.origin}?${new URLSearchParams(query).toString()}`
|
|
199
|
+
|
|
200
|
+
iframe.id = `parafin-${props.product}-widget`
|
|
201
|
+
iframe.src = iframeSrc
|
|
202
|
+
|
|
203
|
+
const sendMessage = (message: any) => {
|
|
204
|
+
iframe.contentWindow?.postMessage(message, url.origin)
|
|
139
205
|
}
|
|
206
|
+
|
|
207
|
+
const messageListener = async ({ data, origin }: MessageEvent) => {
|
|
208
|
+
if (origin === url.origin && data?.product === props.product) {
|
|
209
|
+
switch (data?.message) {
|
|
210
|
+
case 'set-border':
|
|
211
|
+
if (data?.borderColor) {
|
|
212
|
+
iframe.style.border = `1px solid ${data.borderColor}`
|
|
213
|
+
}
|
|
214
|
+
if (data?.borderRadius) {
|
|
215
|
+
iframe.style.borderRadius = data.borderRadius
|
|
216
|
+
}
|
|
217
|
+
break
|
|
218
|
+
case 'open-dashboard':
|
|
219
|
+
openParafinDashboard({
|
|
220
|
+
...props,
|
|
221
|
+
route: data?.route,
|
|
222
|
+
onExit: () => {
|
|
223
|
+
iframe.src = iframeSrc
|
|
224
|
+
props.onExit?.()
|
|
225
|
+
},
|
|
226
|
+
})
|
|
227
|
+
break
|
|
228
|
+
case 'person-opt-in':
|
|
229
|
+
if (props.onEvent) {
|
|
230
|
+
try {
|
|
231
|
+
await props.onEvent('opted_in')
|
|
232
|
+
sendMessage({ message: 'person-opt-in', state: 'success' })
|
|
233
|
+
} catch {
|
|
234
|
+
sendMessage({ message: 'person-opt-in', state: 'error' })
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
sendMessage({ message: 'person-opt-in', state: 'noop' })
|
|
238
|
+
}
|
|
239
|
+
break
|
|
240
|
+
case 'person-opt-out':
|
|
241
|
+
if (props.onEvent) {
|
|
242
|
+
try {
|
|
243
|
+
await props.onEvent('opted_out')
|
|
244
|
+
sendMessage({ message: 'person-opt-out', state: 'success' })
|
|
245
|
+
} catch {
|
|
246
|
+
sendMessage({ message: 'person-opt-out', state: 'error' })
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
sendMessage({ message: 'person-opt-out', state: 'noop' })
|
|
250
|
+
}
|
|
251
|
+
break
|
|
252
|
+
case 'set-height':
|
|
253
|
+
if (data?.height) {
|
|
254
|
+
iframe.style.height = data.height
|
|
255
|
+
}
|
|
256
|
+
break
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
window.addEventListener('message', messageListener)
|
|
262
|
+
|
|
263
|
+
return () => window.removeEventListener('message', messageListener)
|
|
140
264
|
}
|
package/out/index.d.ts
CHANGED
|
@@ -24,5 +24,26 @@ type BNPLProps = {
|
|
|
24
24
|
lineOfCreditApplicationId?: string;
|
|
25
25
|
onExit?: (id?: string) => Promise<void> | void;
|
|
26
26
|
};
|
|
27
|
-
export declare const openParafinDashboard: (props: BaseProps & (CapitalOrSpendProps | BNPLProps)) => void;
|
|
27
|
+
export declare const openParafinDashboard: (props: BaseProps & (CapitalOrSpendProps | BNPLProps)) => () => void;
|
|
28
|
+
export declare const defaultWidgetStyles: {
|
|
29
|
+
width: string;
|
|
30
|
+
height: string;
|
|
31
|
+
backgroundColor: string;
|
|
32
|
+
border: string;
|
|
33
|
+
borderRadius: string;
|
|
34
|
+
transition: string;
|
|
35
|
+
boxSizing: "border-box";
|
|
36
|
+
};
|
|
37
|
+
export type WidgetEvent = 'opted_in' | 'opted_out';
|
|
38
|
+
export type WidgetProps = {
|
|
39
|
+
token: string;
|
|
40
|
+
product: 'capital' | 'spend_card' | 'cash_account';
|
|
41
|
+
externalBusinessId?: string;
|
|
42
|
+
onEvent?: (eventType: WidgetEvent) => Promise<void> | void;
|
|
43
|
+
onExit?: () => void;
|
|
44
|
+
openInNewTab?: boolean;
|
|
45
|
+
onLinkOpened?: (url: string, metadata: LinkOpenedMetadata) => void;
|
|
46
|
+
inWebView?: boolean;
|
|
47
|
+
};
|
|
48
|
+
export declare const initializeParafinWidget: (iframe: HTMLIFrameElement, props: WidgetProps) => () => void;
|
|
28
49
|
export {};
|
package/out/index.js
CHANGED
|
@@ -4,33 +4,41 @@ export const openParafinDashboard = (props) => {
|
|
|
4
4
|
// @ts-ignore
|
|
5
5
|
props.dashboardUrlOverride ?? 'https://app.parafin.com');
|
|
6
6
|
const route = 'route' in props ? props.route : '/';
|
|
7
|
-
const addPropIfExists = (key) => {
|
|
8
|
-
if (key in props && props[key] !== undefined && props[key] !== null) {
|
|
9
|
-
return { [key]: props[key] };
|
|
10
|
-
}
|
|
11
|
-
else {
|
|
12
|
-
return {};
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
7
|
const query = {
|
|
16
8
|
product: props.product,
|
|
17
9
|
referrer: 'partner',
|
|
18
|
-
...
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
...
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
...('token' in props &&
|
|
11
|
+
props.token !== undefined &&
|
|
12
|
+
props.token !== null && { token: props.token }),
|
|
13
|
+
...('partner' in props &&
|
|
14
|
+
props.partner !== undefined &&
|
|
15
|
+
props.partner !== null && { partner: props.partner }),
|
|
16
|
+
...('externalBusinessId' in props &&
|
|
17
|
+
props.externalBusinessId !== undefined &&
|
|
18
|
+
props.externalBusinessId !== null && {
|
|
19
|
+
externalBusinessId: props.externalBusinessId,
|
|
20
|
+
}),
|
|
21
|
+
...('orderId' in props &&
|
|
22
|
+
props.orderId !== undefined &&
|
|
23
|
+
props.orderId !== null && { orderId: props.orderId }),
|
|
24
|
+
...('lineOfCreditApplicationId' in props &&
|
|
25
|
+
props.lineOfCreditApplicationId !== undefined &&
|
|
26
|
+
props.lineOfCreditApplicationId !== null && {
|
|
27
|
+
lineOfCreditApplicationId: props.lineOfCreditApplicationId,
|
|
28
|
+
}),
|
|
29
|
+
...('inWebView' in props &&
|
|
30
|
+
props.inWebView !== undefined &&
|
|
31
|
+
props.inWebView !== null && { inWebView: props.inWebView.toString() }),
|
|
24
32
|
...Object.fromEntries(searchParams),
|
|
25
33
|
};
|
|
26
34
|
const url = `${origin}${route}?${new URLSearchParams(query).toString()}`;
|
|
27
35
|
if ('openInNewTab' in props && props.openInNewTab) {
|
|
28
36
|
window.open(url, '_blank');
|
|
29
|
-
return;
|
|
37
|
+
return () => { }; // noop
|
|
30
38
|
}
|
|
31
39
|
if ('mode' in props && props.mode === 'redirect') {
|
|
32
40
|
window.location.href = url;
|
|
33
|
-
return;
|
|
41
|
+
return () => { }; // noop
|
|
34
42
|
}
|
|
35
43
|
const existingParafinDashboard = document.getElementById('parafin-dashboard');
|
|
36
44
|
if (existingParafinDashboard) {
|
|
@@ -69,17 +77,25 @@ export const openParafinDashboard = (props) => {
|
|
|
69
77
|
props.onExit?.();
|
|
70
78
|
}
|
|
71
79
|
};
|
|
80
|
+
let cleanedUp = false;
|
|
81
|
+
const cleanup = ({ withOnExit }) => {
|
|
82
|
+
if (cleanedUp)
|
|
83
|
+
return; // noop
|
|
84
|
+
cleanedUp = true;
|
|
85
|
+
window.removeEventListener('message', messageListener);
|
|
86
|
+
frame.style.opacity = '0';
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
if (withOnExit)
|
|
89
|
+
onExit();
|
|
90
|
+
dashboardTargetElement.removeChild(frame);
|
|
91
|
+
document.body.style.removeProperty('overflow');
|
|
92
|
+
}, 200);
|
|
93
|
+
};
|
|
72
94
|
const messageListener = async (event) => {
|
|
73
95
|
if (event.origin === origin) {
|
|
74
96
|
switch (event.data?.message) {
|
|
75
97
|
case 'close-dashboard':
|
|
76
|
-
|
|
77
|
-
frame.style.opacity = '0';
|
|
78
|
-
setTimeout(() => {
|
|
79
|
-
onExit();
|
|
80
|
-
dashboardTargetElement.removeChild(frame);
|
|
81
|
-
document.body.style.removeProperty('overflow');
|
|
82
|
-
}, 200);
|
|
98
|
+
cleanup({ withOnExit: true });
|
|
83
99
|
break;
|
|
84
100
|
case 'link-opened':
|
|
85
101
|
if (props.onLinkOpened && event.data?.url && event.data?.metadata) {
|
|
@@ -94,9 +110,96 @@ export const openParafinDashboard = (props) => {
|
|
|
94
110
|
setTimeout(() => {
|
|
95
111
|
frame.style.opacity = '1';
|
|
96
112
|
document.body.style.overflow = 'hidden';
|
|
97
|
-
},
|
|
113
|
+
}, 0);
|
|
114
|
+
return () => cleanup({ withOnExit: false });
|
|
98
115
|
}
|
|
99
116
|
catch (error) {
|
|
100
117
|
console.error('Error loading Parafin dashboard', error);
|
|
118
|
+
return () => { }; // noop
|
|
101
119
|
}
|
|
102
120
|
};
|
|
121
|
+
export const defaultWidgetStyles = {
|
|
122
|
+
width: '100%',
|
|
123
|
+
height: '258px',
|
|
124
|
+
backgroundColor: '#fff',
|
|
125
|
+
border: '1px solid #E8E8E8',
|
|
126
|
+
borderRadius: '16px',
|
|
127
|
+
transition: 'border 0.2s, border-radius 0.2s',
|
|
128
|
+
boxSizing: 'border-box',
|
|
129
|
+
};
|
|
130
|
+
export const initializeParafinWidget = (iframe, props) => {
|
|
131
|
+
// @ts-ignore
|
|
132
|
+
const url = new URL(props.widgetUrlOverride ?? 'https://widget.parafin.com');
|
|
133
|
+
const query = {
|
|
134
|
+
token: props.token,
|
|
135
|
+
product: props.product,
|
|
136
|
+
host: window.location.origin,
|
|
137
|
+
externalBusinessId: props.externalBusinessId ?? '',
|
|
138
|
+
...Object.fromEntries(url.searchParams),
|
|
139
|
+
};
|
|
140
|
+
const iframeSrc = `${url.origin}?${new URLSearchParams(query).toString()}`;
|
|
141
|
+
iframe.id = `parafin-${props.product}-widget`;
|
|
142
|
+
iframe.src = iframeSrc;
|
|
143
|
+
const sendMessage = (message) => {
|
|
144
|
+
iframe.contentWindow?.postMessage(message, url.origin);
|
|
145
|
+
};
|
|
146
|
+
const messageListener = async ({ data, origin }) => {
|
|
147
|
+
if (origin === url.origin && data?.product === props.product) {
|
|
148
|
+
switch (data?.message) {
|
|
149
|
+
case 'set-border':
|
|
150
|
+
if (data?.borderColor) {
|
|
151
|
+
iframe.style.border = `1px solid ${data.borderColor}`;
|
|
152
|
+
}
|
|
153
|
+
if (data?.borderRadius) {
|
|
154
|
+
iframe.style.borderRadius = data.borderRadius;
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
case 'open-dashboard':
|
|
158
|
+
openParafinDashboard({
|
|
159
|
+
...props,
|
|
160
|
+
route: data?.route,
|
|
161
|
+
onExit: () => {
|
|
162
|
+
iframe.src = iframeSrc;
|
|
163
|
+
props.onExit?.();
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
break;
|
|
167
|
+
case 'person-opt-in':
|
|
168
|
+
if (props.onEvent) {
|
|
169
|
+
try {
|
|
170
|
+
await props.onEvent('opted_in');
|
|
171
|
+
sendMessage({ message: 'person-opt-in', state: 'success' });
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
sendMessage({ message: 'person-opt-in', state: 'error' });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
sendMessage({ message: 'person-opt-in', state: 'noop' });
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
case 'person-opt-out':
|
|
182
|
+
if (props.onEvent) {
|
|
183
|
+
try {
|
|
184
|
+
await props.onEvent('opted_out');
|
|
185
|
+
sendMessage({ message: 'person-opt-out', state: 'success' });
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
sendMessage({ message: 'person-opt-out', state: 'error' });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
sendMessage({ message: 'person-opt-out', state: 'noop' });
|
|
193
|
+
}
|
|
194
|
+
break;
|
|
195
|
+
case 'set-height':
|
|
196
|
+
if (data?.height) {
|
|
197
|
+
iframe.style.height = data.height;
|
|
198
|
+
}
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
window.addEventListener('message', messageListener);
|
|
204
|
+
return () => window.removeEventListener('message', messageListener);
|
|
205
|
+
};
|