@abihealth/goapp-react-native 1.20.3 → 1.22.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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.22.0](https://github.com/abiglobalhealth/react-native-sdk/compare/goapp-react-native-v1.21.0...goapp-react-native-v1.22.0) (2025-04-23)
4
+
5
+
6
+ ### Features
7
+
8
+ * add caret to svg dependency ([#172](https://github.com/abiglobalhealth/react-native-sdk/issues/172)) ([79b08fc](https://github.com/abiglobalhealth/react-native-sdk/commit/79b08fc3761e6d5005208eb1b90b4b6a054bf206))
9
+ * add SSL pinning ([#173](https://github.com/abiglobalhealth/react-native-sdk/issues/173)) ([07cbd47](https://github.com/abiglobalhealth/react-native-sdk/commit/07cbd47ef327a7c836d2671485963936ca2cf5f0))
10
+
11
+ ## [1.21.0](https://github.com/abiglobalhealth/react-native-sdk/compare/goapp-react-native-v1.20.3...goapp-react-native-v1.21.0) (2025-04-14)
12
+
13
+
14
+ ### Features
15
+
16
+ * create a styled ConsultationContainer component for cases ([#166](https://github.com/abiglobalhealth/react-native-sdk/issues/166)) ([528f6e5](https://github.com/abiglobalhealth/react-native-sdk/commit/528f6e5b9a96393a271100d0777463baa08281f9))
17
+ * use new domains ([#169](https://github.com/abiglobalhealth/react-native-sdk/issues/169)) ([ee64438](https://github.com/abiglobalhealth/react-native-sdk/commit/ee644381aa86b94344b0ca8a5f5126b16b7d8ea3))
18
+
3
19
  ## [1.20.3](https://github.com/abiglobalhealth/react-native-sdk/compare/goapp-react-native-v1.20.2...goapp-react-native-v1.20.3) (2025-03-27)
4
20
 
5
21
 
package/README.md CHANGED
@@ -1,3 +1,273 @@
1
- # dependencies needed
1
+ # Abi GoApp SDK Installation Guide
2
2
 
3
- `react-native-agora ract-native-svg`
3
+ This guide explains how to install the `@abihealth/goapp-react-native` SDK and its peer dependencies. Correct installation and configuration are needed to use the SDK's features.
4
+
5
+ ## Installation Requirements
6
+
7
+ Install the main package (`@abihealth/goapp-react-native`) and these essential peer dependencies:
8
+
9
+ - **react-native-agora** ([npm](https://www.npmjs.com/package/react-native-agora)): For video calls
10
+ - **react-native-svg** ([npm](https://www.npmjs.com/package/react-native-svg)): For rendering SVGs
11
+ - **react-native-ssl-public-key-pinning** ([npm](https://www.npmjs.com/package/react-native-ssl-public-key-pinning)): For security
12
+
13
+ Follow the instructions for your environment (Bare React Native or Expo). Always consult the official docs for each dependency for detailed information.
14
+
15
+ ## Expo Projects (Managed Workflow)
16
+
17
+ Use these steps for Expo managed workflow (requires a development build).
18
+
19
+ ### 1. Install using expo install
20
+
21
+ This command helps install compatible versions:
22
+
23
+ ```bash
24
+ npx expo install @abihealth/goapp-react-native react-native-agora react-native-svg react-native-ssl-public-key-pinning
25
+ ```
26
+
27
+ ### 2. Configure Permissions and Plugins
28
+
29
+ Set up permissions and required Expo plugins in `app.json` or `app.config.js`:
30
+
31
+ ```json
32
+ {
33
+ "expo": {
34
+ "plugins": [
35
+ [
36
+ "react-native-agora",
37
+ {
38
+ "cameraPermission": "Allow $(PRODUCT_NAME) to access camera for video.",
39
+ "microphonePermission": "Allow $(PRODUCT_NAME) to access microphone for video."
40
+ }
41
+ ]
42
+ ],
43
+ "android": {
44
+ "permissions": ["android.permission.CAMERA", "android.permission.RECORD_AUDIO"]
45
+ },
46
+ "ios": {
47
+ "infoPlist": {
48
+ "NSCameraUsageDescription": "Allow $(PRODUCT_NAME) access for video calls.",
49
+ "NSMicrophoneUsageDescription": "Allow $(PRODUCT_NAME) access for video calls."
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ > **Important**: Plugin configurations may change. Always check official react-native-agora docs. Verify Expo compatibility for react-native-ssl-public-key-pinning.
57
+
58
+ ### 3. Create a Development Build
59
+
60
+ Standard Expo Go is insufficient. Create a development build:
61
+
62
+ ```bash
63
+ npx expo run:android
64
+ # or
65
+ npx expo run:ios
66
+ ```
67
+
68
+ Alternatively, use EAS Build:
69
+
70
+ ```bash
71
+ eas build --profile development --platform [android|ios]
72
+ ```
73
+
74
+ Install the build, then run your project:
75
+
76
+ ```bash
77
+ npx expo start --dev-client
78
+ ```
79
+
80
+ ## Bare React Native Projects
81
+
82
+ Use these steps for standard bare React Native projects.
83
+
84
+ ### 1. Install SDK and dependencies
85
+
86
+ Using npm:
87
+
88
+ ```bash
89
+ npm install @abihealth/goapp-react-native react-native-agora react-native-svg react-native-ssl-public-key-pinning
90
+ ```
91
+
92
+ Or using Yarn:
93
+
94
+ ```bash
95
+ yarn add @abihealth/goapp-react-native react-native-agora react-native-svg react-native-ssl-public-key-pinning
96
+ ```
97
+
98
+ ### 2. Link native dependencies (React Native < 0.60)
99
+
100
+ If using RN < 0.60, you might need manual linking:
101
+
102
+ ```bash
103
+ npx react-native link react-native-agora react-native-svg react-native-ssl-public-key-pinning
104
+ ```
105
+
106
+ > Note: Autolinking should work for RN >= 0.60 (iOS/Android). Verify if issues arise.
107
+
108
+ ### 3. Install Pods (iOS)
109
+
110
+ Install CocoaPods dependencies:
111
+
112
+ ```bash
113
+ cd ios && pod install && cd ..
114
+ ```
115
+
116
+ ### 4. Android Setup & Permissions
117
+
118
+ Add necessary permissions to `android/app/src/main/AndroidManifest.xml`:
119
+
120
+ ```xml
121
+ <uses-permission android:name="android.permission.CAMERA" />
122
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
123
+ ```
124
+
125
+ Agora Specific: Ensure JitPack is in `android/build.gradle`:
126
+
127
+ ```gradle
128
+ allprojects {
129
+ repositories {
130
+ // ... other repositories
131
+ maven { url 'https://www.jitpack.io' }
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### 5. iOS Setup & Permissions
137
+
138
+ Add privacy descriptions to `ios/<YourProjectName>/Info.plist`:
139
+
140
+ - **NSCameraUsageDescription**: Reason for camera access (e.g., "Enable video calls")
141
+ - **NSMicrophoneUsageDescription**: Reason for microphone access (e.g., "Enable audio in video calls")
142
+
143
+ ## Post-Installation
144
+
145
+ After installing and configuring dependencies, import and use `@abihealth/goapp-react-native`. Remember `react-native-ssl-public-key-pinning` needs careful key/domain setup. Ensure your build environment (SDK/NDK versions, Xcode) is correct.
146
+
147
+ ## Usage
148
+
149
+ Basic guide to integrating SDK components:
150
+
151
+ ### 1. Import components and hooks
152
+
153
+ ```typescript
154
+ import { ConsultationsProvider, VideoConsultation, useConsultation } from '@abihealth/goapp-react-native'
155
+ ```
156
+
157
+ ### 2. Wrap your app with ConsultationsProvider
158
+
159
+ Initializes SDK context with necessary configuration:
160
+
161
+ ```jsx
162
+ // Example App.js
163
+ import React from 'react'
164
+ import { ConsultationsProvider } from '@abihealth/goapp-react-native'
165
+ import MainApp from './MainApp'
166
+
167
+ const user_access_token = 'YOUR_USER_ACCESS_TOKEN' // Get from your app logic
168
+ const region = 'YOUR_API_REGION' // Get from your app logic
169
+ // Optional props
170
+ const theme = {
171
+ /* Custom theme */
172
+ }
173
+ const components = {
174
+ /* Custom components */
175
+ }
176
+
177
+ const App = () => {
178
+ const onError = (error) => {
179
+ console.error('SDK Error:', error)
180
+ /* Handle error */
181
+ }
182
+
183
+ return (
184
+ <ConsultationsProvider
185
+ region={region}
186
+ token={user_access_token}
187
+ theme={theme} // Optional
188
+ components={components} // Optional
189
+ onError={onError} // Optional
190
+ >
191
+ {/* Other components */}
192
+ </ConsultationsProvider>
193
+ )
194
+ }
195
+
196
+ export default App
197
+ ```
198
+
199
+ #### Provider Props:
200
+
201
+ - `region` (string, required): API region
202
+ - `token` (string, required): User authentication token
203
+ - `theme` (object, optional): Customize visual theme
204
+ - `components` (object, optional): Override default components
205
+ - `onError` (function, optional): Error callback
206
+
207
+ ### 3. Use the VideoConsultation component
208
+
209
+ Renders the video consultation UI:
210
+
211
+ ```jsx
212
+ // Example ConsultationScreen.js
213
+ import React from 'react'
214
+ import { View } from 'react-native'
215
+ import { VideoConsultation } from '@abihealth/goapp-react-native'
216
+
217
+ // Optional props
218
+ const options = {
219
+ /* Video call options */
220
+ }
221
+
222
+ const ConsultationScreen = () => {
223
+ const eventHandlers = {
224
+ /* Callbacks for events */
225
+ }
226
+
227
+ return <VideoConsultation options={options} eventHandlers={eventHandlers} />
228
+ }
229
+
230
+ export default ConsultationScreen
231
+ ```
232
+
233
+ #### VideoConsultation Props:
234
+
235
+ - `options` (object, optional): Video call appearance/behavior config
236
+ - `eventHandlers` (object, optional): Callbacks for video call events
237
+
238
+ ### 4. Use the useConsultation hook
239
+
240
+ Access consultation state and control functions:
241
+
242
+ ```jsx
243
+ // Example ConsultationControls.js
244
+ import React from 'react'
245
+ import { View, Button, Text } from 'react-native'
246
+ import { useConsultation } from '@abihealth/goapp-react-native'
247
+
248
+ const ConsultationControls = () => {
249
+ const { consultation, start, cancel } = useConsultation()
250
+
251
+ const handleStart = () => start(/* params if needed */)
252
+ const handleCancel = () => cancel(/* params if needed */)
253
+
254
+ return (
255
+ <View>
256
+ {consultation && <Text>Consultation Info: {/* Details */}</Text>}
257
+ <Button title="Start" onPress={handleStart} />
258
+ <Button title="Cancel" onPress={handleCancel} />
259
+ </View>
260
+ )
261
+ }
262
+
263
+ export default ConsultationControls
264
+ ```
265
+
266
+ #### useConsultation Hook returns:
267
+
268
+ - `consultation` (object | null): Current/last consultation info
269
+ - `start` (function): Initiates consultation
270
+ - `cancel` (function): Cancels consultation
271
+ - Other values may be available; check SDK docs
272
+
273
+ Always consult the specific `@abihealth/goapp-react-native` documentation for details on props, events, hooks, parameters, and advanced configuration.
@@ -6,10 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.axios = exports.configureAxios = void 0;
7
7
  var axios_1 = __importDefault(require("axios"));
8
8
  exports.axios = axios_1.default;
9
- var BASE_URL = { ape1: 'https://m10bzqot97.execute-api.ap-east-1.amazonaws.com/prod' };
10
9
  var configureAxios = function (_a) {
11
10
  var token = _a.token, region = _a.region;
12
- axios_1.default.defaults.baseURL = BASE_URL[region];
11
+ axios_1.default.defaults.baseURL = "https://".concat(region, ".sdk.abi.ai");
13
12
  axios_1.default.defaults.headers.common.Authorization = "Bearer ".concat(token);
14
13
  };
15
14
  exports.configureAxios = configureAxios;
@@ -6,5 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getPartnerInfo = void 0;
7
7
  var axios_1 = __importDefault(require("axios"));
8
8
  var PARTNER_URL = 'partner';
9
- var getPartnerInfo = function () { return axios_1.default.get(PARTNER_URL).then(function (response) { return response === null || response === void 0 ? void 0 : response.data; }); };
9
+ var getPartnerInfo = function () {
10
+ return axios_1.default.get(PARTNER_URL).then(function (response) { return response === null || response === void 0 ? void 0 : response.data; });
11
+ };
10
12
  exports.getPartnerInfo = getPartnerInfo;
@@ -0,0 +1 @@
1
+ export declare const initializeSslPinning: (disableSslPinning: boolean) => Promise<void>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.initializeSslPinning = void 0;
40
+ var react_native_ssl_public_key_pinning_1 = require("react-native-ssl-public-key-pinning");
41
+ var initializeSslPinning = function (disableSslPinning) { return __awaiter(void 0, void 0, void 0, function () {
42
+ return __generator(this, function (_a) {
43
+ switch (_a.label) {
44
+ case 0:
45
+ if (!disableSslPinning) return [3 /*break*/, 2];
46
+ return [4 /*yield*/, (0, react_native_ssl_public_key_pinning_1.disableSslPinning)()];
47
+ case 1:
48
+ _a.sent();
49
+ return [2 /*return*/, console.log('🔒🚫 SSL pinning disabled')];
50
+ case 2: return [4 /*yield*/, (0, react_native_ssl_public_key_pinning_1.initializeSslPinning)({
51
+ 'ape1.sdk.abi.ai': {
52
+ publicKeyHashes: ['95kHJrJXD1L/WORHTc5rh99KvZ10Ipd9m7eW0JUsLnA=', 'b+nnCNzPN8D2jN0srTRwMXqLUjmnZODZ0k28NZFFrkc=']
53
+ }
54
+ })];
55
+ case 3:
56
+ _a.sent();
57
+ return [2 /*return*/, console.log('🔒 SSL pinning initialized')];
58
+ }
59
+ });
60
+ }); };
61
+ exports.initializeSslPinning = initializeSslPinning;
@@ -37,14 +37,13 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.connectWebsocket = void 0;
40
- var WS_URL = { ape1: 'wss://yrmfk5amqg.execute-api.ap-east-1.amazonaws.com/prod' };
41
40
  var connectWebsocket = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
42
41
  var token = _b.token, userId = _b.userId, region = _b.region;
43
42
  return __generator(this, function (_c) {
44
43
  return [2 /*return*/, new Promise(function (resolve, reject) {
45
44
  console.log('❔ Connecting to WS...', { token: token, userId: userId, region: region });
46
45
  try {
47
- var websocket_1 = new WebSocket("".concat(WS_URL[region], "?eventType=CONNECT"), null);
46
+ var websocket_1 = new WebSocket("wss://".concat(region, ".sdk-ws.abi.ai?eventType=CONNECT"), null);
48
47
  websocket_1.onopen = function () {
49
48
  console.log('🟢 WS connected');
50
49
  websocket_1.send(JSON.stringify({ action: 'connect', payload: { userId: userId, token: "Bearer ".concat(token) } }));
@@ -0,0 +1,2 @@
1
+ import { PropsWithChildren } from 'react';
2
+ export declare const ConsultationContainer: ({ children }: PropsWithChildren) => import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConsultationContainer = void 0;
4
+ var react_native_1 = require("react-native");
5
+ var ConsultationContainer = function (_a) {
6
+ var children = _a.children;
7
+ return <react_native_1.View style={styles.container}>{children}</react_native_1.View>;
8
+ };
9
+ exports.ConsultationContainer = ConsultationContainer;
10
+ var styles = react_native_1.StyleSheet.create({
11
+ container: { flex: 1, width: '100%', minWidth: '100%' }
12
+ });
@@ -11,6 +11,7 @@ interface ConsultationProviderProps {
11
11
  theme?: RecursivePartial<Theme>;
12
12
  components?: (theme: Theme) => Components;
13
13
  onError?: ErrorCallback;
14
+ disableSslPinning?: boolean;
14
15
  }
15
16
  export type ConsultationContextProps = ConsultationProviderProps & {
16
17
  consultation: Consultation | null;
@@ -20,7 +21,8 @@ export type ConsultationContextProps = ConsultationProviderProps & {
20
21
  user: User;
21
22
  setUser: Dispatch<SetStateAction<User>>;
22
23
  slug: string | null;
24
+ initialised: boolean;
23
25
  };
24
26
  export declare const ConsultationContext: import("react").Context<ConsultationContextProps>;
25
- export declare const ConsultationProvider: ({ children, token, region, theme, components, onError }: PropsWithChildren<ConsultationProviderProps>) => import("react").JSX.Element;
27
+ export declare const ConsultationProvider: ({ children, token, region, theme, components, onError, disableSslPinning }: PropsWithChildren<ConsultationProviderProps>) => import("react").JSX.Element;
26
28
  export {};
@@ -42,6 +42,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.ConsultationProvider = exports.ConsultationContext = void 0;
43
43
  var config_1 = require("../api/config");
44
44
  var partner_1 = require("../api/partner");
45
+ var sslPinning_1 = require("../api/sslPinning");
45
46
  var user_1 = require("../api/user");
46
47
  var websocket_1 = require("../api/websocket");
47
48
  var i18n_1 = __importDefault(require("../locale/i18n"));
@@ -49,6 +50,7 @@ var theme_1 = require("../types/theme");
49
50
  var axios_1 = require("axios");
50
51
  var react_1 = require("react");
51
52
  var react_i18next_1 = require("react-i18next");
53
+ var react_native_ssl_public_key_pinning_1 = require("react-native-ssl-public-key-pinning");
52
54
  var ThemeContext_1 = require("./ThemeContext");
53
55
  // eslint-disable-next-line react-refresh/only-export-components
54
56
  exports.ConsultationContext = (0, react_1.createContext)({
@@ -62,75 +64,87 @@ exports.ConsultationContext = (0, react_1.createContext)({
62
64
  userId: '',
63
65
  setUserId: function () { },
64
66
  components: function () { return ({}); },
65
- slug: null
67
+ slug: null,
68
+ initialised: false
66
69
  });
67
70
  var ConsultationProvider = function (_a) {
68
- var children = _a.children, token = _a.token, region = _a.region, theme = _a.theme, components = _a.components, _b = _a.onError, onError = _b === void 0 ? function () { } : _b;
69
- var _c = (0, react_1.useState)(null), consultation = _c[0], setConsultation = _c[1];
70
- var _d = (0, react_1.useState)(null), userId = _d[0], setUserId = _d[1];
71
- var _e = (0, react_1.useState)(null), user = _e[0], setUser = _e[1];
72
- var _f = (0, react_1.useState)(null), websocket = _f[0], setWebsocket = _f[1];
73
- var _g = (0, react_1.useState)(null), slug = _g[0], setSlug = _g[1];
71
+ var children = _a.children, token = _a.token, region = _a.region, theme = _a.theme, components = _a.components, _b = _a.onError, onError = _b === void 0 ? function () { } : _b, _c = _a.disableSslPinning, disableSslPinning = _c === void 0 ? false : _c;
72
+ var _d = (0, react_1.useState)(null), consultation = _d[0], setConsultation = _d[1];
73
+ var _e = (0, react_1.useState)(null), userId = _e[0], setUserId = _e[1];
74
+ var _f = (0, react_1.useState)(null), user = _f[0], setUser = _f[1];
75
+ var _g = (0, react_1.useState)(null), websocket = _g[0], setWebsocket = _g[1];
76
+ var _h = (0, react_1.useState)(null), slug = _h[0], setSlug = _h[1];
77
+ var _j = (0, react_1.useState)(false), initialised = _j[0], setInitialised = _j[1];
74
78
  var handleError = function (e) {
75
79
  console.error('🚨 Error caught on handler', e);
76
80
  onError(e);
77
81
  };
78
82
  var initialise = function () { return __awaiter(void 0, void 0, void 0, function () {
79
- var partnerInfo, e_1, userResponse, e_2, activeConsultation, e_3, ws, e_4;
83
+ var e_1, partnerInfo, e_2, userResponse, e_3, activeConsultation, e_4, ws, e_5;
80
84
  return __generator(this, function (_a) {
81
85
  switch (_a.label) {
82
86
  case 0:
83
87
  _a.trys.push([0, 2, , 3]);
84
- return [4 /*yield*/, (0, partner_1.getPartnerInfo)()];
88
+ return [4 /*yield*/, (0, sslPinning_1.initializeSslPinning)(disableSslPinning)];
85
89
  case 1:
86
- partnerInfo = _a.sent();
87
- setSlug(partnerInfo.slug);
90
+ _a.sent();
88
91
  return [3 /*break*/, 3];
89
92
  case 2:
90
93
  e_1 = _a.sent();
91
- console.error('Error getting partner info', e_1);
94
+ console.error('Error initializing SSL pinning', e_1);
92
95
  throw e_1;
93
96
  case 3:
94
97
  _a.trys.push([3, 5, , 6]);
95
- return [4 /*yield*/, (0, user_1.getUser)({ userId: userId })];
98
+ return [4 /*yield*/, (0, partner_1.getPartnerInfo)()];
96
99
  case 4:
97
- userResponse = _a.sent();
98
- setUser(userResponse);
100
+ partnerInfo = _a.sent();
101
+ setSlug(partnerInfo.slug);
99
102
  return [3 /*break*/, 6];
100
103
  case 5:
101
104
  e_2 = _a.sent();
102
- console.error('Error getting user', e_2);
105
+ console.error('Error getting partner info', e_2);
103
106
  throw e_2;
104
107
  case 6:
105
108
  _a.trys.push([6, 8, , 9]);
106
- return [4 /*yield*/, (0, user_1.getActiveConsultation)({ userId: userId })];
109
+ return [4 /*yield*/, (0, user_1.getUser)({ userId: userId })];
107
110
  case 7:
108
- activeConsultation = _a.sent();
109
- console.log('⏮️ Active:', activeConsultation.consultation);
110
- setConsultation(activeConsultation === null || activeConsultation === void 0 ? void 0 : activeConsultation.consultation);
111
+ userResponse = _a.sent();
112
+ setUser(userResponse);
111
113
  return [3 /*break*/, 9];
112
114
  case 8:
113
115
  e_3 = _a.sent();
114
- if ((0, axios_1.isAxiosError)(e_3) && e_3.status === 404) {
116
+ console.error('Error getting user', e_3);
117
+ throw e_3;
118
+ case 9:
119
+ _a.trys.push([9, 11, , 12]);
120
+ return [4 /*yield*/, (0, user_1.getActiveConsultation)({ userId: userId })];
121
+ case 10:
122
+ activeConsultation = _a.sent();
123
+ console.log('⏮️ Active:', activeConsultation.consultation);
124
+ setConsultation(activeConsultation === null || activeConsultation === void 0 ? void 0 : activeConsultation.consultation);
125
+ return [3 /*break*/, 12];
126
+ case 11:
127
+ e_4 = _a.sent();
128
+ if ((0, axios_1.isAxiosError)(e_4) && e_4.status === 404) {
115
129
  setConsultation(null);
116
130
  }
117
131
  else {
118
- console.error('Error getting active consultation', e_3);
119
- throw e_3;
132
+ console.error('Error getting active consultation', e_4);
133
+ throw e_4;
120
134
  }
121
- return [3 /*break*/, 9];
122
- case 9:
123
- _a.trys.push([9, 11, , 12]);
135
+ return [3 /*break*/, 12];
136
+ case 12:
137
+ _a.trys.push([12, 14, , 15]);
124
138
  return [4 /*yield*/, (0, websocket_1.connectWebsocket)({ token: token, userId: userId, region: region })];
125
- case 10:
139
+ case 13:
126
140
  ws = _a.sent();
127
141
  setWebsocket(ws);
128
- return [3 /*break*/, 12];
129
- case 11:
130
- e_4 = _a.sent();
131
- console.error('Error connecting to websocket', e_4);
132
- throw e_4;
133
- case 12: return [2 /*return*/];
142
+ return [3 /*break*/, 15];
143
+ case 14:
144
+ e_5 = _a.sent();
145
+ console.error('Error connecting to websocket', e_5);
146
+ throw e_5;
147
+ case 15: return [2 /*return*/];
134
148
  }
135
149
  });
136
150
  }); };
@@ -143,7 +157,8 @@ var ConsultationProvider = function (_a) {
143
157
  var method = config.method, url = config.url, data = config.data;
144
158
  console.log({
145
159
  service: 'API Rest',
146
- message: "".concat(method === null || method === void 0 ? void 0 : method.toUpperCase(), " ").concat(url, " ").concat(data !== undefined ? "- body: ".concat(JSON.stringify(data)) : ' ')
160
+ message: "".concat(method === null || method === void 0 ? void 0 : method.toUpperCase(), " ").concat(url, " ").concat(data !== undefined ? "- body: ".concat(JSON.stringify(data)) : ' '),
161
+ headers: config.headers
147
162
  });
148
163
  return config;
149
164
  });
@@ -177,8 +192,10 @@ var ConsultationProvider = function (_a) {
177
192
  setConsultation(data.consultation);
178
193
  if (data.event === 'websocketError')
179
194
  handleError(new Error('Websocket error'));
180
- if (data.event === 'websocketConnected')
195
+ if (data.event === 'websocketConnected') {
181
196
  console.log('🟢🟢 Websocket connected');
197
+ setInitialised(true);
198
+ }
182
199
  };
183
200
  websocket.onclose = function (e) {
184
201
  console.log('❌ WS closed', JSON.stringify(e, null, 2));
@@ -186,6 +203,10 @@ var ConsultationProvider = function (_a) {
186
203
  (0, websocket_1.connectWebsocket)({ token: token, userId: userId, region: region }).then(setWebsocket).catch(handleError);
187
204
  };
188
205
  }, [websocket]);
206
+ (0, react_1.useEffect)(function () {
207
+ var subscription = (0, react_native_ssl_public_key_pinning_1.addSslPinningErrorListener)(console.error);
208
+ return function () { return subscription.remove(); };
209
+ }, []);
189
210
  var value = {
190
211
  token: token,
191
212
  region: region,
@@ -197,7 +218,8 @@ var ConsultationProvider = function (_a) {
197
218
  onError: handleError,
198
219
  user: user,
199
220
  setUser: setUser,
200
- slug: slug
221
+ slug: slug,
222
+ initialised: initialised
201
223
  };
202
224
  return (<exports.ConsultationContext.Provider value={value}>
203
225
  <react_i18next_1.I18nextProvider i18n={i18n_1.default}>
@@ -3,6 +3,7 @@ import { ConsultationContextProps } from '../contexts/ConsultationContext';
3
3
  import { CASE_TYPE, Consultation } from '../types/consultation';
4
4
  interface UseConsultationProps {
5
5
  consultation: ConsultationContextProps['consultation'];
6
+ initialised: ConsultationContextProps['initialised'];
6
7
  updateConsultation: (_: Consultation) => void;
7
8
  start: (caseType: CASE_TYPE, payload: CreateConsultationRequest) => Promise<Consultation>;
8
9
  cancel: () => Promise<Consultation>;
@@ -50,7 +50,7 @@ var react_1 = require("react");
50
50
  var useUser_1 = require("./useUser");
51
51
  var useConsultation = function () {
52
52
  var _a;
53
- var _b = (0, react_1.useContext)(ConsultationContext_1.ConsultationContext), consultation = _b.consultation, setConsultation = _b.setConsultation, onError = _b.onError;
53
+ var _b = (0, react_1.useContext)(ConsultationContext_1.ConsultationContext), consultation = _b.consultation, setConsultation = _b.setConsultation, onError = _b.onError, initialised = _b.initialised;
54
54
  var user = (0, useUser_1.useUser)().user;
55
55
  var minLength = (0, react_1.useMemo)(function () {
56
56
  switch (user === null || user === void 0 ? void 0 : user.language) {
@@ -176,7 +176,8 @@ var useConsultation = function () {
176
176
  start: start,
177
177
  cancel: cancel,
178
178
  close: close,
179
- rate: rate
179
+ rate: rate,
180
+ initialised: initialised
180
181
  };
181
182
  };
182
183
  exports.useConsultation = useConsultation;
@@ -2,11 +2,12 @@
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.FormPrescription = void 0;
5
+ var ConsultationContainer_1 = require("../../common/components/ConsultationContainer");
5
6
  var eventHandler_1 = require("../../common/helpers/eventHandler");
6
7
  var useConsultation_1 = require("../../common/hooks/useConsultation");
7
8
  var useUser_1 = require("../../common/hooks/useUser");
8
- var utils_1 = require("../../common/screens/utils");
9
9
  var NotValidActiveTypeScreen_1 = require("../../common/screens/NotValidActiveTypeScreen");
10
+ var utils_1 = require("../../common/screens/utils");
10
11
  var consultation_1 = require("../../common/types/consultation");
11
12
  var valid_active_type_1 = require("../../common/utils/valid-active-type");
12
13
  var IndicationSurveyContext_1 = require("../contexts/IndicationSurveyContext");
@@ -55,12 +56,9 @@ var FormPrescription = function (_a) {
55
56
  setUserId(userId);
56
57
  }, [userId]);
57
58
  return (<IndicationSurveyContext_1.IndicationSurveyProvider>
58
- <react_native_1.View style={styles.container}>
59
+ <ConsultationContainer_1.ConsultationContainer>
59
60
  <ConsultationScreen />
60
- </react_native_1.View>
61
+ </ConsultationContainer_1.ConsultationContainer>
61
62
  </IndicationSurveyContext_1.IndicationSurveyProvider>);
62
63
  };
63
64
  exports.FormPrescription = FormPrescription;
64
- var styles = react_native_1.StyleSheet.create({
65
- container: { flex: 1 }
66
- });
@@ -1,17 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TextConsultation = void 0;
4
+ var ConsultationContainer_1 = require("../../common/components/ConsultationContainer");
4
5
  var eventHandler_1 = require("../../common/helpers/eventHandler");
5
6
  var useConsultation_1 = require("../../common/hooks/useConsultation");
6
7
  var useUser_1 = require("../../common/hooks/useUser");
7
- var utils_1 = require("../../common/screens/utils");
8
8
  var NoConsultationFoundScreen_1 = require("../../common/screens/NoConsultationFoundScreen");
9
9
  var NotValidActiveTypeScreen_1 = require("../../common/screens/NotValidActiveTypeScreen");
10
+ var utils_1 = require("../../common/screens/utils");
10
11
  var consultation_1 = require("../../common/types/consultation");
11
12
  var valid_active_type_1 = require("../../common/utils/valid-active-type");
12
13
  var HomeScreen_1 = require("../screens/HomeScreen");
13
14
  var react_1 = require("react");
14
- var react_native_1 = require("react-native");
15
15
  var TextConsultation = function (_a) {
16
16
  var eventHandlers = _a.eventHandlers, userId = _a.userId;
17
17
  var consultation = (0, useConsultation_1.useConsultation)().consultation;
@@ -33,9 +33,6 @@ var TextConsultation = function (_a) {
33
33
  return <NoConsultationFoundScreen_1.NoConsultationFoundScreen />;
34
34
  return <HomeScreen_1.HomeScreen />;
35
35
  }, [consultation]);
36
- return <react_native_1.View style={styles.container}>{getConsultationScreen(consultation)}</react_native_1.View>;
36
+ return <ConsultationContainer_1.ConsultationContainer>{getConsultationScreen(consultation)}</ConsultationContainer_1.ConsultationContainer>;
37
37
  };
38
38
  exports.TextConsultation = TextConsultation;
39
- var styles = react_native_1.StyleSheet.create({
40
- container: { flex: 1 }
41
- });
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VideoConsultation = void 0;
4
+ var ConsultationContainer_1 = require("../../common/components/ConsultationContainer");
4
5
  var eventHandler_1 = require("../../common/helpers/eventHandler");
5
6
  var useConsultation_1 = require("../../common/hooks/useConsultation");
6
7
  var useUser_1 = require("../../common/hooks/useUser");
7
- var utils_1 = require("../../common/screens/utils");
8
8
  var NoConsultationFoundScreen_1 = require("../../common/screens/NoConsultationFoundScreen");
9
9
  var NotValidActiveTypeScreen_1 = require("../../common/screens/NotValidActiveTypeScreen");
10
10
  var PreparingSummaryScreen_1 = require("../../common/screens/PreparingSummaryScreen");
11
+ var utils_1 = require("../../common/screens/utils");
11
12
  var consultation_1 = require("../../common/types/consultation");
12
13
  var valid_active_type_1 = require("../../common/utils/valid-active-type");
13
14
  var DeliveryAddressScreen_1 = require("../screens/DeliveryAddressScreen");
@@ -49,9 +50,6 @@ var VideoConsultation = function (_a) {
49
50
  throw new Error("Screen not found ".concat(status));
50
51
  }
51
52
  }, [consultation]);
52
- return <react_native_1.View style={styles.container}>{getConsultationScreen(consultation)}</react_native_1.View>;
53
+ return <ConsultationContainer_1.ConsultationContainer>{getConsultationScreen(consultation)}</ConsultationContainer_1.ConsultationContainer>;
53
54
  };
54
55
  exports.VideoConsultation = VideoConsultation;
55
- var styles = react_native_1.StyleSheet.create({
56
- container: { flex: 1 }
57
- });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abihealth/goapp-react-native",
3
- "version": "1.20.3",
3
+ "version": "1.22.0",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
@@ -15,26 +15,27 @@
15
15
  "main": "./dist/index.js",
16
16
  "types": "./dist/index.d.ts",
17
17
  "dependencies": {
18
- "axios": "^1.7.9",
19
- "i18next": "^23.16.8",
20
- "phone": "^3.1.58",
21
- "react-i18next": "^14.1.3",
22
- "react-native-agora": "^4.4.0",
23
- "react-native-bouncy-checkbox": "^4.1.2",
18
+ "axios": "1.7.9",
19
+ "i18next": "23.16.8",
20
+ "phone": "3.1.58",
21
+ "react-i18next": "14.1.3",
22
+ "react-native-agora": "4.5.2",
23
+ "react-native-bouncy-checkbox": "4.1.2",
24
24
  "react-native-date-picker": "5.0.1",
25
- "react-native-phone-input": "^1.3.7",
25
+ "react-native-phone-input": "1.3.7",
26
26
  "react-native-svg": "^15.11.1",
27
- "zod": "^3.24.1"
27
+ "react-native-ssl-public-key-pinning": "^1.2.5",
28
+ "zod": "3.24.1"
28
29
  },
29
30
  "devDependencies": {
30
31
  "@abiglobalhealth/ts-config": "1.3.0",
31
- "@tsconfig/react-native": "^3.0.5",
32
- "@types/jest": "^29.5.12",
33
- "@types/react": "~18.3.12",
34
- "@types/react-native": "^0.73.0",
35
- "concurrently": "^9.1.2",
36
- "tsc-alias": "^1.8.10",
37
- "typescript": "^5.7.3"
32
+ "@tsconfig/react-native": "3.0.5",
33
+ "@types/jest": "29.5.12",
34
+ "@types/react": "18.3.12",
35
+ "@types/react-native": "0.73.0",
36
+ "concurrently": "9.1.2",
37
+ "tsc-alias": "1.8.10",
38
+ "typescript": "5.7.3"
38
39
  },
39
40
  "peerDependencies": {
40
41
  "react": ">=18.0.0",