rn-erxes-sdk 0.1.24 → 0.1.26

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 (34) hide show
  1. package/README.md +322 -48
  2. package/lib/commonjs/App.js +5 -6
  3. package/lib/commonjs/App.js.map +1 -1
  4. package/lib/commonjs/assets/images/index.js +1 -1
  5. package/lib/commonjs/assets/images/index.js.map +1 -1
  6. package/lib/commonjs/assets/images/x.png +0 -0
  7. package/lib/commonjs/components/InputTools.js +3 -2
  8. package/lib/commonjs/components/InputTools.js.map +1 -1
  9. package/lib/commonjs/screen/home/Home.js +62 -5
  10. package/lib/commonjs/screen/home/Home.js.map +1 -1
  11. package/lib/commonjs/utils/objectId.js +61 -0
  12. package/lib/commonjs/utils/objectId.js.map +1 -0
  13. package/lib/module/App.js +5 -6
  14. package/lib/module/App.js.map +1 -1
  15. package/lib/module/assets/images/index.js +1 -1
  16. package/lib/module/assets/images/index.js.map +1 -1
  17. package/lib/module/assets/images/x.png +0 -0
  18. package/lib/module/components/InputTools.js +3 -2
  19. package/lib/module/components/InputTools.js.map +1 -1
  20. package/lib/module/screen/home/Home.js +63 -6
  21. package/lib/module/screen/home/Home.js.map +1 -1
  22. package/lib/module/utils/objectId.js +53 -0
  23. package/lib/module/utils/objectId.js.map +1 -0
  24. package/lib/typescript/components/InputTools.d.ts.map +1 -1
  25. package/lib/typescript/screen/home/Home.d.ts.map +1 -1
  26. package/lib/typescript/utils/objectId.d.ts +3 -0
  27. package/lib/typescript/utils/objectId.d.ts.map +1 -0
  28. package/package.json +5 -3
  29. package/src/App.tsx +6 -6
  30. package/src/assets/images/index.ts +1 -1
  31. package/src/assets/images/x.png +0 -0
  32. package/src/components/InputTools.tsx +2 -1
  33. package/src/screen/home/Home.tsx +73 -2
  34. package/src/utils/objectId.ts +59 -0
@@ -0,0 +1,53 @@
1
+ /* eslint-disable no-bitwise */
2
+ // Lightweight, React Native-compatible replacement for `bson`'s `ObjectId`.
3
+ //
4
+ // The SDK only ever used `new ObjectId().toString()` to mint a `visitorId`,
5
+ // which the erxes backend accepts as a plain `String`. Importing the whole
6
+ // `bson` package for this pulls in `bson/lib/bson.mjs`, whose top-level
7
+ // `await` crashes Metro/Hermes ("await is not defined") once Expo resolves
8
+ // packages through the ESM `exports` map.
9
+ //
10
+ // This helper returns the exact same shape an ObjectId stringifies to:
11
+ // 24 lowercase hexadecimal characters (a 12-byte value made of a 4-byte
12
+ // big-endian timestamp followed by 8 random bytes).
13
+
14
+ const toHex = bytes => {
15
+ let out = '';
16
+ for (let i = 0; i < bytes.length; i++) {
17
+ const byte = bytes[i];
18
+ out += byte.toString(16).padStart(2, '0');
19
+ }
20
+ return out;
21
+ };
22
+ const getRandomBytes = length => {
23
+ const bytes = new Uint8Array(length);
24
+
25
+ // `react-native-get-random-values` (imported by the SDK entry point)
26
+ // polyfills `crypto.getRandomValues` on device. Fall back to `Math.random`
27
+ // so the helper still works in environments without the polyfill (e.g. Jest).
28
+ const cryptoObj = typeof globalThis !== 'undefined' ? globalThis.crypto : undefined;
29
+ if (cryptoObj && typeof cryptoObj.getRandomValues === 'function') {
30
+ cryptoObj.getRandomValues(bytes);
31
+ return bytes;
32
+ }
33
+ for (let i = 0; i < length; i++) {
34
+ bytes[i] = Math.floor(Math.random() * 256);
35
+ }
36
+ return bytes;
37
+ };
38
+ export const createObjectIdLikeString = () => {
39
+ const bytes = new Uint8Array(12);
40
+
41
+ // 4-byte big-endian timestamp (seconds since epoch), like a real ObjectId.
42
+ const timestamp = Math.floor(Date.now() / 1000);
43
+ bytes[0] = timestamp >> 24 & 0xff;
44
+ bytes[1] = timestamp >> 16 & 0xff;
45
+ bytes[2] = timestamp >> 8 & 0xff;
46
+ bytes[3] = timestamp & 0xff;
47
+
48
+ // Remaining 8 bytes from a CSPRNG when available.
49
+ bytes.set(getRandomBytes(8), 4);
50
+ return toHex(bytes);
51
+ };
52
+ export default createObjectIdLikeString;
53
+ //# sourceMappingURL=objectId.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["toHex","bytes","out","i","length","byte","toString","padStart","getRandomBytes","Uint8Array","cryptoObj","globalThis","crypto","undefined","getRandomValues","Math","floor","random","createObjectIdLikeString","timestamp","Date","now","set"],"sourceRoot":"../../../src","sources":["utils/objectId.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,MAAMA,KAAK,GAAIC,KAAiB,IAAa;EAC3C,IAAIC,GAAG,GAAG,EAAE;EACZ,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGF,KAAK,CAACG,MAAM,EAAED,CAAC,EAAE,EAAE;IACrC,MAAME,IAAI,GAAGJ,KAAK,CAACE,CAAC,CAAW;IAC/BD,GAAG,IAAIG,IAAI,CAACC,QAAQ,CAAC,EAAE,CAAC,CAACC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;EAC3C;EACA,OAAOL,GAAG;AACZ,CAAC;AAED,MAAMM,cAAc,GAAIJ,MAAc,IAAiB;EACrD,MAAMH,KAAK,GAAG,IAAIQ,UAAU,CAACL,MAAM,CAAC;;EAEpC;EACA;EACA;EACA,MAAMM,SAAS,GACb,OAAOC,UAAU,KAAK,WAAW,GAAIA,UAAU,CAASC,MAAM,GAAGC,SAAS;EAE5E,IAAIH,SAAS,IAAI,OAAOA,SAAS,CAACI,eAAe,KAAK,UAAU,EAAE;IAChEJ,SAAS,CAACI,eAAe,CAACb,KAAK,CAAC;IAChC,OAAOA,KAAK;EACd;EAEA,KAAK,IAAIE,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGC,MAAM,EAAED,CAAC,EAAE,EAAE;IAC/BF,KAAK,CAACE,CAAC,CAAC,GAAGY,IAAI,CAACC,KAAK,CAACD,IAAI,CAACE,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC;EAC5C;EACA,OAAOhB,KAAK;AACd,CAAC;AAED,OAAO,MAAMiB,wBAAwB,GAAGA,CAAA,KAAc;EACpD,MAAMjB,KAAK,GAAG,IAAIQ,UAAU,CAAC,EAAE,CAAC;;EAEhC;EACA,MAAMU,SAAS,GAAGJ,IAAI,CAACC,KAAK,CAACI,IAAI,CAACC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;EAC/CpB,KAAK,CAAC,CAAC,CAAC,GAAIkB,SAAS,IAAI,EAAE,GAAI,IAAI;EACnClB,KAAK,CAAC,CAAC,CAAC,GAAIkB,SAAS,IAAI,EAAE,GAAI,IAAI;EACnClB,KAAK,CAAC,CAAC,CAAC,GAAIkB,SAAS,IAAI,CAAC,GAAI,IAAI;EAClClB,KAAK,CAAC,CAAC,CAAC,GAAGkB,SAAS,GAAG,IAAI;;EAE3B;EACAlB,KAAK,CAACqB,GAAG,CAACd,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;EAE/B,OAAOR,KAAK,CAACC,KAAK,CAAC;AACrB,CAAC;AAED,eAAeiB,wBAAwB"}
@@ -1 +1 @@
1
- {"version":3,"file":"InputTools.d.ts","sourceRoot":"","sources":["../../../src/components/InputTools.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAoCpE,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAuO7B,CAAC;AA0IF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"InputTools.d.ts","sourceRoot":"","sources":["../../../src/components/InputTools.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAoCpE,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,CAwO7B,CAAC;AA0IF,eAAe,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Home.d.ts","sourceRoot":"","sources":["../../../../src/screen/home/Home.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAe1C,QAAA,MAAM,IAAI,yBA8IT,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"Home.d.ts","sourceRoot":"","sources":["../../../../src/screen/home/Home.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAkB1C,QAAA,MAAM,IAAI,yBA8MT,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const createObjectIdLikeString: () => string;
2
+ export default createObjectIdLikeString;
3
+ //# sourceMappingURL=objectId.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"objectId.d.ts","sourceRoot":"","sources":["../../../src/utils/objectId.ts"],"names":[],"mappings":"AA0CA,eAAO,MAAM,wBAAwB,QAAO,MAc3C,CAAC;AAEF,eAAe,wBAAwB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-erxes-sdk",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "react-native erxes sdk",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -40,7 +40,10 @@
40
40
  "ios",
41
41
  "android"
42
42
  ],
43
- "repository": "https://github.com/erxes/rn-erxes-sdk",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/erxes/rn-erxes-sdk.git"
46
+ },
44
47
  "author": "Munkh-orgil <monkhorgilbayarbaatar@gmail.com> (https://github.com/Munkhorgilb)",
45
48
  "license": "MIT",
46
49
  "bugs": {
@@ -169,7 +172,6 @@
169
172
  },
170
173
  "dependencies": {
171
174
  "@apollo/client": "^3.14.1",
172
- "bson": "^5.3.0",
173
175
  "dayjs": "^1.11.8",
174
176
  "graphql": "^16.6.0",
175
177
  "graphql-ws": "^5.13.1",
package/src/App.tsx CHANGED
@@ -2,7 +2,7 @@ import 'react-native-get-random-values';
2
2
  import React, { useEffect } from 'react';
3
3
  import Widget from './Widget';
4
4
  import AsyncStorage from '@react-native-async-storage/async-storage';
5
- import { ObjectId } from 'bson';
5
+ import { createObjectIdLikeString } from './utils/objectId';
6
6
  import ApolloContainer from './graphql/ApolloContainer';
7
7
 
8
8
  export type PropTypes = {
@@ -44,7 +44,7 @@ const ErxesSDK: React.FC<PropTypes> = ({
44
44
  const [show, setShow] = React.useState<boolean>(showWidget);
45
45
 
46
46
  useEffect(() => {
47
- let visitorId: any;
47
+ let visitorId: string | undefined;
48
48
  let tempCustomerId = '';
49
49
  setLoading(true);
50
50
  AsyncStorage.getItem('cachedCustomerId')
@@ -53,12 +53,12 @@ const ErxesSDK: React.FC<PropTypes> = ({
53
53
  tempCustomerId = JSON.parse(value);
54
54
  }
55
55
  if (!tempCustomerId) {
56
- // declare the data fetching function
57
- visitorId = new ObjectId();
56
+ // mint a guest visitor id (24-char hex, same shape as a Mongo ObjectId)
57
+ visitorId = createObjectIdLikeString();
58
58
  }
59
59
  setConnection({
60
60
  cachedCustomerId: tempCustomerId ? tempCustomerId : null,
61
- visitorId: visitorId?.toString(),
61
+ visitorId: visitorId,
62
62
  });
63
63
  AsyncStorage.getItem('conversationId')
64
64
  .then((v) => {
@@ -75,7 +75,7 @@ const ErxesSDK: React.FC<PropTypes> = ({
75
75
  .catch((e) => {
76
76
  setConnection({
77
77
  cachedCustomerId: null,
78
- visitorId: new ObjectId(),
78
+ visitorId: createObjectIdLikeString(),
79
79
  });
80
80
  setLoading(false);
81
81
  console.log('Failed on cachedCustomerId', e.message);
@@ -1,7 +1,7 @@
1
1
  const images = {
2
2
  facebook: require('./Facebook.png'),
3
3
  youtube: require('./Youtube.png'),
4
- twitter: require('./Twitter.png'),
4
+ twitter: require('./x.png'),
5
5
  avatar: require('./avatar.png'),
6
6
  logo: require('./logo.png'),
7
7
  };
Binary file
@@ -42,6 +42,7 @@ const InputTools: React.FC<any> = (props: any) => {
42
42
  subDomain,
43
43
  persistentMenus,
44
44
  sending = false,
45
+ placeholder = 'Reply...',
45
46
  } = props;
46
47
 
47
48
  const [input, onInput] = useState<string>('');
@@ -205,7 +206,7 @@ const InputTools: React.FC<any> = (props: any) => {
205
206
  ) : null}
206
207
 
207
208
  <TextInput
208
- placeholder={'Reply...'}
209
+ placeholder={placeholder}
209
210
  selectionColor={bgColor}
210
211
  underlineColorAndroid={'transparent'}
211
212
  style={styles.textInput}
@@ -8,9 +8,11 @@ import {
8
8
  Platform,
9
9
  StatusBar,
10
10
  ScrollView,
11
+ KeyboardAvoidingView,
11
12
  } from 'react-native';
12
13
  import React, { useContext } from 'react';
13
14
  import AsyncStorage from '@react-native-async-storage/async-storage';
15
+ import { useMutation } from '@apollo/client';
14
16
  import AppContext from '../../context/Context';
15
17
  import Supporters from '../greetings/Supporters';
16
18
  import Social from '../greetings/Social';
@@ -20,6 +22,8 @@ import {
20
22
  AVAILABILITY_MESSAGE,
21
23
  formatOnlineHours,
22
24
  } from '../../utils/onlineHours';
25
+ import InputTools from '../../components/InputTools';
26
+ import { widgetsInsertMessage } from '../../graphql/mutation';
23
27
 
24
28
  const LOGO_CHIP = 36;
25
29
 
@@ -35,12 +39,20 @@ const Home = () => {
35
39
  textColor,
36
40
  logoUrl,
37
41
  integrationId,
42
+ customerId,
43
+ visitorId,
38
44
  showWidget,
39
45
  setShow,
40
46
  setConversationId,
41
47
  backIcon,
48
+ sendIcon,
49
+ subDomain,
42
50
  } = value;
43
51
 
52
+ const [sendMutation] = useMutation(widgetsInsertMessage);
53
+ const [sending, setSending] = React.useState(false);
54
+ const sendingRef = React.useRef(false);
55
+
44
56
  const greetingMessages = greetings?.messages?.greetings;
45
57
  const title = greetingMessages?.title || 'How can we help?';
46
58
  const message =
@@ -58,6 +70,48 @@ const Home = () => {
58
70
  setConversationId('');
59
71
  };
60
72
 
73
+ const onSend = (text: string, attachments?: any[]) => {
74
+ if (sendingRef.current) {
75
+ return;
76
+ }
77
+
78
+ sendingRef.current = true;
79
+ setSending(true);
80
+
81
+ sendMutation({
82
+ variables: {
83
+ integrationId,
84
+ customerId,
85
+ visitorId,
86
+ conversationId: null,
87
+ contentType: 'text',
88
+ message: text,
89
+ attachments:
90
+ attachments && attachments.length > 0 ? attachments : undefined,
91
+ },
92
+ })
93
+ .then((res: any) => {
94
+ if (res.errors) {
95
+ return console.log(res.errors);
96
+ }
97
+
98
+ const insertedMessage = res.data.widgetsInsertMessage;
99
+ const nextConversationId = insertedMessage?.conversationId;
100
+
101
+ if (nextConversationId) {
102
+ AsyncStorage.setItem('conversationId', nextConversationId);
103
+ setConversationId(nextConversationId);
104
+ }
105
+ })
106
+ .catch((err: any) => {
107
+ console.log(err);
108
+ })
109
+ .finally(() => {
110
+ sendingRef.current = false;
111
+ setSending(false);
112
+ });
113
+ };
114
+
61
115
  const renderLogoButton = () => {
62
116
  if (!showWidget && !hasBack) {
63
117
  return <View style={{ width: LOGO_CHIP, height: LOGO_CHIP }} />;
@@ -86,10 +140,15 @@ const Home = () => {
86
140
  Platform.OS === 'android' ? StatusBar.currentHeight || 0 : 0;
87
141
 
88
142
  return (
89
- <View style={styles.root}>
143
+ <KeyboardAvoidingView
144
+ style={styles.root}
145
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
146
+ >
90
147
  <ScrollView
148
+ style={styles.scroll}
91
149
  showsVerticalScrollIndicator={false}
92
150
  contentContainerStyle={styles.scrollContent}
151
+ keyboardShouldPersistTaps="handled"
93
152
  >
94
153
  {/* Hero */}
95
154
  <SafeAreaView style={[styles.hero, { backgroundColor: bgColor }]}>
@@ -164,7 +223,16 @@ const Home = () => {
164
223
  </View>
165
224
  </View>
166
225
  </ScrollView>
167
- </View>
226
+ <InputTools
227
+ onSend={onSend}
228
+ bgColor={bgColor}
229
+ sendIcon={sendIcon}
230
+ subDomain={subDomain}
231
+ sending={sending}
232
+ persistentMenus={greetings?.persistentMenus}
233
+ placeholder="Start a new conversation..."
234
+ />
235
+ </KeyboardAvoidingView>
168
236
  );
169
237
  };
170
238
 
@@ -175,6 +243,9 @@ const styles = StyleSheet.create({
175
243
  flex: 1,
176
244
  backgroundColor: messengerTheme.colors.background,
177
245
  },
246
+ scroll: {
247
+ flex: 1,
248
+ },
178
249
  scrollContent: {
179
250
  paddingBottom: messengerTheme.spacing.xl,
180
251
  },
@@ -0,0 +1,59 @@
1
+ /* eslint-disable no-bitwise */
2
+ // Lightweight, React Native-compatible replacement for `bson`'s `ObjectId`.
3
+ //
4
+ // The SDK only ever used `new ObjectId().toString()` to mint a `visitorId`,
5
+ // which the erxes backend accepts as a plain `String`. Importing the whole
6
+ // `bson` package for this pulls in `bson/lib/bson.mjs`, whose top-level
7
+ // `await` crashes Metro/Hermes ("await is not defined") once Expo resolves
8
+ // packages through the ESM `exports` map.
9
+ //
10
+ // This helper returns the exact same shape an ObjectId stringifies to:
11
+ // 24 lowercase hexadecimal characters (a 12-byte value made of a 4-byte
12
+ // big-endian timestamp followed by 8 random bytes).
13
+
14
+ const toHex = (bytes: Uint8Array): string => {
15
+ let out = '';
16
+ for (let i = 0; i < bytes.length; i++) {
17
+ const byte = bytes[i] as number;
18
+ out += byte.toString(16).padStart(2, '0');
19
+ }
20
+ return out;
21
+ };
22
+
23
+ const getRandomBytes = (length: number): Uint8Array => {
24
+ const bytes = new Uint8Array(length);
25
+
26
+ // `react-native-get-random-values` (imported by the SDK entry point)
27
+ // polyfills `crypto.getRandomValues` on device. Fall back to `Math.random`
28
+ // so the helper still works in environments without the polyfill (e.g. Jest).
29
+ const cryptoObj =
30
+ typeof globalThis !== 'undefined' ? (globalThis as any).crypto : undefined;
31
+
32
+ if (cryptoObj && typeof cryptoObj.getRandomValues === 'function') {
33
+ cryptoObj.getRandomValues(bytes);
34
+ return bytes;
35
+ }
36
+
37
+ for (let i = 0; i < length; i++) {
38
+ bytes[i] = Math.floor(Math.random() * 256);
39
+ }
40
+ return bytes;
41
+ };
42
+
43
+ export const createObjectIdLikeString = (): string => {
44
+ const bytes = new Uint8Array(12);
45
+
46
+ // 4-byte big-endian timestamp (seconds since epoch), like a real ObjectId.
47
+ const timestamp = Math.floor(Date.now() / 1000);
48
+ bytes[0] = (timestamp >> 24) & 0xff;
49
+ bytes[1] = (timestamp >> 16) & 0xff;
50
+ bytes[2] = (timestamp >> 8) & 0xff;
51
+ bytes[3] = timestamp & 0xff;
52
+
53
+ // Remaining 8 bytes from a CSPRNG when available.
54
+ bytes.set(getRandomBytes(8), 4);
55
+
56
+ return toHex(bytes);
57
+ };
58
+
59
+ export default createObjectIdLikeString;