@duffel/react-native-components-assistant 0.4.4 → 0.4.5-canary.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.
@@ -1,11 +1,21 @@
1
1
  "use strict";
2
2
 
3
3
  import React from 'react';
4
- import { Modal, Platform, StyleSheet, View } from 'react-native';
4
+ import { Linking, Modal, Platform, StyleSheet, View } from 'react-native';
5
5
  import { WebView } from 'react-native-webview';
6
6
  import { hasJsonWebTokenFormat } from "./lib/hasJsonWebTokenFormat.js";
7
7
  import { getClientKeyPayload } from "./lib/getClientKeyPayload.js";
8
8
  import { jsx as _jsx } from "react/jsx-runtime";
9
+ const assistantIframeUrl = 'https://assets.duffel.com/assistant/iframe.html';
10
+ const isHttpUrl = url => /^https?:\/\//.test(url);
11
+ const isAssistantIframeUrl = url => {
12
+ try {
13
+ const parsedUrl = new URL(url);
14
+ return `${parsedUrl.origin}${parsedUrl.pathname}` === assistantIframeUrl;
15
+ } catch (error) {
16
+ return false;
17
+ }
18
+ };
9
19
  export const DuffelAssistant = ({
10
20
  isOpen,
11
21
  onClose,
@@ -36,6 +46,35 @@ export const DuffelAssistant = ({
36
46
  if (properties.showMinimiseButton && typeof properties.onMinimise !== 'function') {
37
47
  console.warn('The showMinimiseButton prop is set to true, but the onMinimise callback is not provided. Make sure to listen to the onMinimise callback to handle the minimisation of the Assistant.');
38
48
  }
49
+ const handleMessage = event => {
50
+ if (event.nativeEvent.data === 'duffel-assistant-close') {
51
+ onClose();
52
+ }
53
+ if (typeof properties.onMinimise === 'function' && event.nativeEvent.data === 'duffel-assistant-minimise') {
54
+ properties.onMinimise();
55
+ }
56
+ try {
57
+ const parsedData = JSON.parse(event.nativeEvent.data);
58
+ if (parsedData.type === 'duffel-assistant-new-message' && typeof parsedData.userId === 'string' && typeof parsedData.resourceId === 'string' && typeof onNewMessage === 'function') {
59
+ onNewMessage({
60
+ userId: parsedData.userId,
61
+ resourceId: parsedData.resourceId
62
+ });
63
+ }
64
+ } catch (error) {
65
+ // do nothing, invalid JSON
66
+ }
67
+ };
68
+ const handleShouldStartLoadWithRequest = request => {
69
+ if (!isHttpUrl(request.url) || isAssistantIframeUrl(request.url)) {
70
+ return true;
71
+ }
72
+ if (Platform.OS === 'ios' && request.navigationType !== 'click') {
73
+ return true;
74
+ }
75
+ Linking.openURL(request.url).catch(() => {});
76
+ return false;
77
+ };
39
78
  return /*#__PURE__*/_jsx(Modal, {
40
79
  visible: isOpen,
41
80
  onRequestClose: () => onClose(),
@@ -50,27 +89,10 @@ export const DuffelAssistant = ({
50
89
  // If that's not possible, you can also upload the assistant built assets to a different folder in assets.duffel and work with that.
51
90
  ,
52
91
  source: {
53
- uri: 'https://assets.duffel.com/assistant/iframe.html'
92
+ uri: assistantIframeUrl
54
93
  },
55
- onMessage: event => {
56
- if (event.nativeEvent.data === 'duffel-assistant-close') {
57
- onClose();
58
- }
59
- if (typeof properties.onMinimise === 'function' && event.nativeEvent.data === 'duffel-assistant-minimise') {
60
- properties.onMinimise();
61
- }
62
- try {
63
- const parsedData = JSON.parse(event.nativeEvent.data);
64
- if (parsedData.type === 'duffel-assistant-new-message' && typeof parsedData.userId === 'string' && typeof parsedData.resourceId === 'string' && typeof onNewMessage === 'function') {
65
- onNewMessage({
66
- userId: parsedData.userId,
67
- resourceId: parsedData.resourceId
68
- });
69
- }
70
- } catch (error) {
71
- // do nothing, invalid JSON
72
- }
73
- }
94
+ onMessage: handleMessage,
95
+ onShouldStartLoadWithRequest: handleShouldStartLoadWithRequest
74
96
  }) : /*#__PURE__*/_jsx(WebView
75
97
  // Required for Android
76
98
  , {
@@ -84,13 +106,10 @@ export const DuffelAssistant = ({
84
106
  );
85
107
  true;`,
86
108
  source: {
87
- uri: 'https://assets.duffel.com/assistant/iframe.html'
109
+ uri: assistantIframeUrl
88
110
  },
89
- onMessage: event => {
90
- if (event.nativeEvent.data === 'duffel-assistant-close') {
91
- onClose();
92
- }
93
- }
111
+ onMessage: handleMessage,
112
+ onShouldStartLoadWithRequest: handleShouldStartLoadWithRequest
94
113
  })
95
114
  })
96
115
  });
@@ -1 +1 @@
1
- {"version":3,"names":["React","Modal","Platform","StyleSheet","View","WebView","hasJsonWebTokenFormat","getClientKeyPayload","jsx","_jsx","DuffelAssistant","isOpen","onClose","onNewMessage","properties","clientKey","Error","clientKeyPayload","clientKeyIncludesResource","order_id","undefined","booking_id","cars_booking_id","issueType","console","warn","context","showMinimiseButton","onMinimise","visible","onRequestClose","animationType","children","style","styles","container","OS","injectedJavaScriptObject","source","uri","onMessage","event","nativeEvent","data","parsedData","JSON","parse","type","userId","resourceId","error","injectedJavaScript","stringify","create","height","width","paddingHorizontal","paddingTop","paddingBottom"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","Linking","Modal","Platform","StyleSheet","View","WebView","hasJsonWebTokenFormat","getClientKeyPayload","jsx","_jsx","assistantIframeUrl","isHttpUrl","url","test","isAssistantIframeUrl","parsedUrl","URL","origin","pathname","error","DuffelAssistant","isOpen","onClose","onNewMessage","properties","clientKey","Error","clientKeyPayload","clientKeyIncludesResource","order_id","undefined","booking_id","cars_booking_id","issueType","console","warn","context","showMinimiseButton","onMinimise","handleMessage","event","nativeEvent","data","parsedData","JSON","parse","type","userId","resourceId","handleShouldStartLoadWithRequest","request","OS","navigationType","openURL","catch","visible","onRequestClose","animationType","children","style","styles","container","injectedJavaScriptObject","source","uri","onMessage","onShouldStartLoadWithRequest","injectedJavaScript","stringify","create","height","width","paddingHorizontal","paddingTop","paddingBottom"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,KAAK,oBAAoB,IAAI,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAInG,MAAM,MAAM,oBAAoB,GAAG,4BAA4B,CAAC;AAEhE,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgI1D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,KAAK,oBAAoB,IAAI,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAInG,MAAM,MAAM,oBAAoB,GAAG,4BAA4B,CAAC;AA2BhE,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgJ1D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duffel/react-native-components-assistant",
3
- "version": "0.4.4",
3
+ "version": "0.4.5-canary.0",
4
4
  "description": "Duffel Assistant component in React Native",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -59,29 +59,29 @@
59
59
  "registry": "https://registry.npmjs.org/"
60
60
  },
61
61
  "devDependencies": {
62
- "@commitlint/config-conventional": "^20.4.4",
63
- "@eslint/compat": "^1.2.7",
64
- "@eslint/eslintrc": "^3.3.0",
65
- "@eslint/js": "^9.22.0",
66
- "@evilmartians/lefthook": "^1.5.0",
62
+ "@commitlint/config-conventional": "20.4.4",
63
+ "@eslint/compat": "1.2.7",
64
+ "@eslint/eslintrc": "3.3.0",
65
+ "@eslint/js": "9.22.0",
66
+ "@evilmartians/lefthook": "1.5.0",
67
67
  "@react-native/babel-preset": "0.78.2",
68
- "@react-native/eslint-config": "^0.78.0",
69
- "@release-it/conventional-changelog": "^10.0.6",
70
- "@types/jest": "^29.5.5",
71
- "@types/react": "^19.0.12",
72
- "commitlint": "^20.4.4",
73
- "del-cli": "^5.1.0",
74
- "eslint": "^9.22.0",
75
- "eslint-config-prettier": "^10.1.1",
76
- "eslint-plugin-prettier": "^5.2.3",
77
- "jest": "^29.7.0",
78
- "prettier": "^3.0.3",
68
+ "@react-native/eslint-config": "0.78.0",
69
+ "@release-it/conventional-changelog": "10.0.6",
70
+ "@types/jest": "29.5.5",
71
+ "@types/react": "19.0.12",
72
+ "commitlint": "20.4.4",
73
+ "del-cli": "5.1.0",
74
+ "eslint": "9.22.0",
75
+ "eslint-config-prettier": "10.1.1",
76
+ "eslint-plugin-prettier": "5.2.3",
77
+ "jest": "29.7.0",
78
+ "prettier": "3.0.3",
79
79
  "react": "19.1.0",
80
80
  "react-native": "0.81.5",
81
81
  "react-native-builder-bob": "0.39.0",
82
82
  "react-native-webview": "13.15.0",
83
- "release-it": "^19.2.4",
84
- "typescript": "^5.8.3"
83
+ "release-it": "19.2.4",
84
+ "typescript": "5.8.3"
85
85
  },
86
86
  "peerDependencies": {
87
87
  "react": "*",
@@ -152,5 +152,8 @@
152
152
  "languages": "js",
153
153
  "type": "library",
154
154
  "version": "0.51.1"
155
+ },
156
+ "dependencies": {
157
+ "expo": "54.0.30"
155
158
  }
156
159
  }
package/src/index.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Modal, Platform, StyleSheet, View } from 'react-native';
2
+ import { Linking, Modal, Platform, StyleSheet, View } from 'react-native';
3
3
  import { WebView } from 'react-native-webview';
4
4
  import { type DuffelAssistantProps as DuffelAssistantPropsImported } from './DuffelAssistantProps';
5
5
  import { hasJsonWebTokenFormat } from './lib/hasJsonWebTokenFormat';
@@ -7,6 +7,31 @@ import { getClientKeyPayload } from './lib/getClientKeyPayload';
7
7
 
8
8
  export type DuffelAssistantProps = DuffelAssistantPropsImported;
9
9
 
10
+ const assistantIframeUrl = 'https://assets.duffel.com/assistant/iframe.html';
11
+
12
+ type WebViewMessageEvent = {
13
+ nativeEvent: {
14
+ data: string;
15
+ };
16
+ };
17
+
18
+ type ShouldStartLoadRequest = {
19
+ navigationType?: string;
20
+ url: string;
21
+ };
22
+
23
+ const isHttpUrl = (url: string) => /^https?:\/\//.test(url);
24
+
25
+ const isAssistantIframeUrl = (url: string) => {
26
+ try {
27
+ const parsedUrl = new URL(url);
28
+
29
+ return `${parsedUrl.origin}${parsedUrl.pathname}` === assistantIframeUrl;
30
+ } catch (error) {
31
+ return false;
32
+ }
33
+ };
34
+
10
35
  export const DuffelAssistant: React.FC<DuffelAssistantProps> = ({
11
36
  isOpen,
12
37
  onClose,
@@ -66,6 +91,53 @@ export const DuffelAssistant: React.FC<DuffelAssistantProps> = ({
66
91
  );
67
92
  }
68
93
 
94
+ const handleMessage = (event: WebViewMessageEvent) => {
95
+ if (event.nativeEvent.data === 'duffel-assistant-close') {
96
+ onClose();
97
+ }
98
+
99
+ if (
100
+ typeof properties.onMinimise === 'function' &&
101
+ event.nativeEvent.data === 'duffel-assistant-minimise'
102
+ ) {
103
+ properties.onMinimise();
104
+ }
105
+
106
+ try {
107
+ const parsedData = JSON.parse(event.nativeEvent.data);
108
+
109
+ if (
110
+ parsedData.type === 'duffel-assistant-new-message' &&
111
+ typeof parsedData.userId === 'string' &&
112
+ typeof parsedData.resourceId === 'string' &&
113
+ typeof onNewMessage === 'function'
114
+ ) {
115
+ onNewMessage({
116
+ userId: parsedData.userId,
117
+ resourceId: parsedData.resourceId,
118
+ });
119
+ }
120
+ } catch (error) {
121
+ // do nothing, invalid JSON
122
+ }
123
+ };
124
+
125
+ const handleShouldStartLoadWithRequest = (
126
+ request: ShouldStartLoadRequest
127
+ ) => {
128
+ if (!isHttpUrl(request.url) || isAssistantIframeUrl(request.url)) {
129
+ return true;
130
+ }
131
+
132
+ if (Platform.OS === 'ios' && request.navigationType !== 'click') {
133
+ return true;
134
+ }
135
+
136
+ Linking.openURL(request.url).catch(() => {});
137
+
138
+ return false;
139
+ };
140
+
69
141
  return (
70
142
  <Modal
71
143
  visible={isOpen}
@@ -80,37 +152,9 @@ export const DuffelAssistant: React.FC<DuffelAssistantProps> = ({
80
152
  // If you try ngrok with the local esbuild server it will fail because ngrok requests in https and the dev server rejects http requests.
81
153
  // Easiest solution is to use the production URL with test data.
82
154
  // If that's not possible, you can also upload the assistant built assets to a different folder in assets.duffel and work with that.
83
- source={{ uri: 'https://assets.duffel.com/assistant/iframe.html' }}
84
- onMessage={(event) => {
85
- if (event.nativeEvent.data === 'duffel-assistant-close') {
86
- onClose();
87
- }
88
-
89
- if (
90
- typeof properties.onMinimise === 'function' &&
91
- event.nativeEvent.data === 'duffel-assistant-minimise'
92
- ) {
93
- properties.onMinimise();
94
- }
95
-
96
- try {
97
- const parsedData = JSON.parse(event.nativeEvent.data);
98
-
99
- if (
100
- parsedData.type === 'duffel-assistant-new-message' &&
101
- typeof parsedData.userId === 'string' &&
102
- typeof parsedData.resourceId === 'string' &&
103
- typeof onNewMessage === 'function'
104
- ) {
105
- onNewMessage({
106
- userId: parsedData.userId,
107
- resourceId: parsedData.resourceId,
108
- });
109
- }
110
- } catch (error) {
111
- // do nothing, invalid JSON
112
- }
113
- }}
155
+ source={{ uri: assistantIframeUrl }}
156
+ onMessage={handleMessage}
157
+ onShouldStartLoadWithRequest={handleShouldStartLoadWithRequest}
114
158
  />
115
159
  ) : (
116
160
  <WebView
@@ -124,12 +168,9 @@ export const DuffelAssistant: React.FC<DuffelAssistantProps> = ({
124
168
  "*",
125
169
  );
126
170
  true;`}
127
- source={{ uri: 'https://assets.duffel.com/assistant/iframe.html' }}
128
- onMessage={(event) => {
129
- if (event.nativeEvent.data === 'duffel-assistant-close') {
130
- onClose();
131
- }
132
- }}
171
+ source={{ uri: assistantIframeUrl }}
172
+ onMessage={handleMessage}
173
+ onShouldStartLoadWithRequest={handleShouldStartLoadWithRequest}
133
174
  />
134
175
  )}
135
176
  </View>