pih-appointment-widget 0.0.27 → 0.0.29

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/README.md CHANGED
@@ -1,70 +1,70 @@
1
- # Getting Started with Create React App
2
-
3
- This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4
-
5
- ## Available Scripts
6
-
7
- In the project directory, you can run:
8
-
9
- ### `npm start`
10
-
11
- Runs the app in the development mode.\
12
- Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13
-
14
- The page will reload when you make changes.\
15
- You may also see any lint errors in the console.
16
-
17
- ### `npm test`
18
-
19
- Launches the test runner in the interactive watch mode.\
20
- See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21
-
22
- ### `npm run build`
23
-
24
- Builds the app for production to the `build` folder.\
25
- It correctly bundles React in production mode and optimizes the build for the best performance.
26
-
27
- The build is minified and the filenames include the hashes.\
28
- Your app is ready to be deployed!
29
-
30
- See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31
-
32
- ### `npm run eject`
33
-
34
- **Note: this is a one-way operation. Once you `eject`, you can't go back!**
35
-
36
- If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37
-
38
- Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
39
-
40
- You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
41
-
42
- ## Learn More
43
-
44
- You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45
-
46
- To learn React, check out the [React documentation](https://reactjs.org/).
47
-
48
- ### Code Splitting
49
-
50
- This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51
-
52
- ### Analyzing the Bundle Size
53
-
54
- This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55
-
56
- ### Making a Progressive Web App
57
-
58
- This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59
-
60
- ### Advanced Configuration
61
-
62
- This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63
-
64
- ### Deployment
65
-
66
- This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67
-
68
- ### `npm run build` fails to minify
69
-
70
- This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
1
+ # Getting Started with Create React App
2
+
3
+ This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4
+
5
+ ## Available Scripts
6
+
7
+ In the project directory, you can run:
8
+
9
+ ### `npm start`
10
+
11
+ Runs the app in the development mode.\
12
+ Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13
+
14
+ The page will reload when you make changes.\
15
+ You may also see any lint errors in the console.
16
+
17
+ ### `npm test`
18
+
19
+ Launches the test runner in the interactive watch mode.\
20
+ See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21
+
22
+ ### `npm run build`
23
+
24
+ Builds the app for production to the `build` folder.\
25
+ It correctly bundles React in production mode and optimizes the build for the best performance.
26
+
27
+ The build is minified and the filenames include the hashes.\
28
+ Your app is ready to be deployed!
29
+
30
+ See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31
+
32
+ ### `npm run eject`
33
+
34
+ **Note: this is a one-way operation. Once you `eject`, you can't go back!**
35
+
36
+ If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37
+
38
+ Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
39
+
40
+ You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
41
+
42
+ ## Learn More
43
+
44
+ You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45
+
46
+ To learn React, check out the [React documentation](https://reactjs.org/).
47
+
48
+ ### Code Splitting
49
+
50
+ This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51
+
52
+ ### Analyzing the Bundle Size
53
+
54
+ This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55
+
56
+ ### Making a Progressive Web App
57
+
58
+ This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59
+
60
+ ### Advanced Configuration
61
+
62
+ This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63
+
64
+ ### Deployment
65
+
66
+ This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67
+
68
+ ### `npm run build` fails to minify
69
+
70
+ This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
package/babel.config.js CHANGED
@@ -1,6 +1,6 @@
1
- module.exports = {
2
- presets: [
3
- '@babel/preset-env',
4
- '@babel/preset-react'
5
- ],
1
+ module.exports = {
2
+ presets: [
3
+ '@babel/preset-env',
4
+ '@babel/preset-react'
5
+ ],
6
6
  };
package/dist/App.js CHANGED
@@ -19,20 +19,21 @@ exports.default = void 0;
19
19
  var _react = _interopRequireDefault(require("react"));
20
20
  var _reactDom = _interopRequireDefault(require("react-dom"));
21
21
  var _AppointmentPage = _interopRequireWildcard(require("./components/AppointmentPage.js"));
22
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
22
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
23
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
23
24
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
24
25
  let bookingWidgetInstance = null;
25
26
 
26
27
  // SDK for embedding appointment widget
27
28
  const BookingSDK = {
28
- /**
29
- * Show appointment widget with configuration
30
- * @param {object} config - Configuration object
31
- * @param {string} config.apiBaseUrl - Base URL for API
32
- * @param {string} config.hospitalId - Hospital ID
33
- * @param {number} config.doctorId - Doctor ID
34
- * @param {string} config.joinCallUrl - Video call URL
35
- * @param {function} onAction - Optional callback for actions
29
+ /**
30
+ * Show appointment widget with configuration
31
+ * @param {object} config - Configuration object
32
+ * @param {string} config.apiBaseUrl - Base URL for API
33
+ * @param {string} config.hospitalId - Hospital ID
34
+ * @param {number} config.doctorId - Doctor ID
35
+ * @param {string} config.joinCallUrl - Video call URL
36
+ * @param {function} onAction - Optional callback for actions
36
37
  */
37
38
  showWidget: (config, onAction) => {
38
39
  if (!bookingWidgetInstance) {
@@ -8,10 +8,8 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _appointmentService = require("../services/appointmentService");
9
9
  var _httpService = require("../services/httpService");
10
10
  var _apiConfig = require("../constants/apiConfig");
11
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
- function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
13
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
14
- function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
11
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
12
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
15
13
  // Decode JWT payload (no verification; for display only). Returns {} on invalid/missing.
16
14
  function getJwtPayload(token) {
17
15
  if (!token || typeof token !== "string") return {};
@@ -21,7 +19,7 @@ function getJwtPayload(token) {
21
19
  const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
22
20
  const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
23
21
  return JSON.parse(atob(padded));
24
- } catch (_unused) {
22
+ } catch {
25
23
  return {};
26
24
  }
27
25
  }
@@ -41,32 +39,26 @@ const PIH_APPOINTMENT_WIDGET_DATA_ATTR = "data-pih-widget";
41
39
 
42
40
  // Extract from SSO login response (not from appToken JWT — these are only in login response)
43
41
  function extractAppToken(response) {
44
- var _ref, _ref2, _ref3, _response$data$access, _response$data, _response$data2;
45
42
  if (!response || response.err) return null;
46
- return (_ref = (_ref2 = (_ref3 = (_response$data$access = (_response$data = response.data) === null || _response$data === void 0 ? void 0 : _response$data.access_token) !== null && _response$data$access !== void 0 ? _response$data$access : (_response$data2 = response.data) === null || _response$data2 === void 0 ? void 0 : _response$data2.token) !== null && _ref3 !== void 0 ? _ref3 : response.token) !== null && _ref2 !== void 0 ? _ref2 : response.accessToken) !== null && _ref !== void 0 ? _ref : null;
43
+ return response.data?.access_token ?? response.data?.token ?? response.token ?? response.accessToken ?? null;
47
44
  }
48
45
  function extractDoctorIdFromLoginResponse(response) {
49
- var _ref4, _response$data$doctor;
50
- if (!(response !== null && response !== void 0 && response.data)) return null;
51
- const id = (_ref4 = (_response$data$doctor = response.data.doctor_id) !== null && _response$data$doctor !== void 0 ? _response$data$doctor : response.data.doctorId) !== null && _ref4 !== void 0 ? _ref4 : null;
46
+ if (!response?.data) return null;
47
+ const id = response.data.doctor_id ?? response.data.doctorId ?? null;
52
48
  console.log(id, 'extractDoctorIdFromLoginResponse -> id');
53
49
  return id != null ? String(id) : null;
54
50
  }
55
51
  function extractUserNameFromLoginResponse(response) {
56
- var _ref5, _ref6, _response$data$name;
57
- if (!(response !== null && response !== void 0 && response.data)) return null;
58
- const name = (_ref5 = (_ref6 = (_response$data$name = response.data.name) !== null && _response$data$name !== void 0 ? _response$data$name : response.data.doctor_name) !== null && _ref6 !== void 0 ? _ref6 : response.data.userName) !== null && _ref5 !== void 0 ? _ref5 : null;
52
+ if (!response?.data) return null;
53
+ const name = response.data.name ?? response.data.doctor_name ?? response.data.userName ?? null;
59
54
  return name != null ? String(name) : null;
60
55
  }
61
56
 
62
57
  // Error boundary so a render error never shows a blank screen
63
58
  class AppointmentErrorBoundary extends _react.Component {
64
- constructor() {
65
- super(...arguments);
66
- _defineProperty(this, "state", {
67
- hasError: false
68
- });
69
- }
59
+ state = {
60
+ hasError: false
61
+ };
70
62
  static getDerivedStateFromError() {
71
63
  return {
72
64
  hasError: true
@@ -123,21 +115,21 @@ class AppointmentErrorBoundary extends _react.Component {
123
115
  }
124
116
 
125
117
  // SDK Component - accepts configuration from parent app
126
- const AppointmentPage = _ref7 => {
118
+ const AppointmentPage = _ref => {
127
119
  let {
128
120
  config = {}
129
- } = _ref7;
121
+ } = _ref;
130
122
  const [storedApiBaseUrl, setStoredApiBaseUrl] = (0, _react.useState)(() => {
131
123
  try {
132
124
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_API_BASE_URL) : null;
133
- } catch (_unused2) {
125
+ } catch {
134
126
  return null;
135
127
  }
136
128
  });
137
129
  const [storedHospitalId, setStoredHospitalId] = (0, _react.useState)(() => {
138
130
  try {
139
131
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_HOSPITAL_ID) : null;
140
- } catch (_unused3) {
132
+ } catch {
141
133
  return null;
142
134
  }
143
135
  });
@@ -148,14 +140,14 @@ const AppointmentPage = _ref7 => {
148
140
  const [storedIdToken, setStoredIdToken] = (0, _react.useState)(() => {
149
141
  try {
150
142
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_ID_TOKEN) : null;
151
- } catch (_unused4) {
143
+ } catch {
152
144
  return null;
153
145
  }
154
146
  });
155
147
  const [storedEmail, setStoredEmail] = (0, _react.useState)(() => {
156
148
  try {
157
149
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_EMAIL) : null;
158
- } catch (_unused5) {
150
+ } catch {
159
151
  return null;
160
152
  }
161
153
  });
@@ -170,10 +162,12 @@ const AppointmentPage = _ref7 => {
170
162
  if (token && String(token).trim()) {
171
163
  const prevToken = localStorage.getItem(STORAGE_KEY_ID_TOKEN);
172
164
  if (prevToken !== token) {
173
- // New token from parent (e.g. Flutter opened with different user) — clear app token so we SSO with new credentials
165
+ // New token from parent (e.g. Flutter re-login) — clear app token and force SSO for the new session.
166
+ // refreshLoginTrigger increment guarantees SSO re-runs even if appToken was already null in state.
174
167
  setAppToken(null);
175
168
  setDoctorIdFromLogin(null);
176
169
  setUserName(null);
170
+ setRefreshLoginTrigger(t => t + 1);
177
171
  localStorage.removeItem(STORAGE_KEY_APP_TOKEN);
178
172
  localStorage.removeItem(STORAGE_KEY_DOCTOR_ID);
179
173
  localStorage.removeItem(STORAGE_KEY_USER_NAME);
@@ -198,21 +192,21 @@ const AppointmentPage = _ref7 => {
198
192
  const [appToken, setAppToken] = (0, _react.useState)(() => {
199
193
  try {
200
194
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_APP_TOKEN) : null;
201
- } catch (_unused6) {
195
+ } catch {
202
196
  return null;
203
197
  }
204
198
  });
205
199
  const [doctorIdFromLogin, setDoctorIdFromLogin] = (0, _react.useState)(() => {
206
200
  try {
207
201
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_DOCTOR_ID) : null;
208
- } catch (_unused7) {
202
+ } catch {
209
203
  return null;
210
204
  }
211
205
  });
212
206
  const [userName, setUserName] = (0, _react.useState)(() => {
213
207
  try {
214
208
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_USER_NAME) : null;
215
- } catch (_unused8) {
209
+ } catch {
216
210
  return null;
217
211
  }
218
212
  });
@@ -223,7 +217,7 @@ const AppointmentPage = _ref7 => {
223
217
  const hasId = localStorage.getItem(STORAGE_KEY_ID_TOKEN);
224
218
  const hasEmail = localStorage.getItem(STORAGE_KEY_EMAIL);
225
219
  return !hasApp && !!(hasId && hasEmail);
226
- } catch (_unused9) {
220
+ } catch {
227
221
  return false;
228
222
  }
229
223
  });
@@ -285,7 +279,7 @@ const AppointmentPage = _ref7 => {
285
279
  const y = date.getFullYear();
286
280
  const m = String(date.getMonth() + 1).padStart(2, "0");
287
281
  const d = String(date.getDate()).padStart(2, "0");
288
- return "".concat(y, "-").concat(m, "-").concat(d);
282
+ return `${y}-${m}-${d}`;
289
283
  };
290
284
  const getDateRange = option => {
291
285
  const today = new Date();
@@ -316,8 +310,8 @@ const AppointmentPage = _ref7 => {
316
310
  to = formatLocalDate(lastOfMonth);
317
311
  break;
318
312
  case "currentYear":
319
- from = "".concat(today.getFullYear(), "-01-01");
320
- to = "".concat(today.getFullYear(), "-12-31");
313
+ from = `${today.getFullYear()}-01-01`;
314
+ to = `${today.getFullYear()}-12-31`;
321
315
  break;
322
316
  default:
323
317
  from = to = getTodayDate();
@@ -342,7 +336,7 @@ const AppointmentPage = _ref7 => {
342
336
  case "currentYear":
343
337
  return "Current Year";
344
338
  case "custom":
345
- return isMobile ? "Custom" : "".concat(fromDate, " to ").concat(toDate);
339
+ return isMobile ? "Custom" : `${fromDate} to ${toDate}`;
346
340
  default:
347
341
  return "Today";
348
342
  }
@@ -427,12 +421,12 @@ const AppointmentPage = _ref7 => {
427
421
 
428
422
  // Helper to get unique identifier from appointment
429
423
  const getAppointmentId = appointment => {
430
- return (appointment === null || appointment === void 0 ? void 0 : appointment.id) || (appointment === null || appointment === void 0 ? void 0 : appointment._id) || (appointment === null || appointment === void 0 ? void 0 : appointment.appointmentId) || (appointment === null || appointment === void 0 ? void 0 : appointment.patientId) || JSON.stringify(appointment);
424
+ return appointment?.id || appointment?._id || appointment?.appointmentId || appointment?.patientId || JSON.stringify(appointment);
431
425
  };
432
426
 
433
427
  // Generate avatar with first letter if no image
434
428
  const getPatientAvatar = appointment => {
435
- if (appointment !== null && appointment !== void 0 && appointment.image) {
429
+ if (appointment?.image) {
436
430
  return appointment.image;
437
431
  }
438
432
  // Return null to use the letter avatar component
@@ -471,7 +465,12 @@ const AppointmentPage = _ref7 => {
471
465
  }
472
466
  };
473
467
  const fetchAppointments = (0, _react.useCallback)(async () => {
474
- if (!appToken) return;
468
+ console.log(appToken, 'fetchAppointments -> appToken');
469
+ if (!appToken) {
470
+ // No token available — force SSO re-login so the next render re-fetches automatically.
471
+ if (idToken && email) setRefreshLoginTrigger(t => t + 1);
472
+ return;
473
+ }
475
474
  console.log(doctorIdFromLogin, 'fetchAppointments -> doctorIdFromLogin');
476
475
  const doctorId = doctorIdFromLogin;
477
476
  setLoading(true);
@@ -517,7 +516,7 @@ const AppointmentPage = _ref7 => {
517
516
  } finally {
518
517
  setLoading(false);
519
518
  }
520
- }, [activeTab, fromDate, toDate, appointmentTypeFilter, apiBaseUrl, hospitalId, doctorIdFromLogin, appToken]);
519
+ }, [activeTab, fromDate, toDate, appointmentTypeFilter, apiBaseUrl, hospitalId, doctorIdFromLogin, appToken, idToken, email]);
521
520
 
522
521
  // Handle appointment selection - no API call, just show data from list
523
522
  const handleAppointmentSelect = appointment => {
@@ -551,7 +550,6 @@ const AppointmentPage = _ref7 => {
551
550
  setCallLoading(true);
552
551
  setCallError(null);
553
552
  try {
554
- var _response$data3;
555
553
  const callConfig = {
556
554
  apiBaseUrl,
557
555
  hospitalId,
@@ -579,7 +577,7 @@ const AppointmentPage = _ref7 => {
579
577
  setCallError("Session expired. Re-authenticating...");
580
578
  return;
581
579
  }
582
- if (response.err || !((_response$data3 = response.data) !== null && _response$data3 !== void 0 && _response$data3.token)) {
580
+ if (response.err || !response.data?.token) {
583
581
  setCallError(String(response.err || "Failed to initiate call"));
584
582
  return;
585
583
  }
@@ -798,6 +796,8 @@ const AppointmentPage = _ref7 => {
798
796
  }, [showPipVideo, isPipMinimized, isPipFullscreen, pipSize]);
799
797
 
800
798
  // Call login API only when we have no appToken (or got 401 / 403 and need refresh). Otherwise use stored appToken.
799
+ // appToken is intentionally included in deps: when the persist effect clears it (new idToken from Flutter after
800
+ // re-login), this effect re-evaluates needLogin with appToken=null and fires SSO for the new session.
801
801
  (0, _react.useEffect)(() => {
802
802
  const needLogin = idToken && email && (!appToken || refreshLoginTrigger > 0);
803
803
  if (!needLogin) return;
@@ -843,13 +843,18 @@ const AppointmentPage = _ref7 => {
843
843
  }
844
844
  } catch (e) {}
845
845
  }
846
- }).catch(() => {}).finally(() => {
846
+ }).catch(err => {
847
+ if (!cancelled) {
848
+ setTokenError(err?.message || "Authentication failed. Please try again.");
849
+ setAppToken(null);
850
+ }
851
+ }).finally(() => {
847
852
  if (!cancelled) setTokenLoading(false);
848
853
  });
849
854
  return () => {
850
855
  cancelled = true;
851
856
  };
852
- }, [apiBaseUrl, hospitalId, idToken, email, refreshLoginTrigger]);
857
+ }, [apiBaseUrl, hospitalId, idToken, email, refreshLoginTrigger, appToken]);
853
858
 
854
859
  // Reset page to 1 and clear call error when filters/tab change
855
860
  (0, _react.useEffect)(() => {
@@ -872,7 +877,32 @@ const AppointmentPage = _ref7 => {
872
877
 
873
878
  // Add responsive styles and animations
874
879
  const style = document.createElement("style");
875
- style.innerHTML = "\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n \n @media (max-width: 768px) {\n .appointments-grid {\n grid-template-columns: 1.5fr 1fr 0.8fr !important;\n }\n .appointments-header-grid {\n grid-template-columns: 1.5fr 1fr 0.8fr !important;\n }\n .hide-on-mobile {\n display: none !important;\n }\n }\n @media (max-width: 480px) {\n .appointments-header-grid {\n font-size: 10px !important;\n }\n .appointments-grid {\n font-size: 11px !important;\n }\n }\n ";
880
+ style.innerHTML = `
881
+ @keyframes spin {
882
+ 0% { transform: rotate(0deg); }
883
+ 100% { transform: rotate(360deg); }
884
+ }
885
+
886
+ @media (max-width: 768px) {
887
+ .appointments-grid {
888
+ grid-template-columns: 1.5fr 1fr 0.8fr !important;
889
+ }
890
+ .appointments-header-grid {
891
+ grid-template-columns: 1.5fr 1fr 0.8fr !important;
892
+ }
893
+ .hide-on-mobile {
894
+ display: none !important;
895
+ }
896
+ }
897
+ @media (max-width: 480px) {
898
+ .appointments-header-grid {
899
+ font-size: 10px !important;
900
+ }
901
+ .appointments-grid {
902
+ font-size: 11px !important;
903
+ }
904
+ }
905
+ `;
876
906
  document.head.appendChild(style);
877
907
 
878
908
  // Handle window resize
@@ -925,7 +955,7 @@ const AppointmentPage = _ref7 => {
925
955
  justifyContent: "center",
926
956
  padding: "24px"
927
957
  }
928
- }, /*#__PURE__*/_react.default.createElement("style", null, "@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }"), /*#__PURE__*/_react.default.createElement("div", {
958
+ }, /*#__PURE__*/_react.default.createElement("style", null, `@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`), /*#__PURE__*/_react.default.createElement("div", {
929
959
  style: {
930
960
  width: "40px",
931
961
  height: "40px",
@@ -1676,7 +1706,7 @@ const AppointmentPage = _ref7 => {
1676
1706
  style: {
1677
1707
  fontSize: "13px"
1678
1708
  }
1679
- }, searchQuery ? "No appointments found for \"".concat(searchQuery, "\"") : "No appointments found"), searchQuery && /*#__PURE__*/_react.default.createElement("button", {
1709
+ }, searchQuery ? `No appointments found for "${searchQuery}"` : "No appointments found"), searchQuery && /*#__PURE__*/_react.default.createElement("button", {
1680
1710
  onClick: () => setSearchQuery(""),
1681
1711
  style: {
1682
1712
  marginTop: "12px",
@@ -1955,7 +1985,7 @@ const AppointmentPage = _ref7 => {
1955
1985
  fontWeight: "700",
1956
1986
  fontSize: isMobile ? "12px" : "13px"
1957
1987
  }
1958
- }, (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.specialisation) || (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.speciality) || "N/A")), /*#__PURE__*/_react.default.createElement("div", {
1988
+ }, selectedAppointment?.specialisation || selectedAppointment?.speciality || "N/A")), /*#__PURE__*/_react.default.createElement("div", {
1959
1989
  style: {
1960
1990
  textAlign: "right"
1961
1991
  }
@@ -1970,7 +2000,7 @@ const AppointmentPage = _ref7 => {
1970
2000
  fontWeight: "700",
1971
2001
  fontSize: isMobile ? "12px" : "13px"
1972
2002
  }
1973
- }, (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.type) || (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.appointmentType) || "Online"))), /*#__PURE__*/_react.default.createElement("div", {
2003
+ }, selectedAppointment?.type || selectedAppointment?.appointmentType || "Online"))), /*#__PURE__*/_react.default.createElement("div", {
1974
2004
  style: {
1975
2005
  display: "flex",
1976
2006
  justifyContent: "space-between"
@@ -1990,7 +2020,7 @@ const AppointmentPage = _ref7 => {
1990
2020
  fontWeight: "700",
1991
2021
  fontSize: isMobile ? "12px" : "13px"
1992
2022
  }
1993
- }, (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.date) || (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.appointmentDate) || "N/A")), /*#__PURE__*/_react.default.createElement("div", {
2023
+ }, selectedAppointment?.date || selectedAppointment?.appointmentDate || "N/A")), /*#__PURE__*/_react.default.createElement("div", {
1994
2024
  style: {
1995
2025
  textAlign: "right"
1996
2026
  }
@@ -2005,7 +2035,7 @@ const AppointmentPage = _ref7 => {
2005
2035
  fontWeight: "700",
2006
2036
  fontSize: isMobile ? "12px" : "13px"
2007
2037
  }
2008
- }, (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.time) || (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.appointmentTime) || "N/A"))), /*#__PURE__*/_react.default.createElement("div", {
2038
+ }, selectedAppointment?.time || selectedAppointment?.appointmentTime || "N/A"))), /*#__PURE__*/_react.default.createElement("div", {
2009
2039
  style: {
2010
2040
  display: "flex",
2011
2041
  justifyContent: "space-between"
@@ -2025,7 +2055,7 @@ const AppointmentPage = _ref7 => {
2025
2055
  fontWeight: "700",
2026
2056
  fontSize: isMobile ? "12px" : "13px"
2027
2057
  }
2028
- }, (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.doctor) || (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.doctorName) || "N/A"))), /*#__PURE__*/_react.default.createElement("div", {
2058
+ }, selectedAppointment?.doctor || selectedAppointment?.doctorName || "N/A"))), /*#__PURE__*/_react.default.createElement("div", {
2029
2059
  style: {
2030
2060
  display: "flex",
2031
2061
  justifyContent: "space-between"
@@ -2045,7 +2075,7 @@ const AppointmentPage = _ref7 => {
2045
2075
  fontWeight: "700",
2046
2076
  fontSize: isMobile ? "12px" : "13px"
2047
2077
  }
2048
- }, (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.hospital) || (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.hospitalName) || "N/A"))), /*#__PURE__*/_react.default.createElement("div", {
2078
+ }, selectedAppointment?.hospital || selectedAppointment?.hospitalName || "N/A"))), /*#__PURE__*/_react.default.createElement("div", {
2049
2079
  style: {
2050
2080
  display: "flex",
2051
2081
  justifyContent: "space-between"
@@ -2066,7 +2096,7 @@ const AppointmentPage = _ref7 => {
2066
2096
  fontSize: isMobile ? "11px" : "12px",
2067
2097
  lineHeight: "1.4"
2068
2098
  }
2069
- }, (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.reason) || (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.reasonForAppointment) || "No reason provided"))), activeTab === "upcoming" && /*#__PURE__*/_react.default.createElement("div", {
2099
+ }, selectedAppointment?.reason || selectedAppointment?.reasonForAppointment || "No reason provided"))), activeTab === "upcoming" && /*#__PURE__*/_react.default.createElement("div", {
2070
2100
  style: {
2071
2101
  display: "flex",
2072
2102
  flexDirection: isMobile ? "column" : "row",
@@ -2119,12 +2149,12 @@ const AppointmentPage = _ref7 => {
2119
2149
  }, "Select an appointment to view details"))))))), showPipVideo && /*#__PURE__*/_react.default.createElement("div", {
2120
2150
  style: {
2121
2151
  position: "fixed",
2122
- left: isPipFullscreen ? "0" : isMobile ? "10px" : "".concat(pipPosition.x, "px"),
2123
- top: isPipFullscreen ? "0" : isMobile ? "70px" : "".concat(pipPosition.y, "px"),
2152
+ left: isPipFullscreen ? "0" : isMobile ? "10px" : `${pipPosition.x}px`,
2153
+ top: isPipFullscreen ? "0" : isMobile ? "70px" : `${pipPosition.y}px`,
2124
2154
  right: isPipFullscreen ? "0" : isMobile ? "10px" : "auto",
2125
2155
  bottom: isPipFullscreen ? "0" : "auto",
2126
- width: isPipFullscreen ? "100vw" : isMobile ? "calc(100vw - 20px)" : isPipMinimized ? "350px" : "".concat(pipSize.width, "px"),
2127
- height: isPipFullscreen ? "100vh" : isPipMinimized ? "auto" : isMobile ? "300px" : "".concat(pipSize.height, "px"),
2156
+ width: isPipFullscreen ? "100vw" : isMobile ? "calc(100vw - 20px)" : isPipMinimized ? "350px" : `${pipSize.width}px`,
2157
+ height: isPipFullscreen ? "100vh" : isPipMinimized ? "auto" : isMobile ? "300px" : `${pipSize.height}px`,
2128
2158
  background: "#FFFFFF",
2129
2159
  borderRadius: isPipFullscreen ? "0" : "8px",
2130
2160
  boxShadow: "0 8px 24px rgba(0, 0, 0, 0.3)",
@@ -2175,7 +2205,7 @@ const AppointmentPage = _ref7 => {
2175
2205
  textOverflow: "ellipsis",
2176
2206
  whiteSpace: "nowrap"
2177
2207
  }
2178
- }, "Video Call - ", (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.patientName) || "Patient")), /*#__PURE__*/_react.default.createElement("div", {
2208
+ }, "Video Call - ", selectedAppointment?.patientName || "Patient")), /*#__PURE__*/_react.default.createElement("div", {
2179
2209
  style: {
2180
2210
  display: "flex",
2181
2211
  gap: isMobile ? "4px" : "6px",
@@ -2304,7 +2334,7 @@ const AppointmentPage = _ref7 => {
2304
2334
  src: (() => {
2305
2335
  if (!callToken) return "";
2306
2336
  const base = String(joinCallUrlBase || "").replace(/\/?$/, "/");
2307
- return "".concat(base).concat(callToken);
2337
+ return `${base}${callToken}`;
2308
2338
  })(),
2309
2339
  style: {
2310
2340
  width: "100%",
@@ -2375,7 +2405,12 @@ const AppointmentPage = _ref7 => {
2375
2405
  background: "transparent",
2376
2406
  zIndex: 10001
2377
2407
  }
2378
- })), /*#__PURE__*/_react.default.createElement("style", null, "\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n "))), showAuthError && /*#__PURE__*/_react.default.createElement("div", {
2408
+ })), /*#__PURE__*/_react.default.createElement("style", null, `
2409
+ @keyframes pulse {
2410
+ 0%, 100% { opacity: 1; }
2411
+ 50% { opacity: 0.5; }
2412
+ }
2413
+ `))), showAuthError && /*#__PURE__*/_react.default.createElement("div", {
2379
2414
  style: {
2380
2415
  position: "fixed",
2381
2416
  inset: 0,