pih-appointment-widget 0.0.38 → 0.0.39

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
@@ -26,20 +26,21 @@ var _react = _interopRequireDefault(require("react"));
26
26
  var _reactDom = _interopRequireDefault(require("react-dom"));
27
27
  var _AppointmentPage = _interopRequireWildcard(require("./components/AppointmentPage.js"));
28
28
  var _ICD10Assistant = _interopRequireDefault(require("./components/ICD10Assistant.jsx"));
29
- 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); }
29
+ 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); }
30
+ 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; }
30
31
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
31
32
  let bookingWidgetInstance = null;
32
33
 
33
34
  // SDK for embedding appointment widget
34
35
  const BookingSDK = {
35
- /**
36
- * Show appointment widget with configuration
37
- * @param {object} config - Configuration object
38
- * @param {string} config.apiBaseUrl - Base URL for API
39
- * @param {string} config.hospitalId - Hospital ID
40
- * @param {number} config.doctorId - Doctor ID
41
- * @param {string} config.joinCallUrl - Video call URL
42
- * @param {function} onAction - Optional callback for actions
36
+ /**
37
+ * Show appointment widget with configuration
38
+ * @param {object} config - Configuration object
39
+ * @param {string} config.apiBaseUrl - Base URL for API
40
+ * @param {string} config.hospitalId - Hospital ID
41
+ * @param {number} config.doctorId - Doctor ID
42
+ * @param {string} config.joinCallUrl - Video call URL
43
+ * @param {function} onAction - Optional callback for actions
43
44
  */
44
45
  showWidget: (config, onAction) => {
45
46
  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,12 +162,14 @@ 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 re-login) — clear app token and force SSO for the new session.
174
- // refreshLoginTrigger increment guarantees SSO re-runs even if appToken was already null in state.
165
+ // New token from parent (e.g. Flutter re-login) — clear stored credentials.
166
+ // Only increment refreshLoginTrigger when there was an existing appToken to evict;
167
+ // if appToken is already absent, the SSO effect will fire naturally via !appToken.
168
+ const hadAppToken = !!localStorage.getItem(STORAGE_KEY_APP_TOKEN);
175
169
  setAppToken(null);
176
170
  setDoctorIdFromLogin(null);
177
171
  setUserName(null);
178
- setRefreshLoginTrigger(t => t + 1);
172
+ if (hadAppToken) setRefreshLoginTrigger(t => t + 1);
179
173
  localStorage.removeItem(STORAGE_KEY_APP_TOKEN);
180
174
  localStorage.removeItem(STORAGE_KEY_DOCTOR_ID);
181
175
  localStorage.removeItem(STORAGE_KEY_USER_NAME);
@@ -200,21 +194,21 @@ const AppointmentPage = _ref7 => {
200
194
  const [appToken, setAppToken] = (0, _react.useState)(() => {
201
195
  try {
202
196
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_APP_TOKEN) : null;
203
- } catch (_unused6) {
197
+ } catch {
204
198
  return null;
205
199
  }
206
200
  });
207
201
  const [doctorIdFromLogin, setDoctorIdFromLogin] = (0, _react.useState)(() => {
208
202
  try {
209
203
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_DOCTOR_ID) : null;
210
- } catch (_unused7) {
204
+ } catch {
211
205
  return null;
212
206
  }
213
207
  });
214
208
  const [userName, setUserName] = (0, _react.useState)(() => {
215
209
  try {
216
210
  return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_USER_NAME) : null;
217
- } catch (_unused8) {
211
+ } catch {
218
212
  return null;
219
213
  }
220
214
  });
@@ -225,7 +219,7 @@ const AppointmentPage = _ref7 => {
225
219
  const hasId = localStorage.getItem(STORAGE_KEY_ID_TOKEN);
226
220
  const hasEmail = localStorage.getItem(STORAGE_KEY_EMAIL);
227
221
  return !hasApp && !!(hasId && hasEmail);
228
- } catch (_unused9) {
222
+ } catch {
229
223
  return false;
230
224
  }
231
225
  });
@@ -287,7 +281,7 @@ const AppointmentPage = _ref7 => {
287
281
  const y = date.getFullYear();
288
282
  const m = String(date.getMonth() + 1).padStart(2, "0");
289
283
  const d = String(date.getDate()).padStart(2, "0");
290
- return "".concat(y, "-").concat(m, "-").concat(d);
284
+ return `${y}-${m}-${d}`;
291
285
  };
292
286
  const getDateRange = option => {
293
287
  const today = new Date();
@@ -318,8 +312,8 @@ const AppointmentPage = _ref7 => {
318
312
  to = formatLocalDate(lastOfMonth);
319
313
  break;
320
314
  case "currentYear":
321
- from = "".concat(today.getFullYear(), "-01-01");
322
- to = "".concat(today.getFullYear(), "-12-31");
315
+ from = `${today.getFullYear()}-01-01`;
316
+ to = `${today.getFullYear()}-12-31`;
323
317
  break;
324
318
  default:
325
319
  from = to = getTodayDate();
@@ -344,7 +338,7 @@ const AppointmentPage = _ref7 => {
344
338
  case "currentYear":
345
339
  return "Current Year";
346
340
  case "custom":
347
- return isMobile ? "Custom" : "".concat(fromDate, " to ").concat(toDate);
341
+ return isMobile ? "Custom" : `${fromDate} to ${toDate}`;
348
342
  default:
349
343
  return "Today";
350
344
  }
@@ -429,12 +423,12 @@ const AppointmentPage = _ref7 => {
429
423
 
430
424
  // Helper to get unique identifier from appointment
431
425
  const getAppointmentId = appointment => {
432
- 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);
426
+ return appointment?.id || appointment?._id || appointment?.appointmentId || appointment?.patientId || JSON.stringify(appointment);
433
427
  };
434
428
 
435
429
  // Generate avatar with first letter if no image
436
430
  const getPatientAvatar = appointment => {
437
- if (appointment !== null && appointment !== void 0 && appointment.image) {
431
+ if (appointment?.image) {
438
432
  return appointment.image;
439
433
  }
440
434
  // Return null to use the letter avatar component
@@ -555,8 +549,8 @@ const AppointmentPage = _ref7 => {
555
549
  // Returns true if the current time is within 2 hours after the appointment's scheduled slot time.
556
550
  // Handles date format: "Sun, 15 Mar 2026" and time format: "12:15 PM"
557
551
  const isWithinJoinWindow = appointment => {
558
- const dateStr = (appointment === null || appointment === void 0 ? void 0 : appointment.date) || (appointment === null || appointment === void 0 ? void 0 : appointment.appointmentDate);
559
- const timeStr = (appointment === null || appointment === void 0 ? void 0 : appointment.time) || (appointment === null || appointment === void 0 ? void 0 : appointment.appointmentTime);
552
+ const dateStr = appointment?.date || appointment?.appointmentDate;
553
+ const timeStr = appointment?.time || appointment?.appointmentTime;
560
554
  if (!dateStr || !timeStr) return false;
561
555
  try {
562
556
  // Parse "12:15 PM" or "9:30 AM" into 24-hour h/m values
@@ -576,11 +570,11 @@ const AppointmentPage = _ref7 => {
576
570
  }
577
571
  if (isNaN(h) || isNaN(m)) return false;
578
572
  // "Sun, 15 Mar 2026 12:15:00" — space-separated; JS parses RFC-like date strings correctly
579
- const appointmentDate = new Date("".concat(dateStr, " ").concat(String(h).padStart(2, "0"), ":").concat(String(m).padStart(2, "0"), ":00"));
573
+ const appointmentDate = new Date(`${dateStr} ${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:00`);
580
574
  if (isNaN(appointmentDate.getTime())) return false;
581
575
  const windowEnd = new Date(appointmentDate.getTime() + 2 * 60 * 60 * 1000);
582
576
  return new Date() <= windowEnd;
583
- } catch (_unused0) {
577
+ } catch {
584
578
  return false;
585
579
  }
586
580
  };
@@ -591,7 +585,6 @@ const AppointmentPage = _ref7 => {
591
585
  setCallLoading(true);
592
586
  setCallError(null);
593
587
  try {
594
- var _response$data3;
595
588
  const callConfig = {
596
589
  apiBaseUrl,
597
590
  hospitalId,
@@ -619,7 +612,7 @@ const AppointmentPage = _ref7 => {
619
612
  setCallError("Session expired. Re-authenticating...");
620
613
  return;
621
614
  }
622
- if (response.err || !((_response$data3 = response.data) !== null && _response$data3 !== void 0 && _response$data3.token)) {
615
+ if (response.err || !response.data?.token) {
623
616
  setCallError(String(response.err || "Failed to initiate call"));
624
617
  return;
625
618
  }
@@ -842,6 +835,7 @@ const AppointmentPage = _ref7 => {
842
835
  setAppToken(null);
843
836
  setDoctorIdFromLogin(null);
844
837
  setUserName(null);
838
+ setRefreshLoginTrigger(0); // reset trigger even on failure to prevent infinite retry loops
845
839
  try {
846
840
  if (typeof localStorage !== "undefined") {
847
841
  localStorage.removeItem(STORAGE_KEY_APP_TOKEN);
@@ -858,6 +852,7 @@ const AppointmentPage = _ref7 => {
858
852
  setUserName(name);
859
853
  setTokenError(null);
860
854
  setRedirectToHome(false);
855
+ setRefreshLoginTrigger(0); // reset one-shot trigger so SSO doesn't re-fire on next dep change
861
856
  try {
862
857
  if (typeof localStorage !== "undefined") {
863
858
  localStorage.setItem(STORAGE_KEY_APP_TOKEN, token);
@@ -868,7 +863,7 @@ const AppointmentPage = _ref7 => {
868
863
  }
869
864
  }).catch(err => {
870
865
  if (!cancelled) {
871
- setTokenError((err === null || err === void 0 ? void 0 : err.message) || "Authentication failed. Please try again.");
866
+ setTokenError(err?.message || "Authentication failed. Please try again.");
872
867
  setAppToken(null);
873
868
  }
874
869
  }).finally(() => {
@@ -900,7 +895,32 @@ const AppointmentPage = _ref7 => {
900
895
 
901
896
  // Add responsive styles and animations
902
897
  const style = document.createElement("style");
903
- 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 ";
898
+ style.innerHTML = `
899
+ @keyframes spin {
900
+ 0% { transform: rotate(0deg); }
901
+ 100% { transform: rotate(360deg); }
902
+ }
903
+
904
+ @media (max-width: 768px) {
905
+ .appointments-grid {
906
+ grid-template-columns: 1.5fr 1fr 0.8fr !important;
907
+ }
908
+ .appointments-header-grid {
909
+ grid-template-columns: 1.5fr 1fr 0.8fr !important;
910
+ }
911
+ .hide-on-mobile {
912
+ display: none !important;
913
+ }
914
+ }
915
+ @media (max-width: 480px) {
916
+ .appointments-header-grid {
917
+ font-size: 10px !important;
918
+ }
919
+ .appointments-grid {
920
+ font-size: 11px !important;
921
+ }
922
+ }
923
+ `;
904
924
  document.head.appendChild(style);
905
925
 
906
926
  // Handle window resize
@@ -953,7 +973,7 @@ const AppointmentPage = _ref7 => {
953
973
  justifyContent: "center",
954
974
  padding: "24px"
955
975
  }
956
- }, /*#__PURE__*/_react.default.createElement("style", null, "@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }"), /*#__PURE__*/_react.default.createElement("div", {
976
+ }, /*#__PURE__*/_react.default.createElement("style", null, `@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`), /*#__PURE__*/_react.default.createElement("div", {
957
977
  style: {
958
978
  width: "40px",
959
979
  height: "40px",
@@ -1712,7 +1732,7 @@ const AppointmentPage = _ref7 => {
1712
1732
  style: {
1713
1733
  fontSize: "13px"
1714
1734
  }
1715
- }, searchQuery ? "No appointments found for \"".concat(searchQuery, "\"") : "No appointments found"), searchQuery && /*#__PURE__*/_react.default.createElement("button", {
1735
+ }, searchQuery ? `No appointments found for "${searchQuery}"` : "No appointments found"), searchQuery && /*#__PURE__*/_react.default.createElement("button", {
1716
1736
  onClick: () => setSearchQuery(""),
1717
1737
  style: {
1718
1738
  marginTop: "12px",
@@ -1991,7 +2011,7 @@ const AppointmentPage = _ref7 => {
1991
2011
  fontWeight: "700",
1992
2012
  fontSize: isMobile ? "12px" : "13px"
1993
2013
  }
1994
- }, (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", {
2014
+ }, selectedAppointment?.specialisation || selectedAppointment?.speciality || "N/A")), /*#__PURE__*/_react.default.createElement("div", {
1995
2015
  style: {
1996
2016
  textAlign: "right"
1997
2017
  }
@@ -2006,7 +2026,7 @@ const AppointmentPage = _ref7 => {
2006
2026
  fontWeight: "700",
2007
2027
  fontSize: isMobile ? "12px" : "13px"
2008
2028
  }
2009
- }, (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.type) || (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.appointmentType) || "Online"))), /*#__PURE__*/_react.default.createElement("div", {
2029
+ }, selectedAppointment?.type || selectedAppointment?.appointmentType || "Online"))), /*#__PURE__*/_react.default.createElement("div", {
2010
2030
  style: {
2011
2031
  display: "flex",
2012
2032
  justifyContent: "space-between"
@@ -2026,7 +2046,7 @@ const AppointmentPage = _ref7 => {
2026
2046
  fontWeight: "700",
2027
2047
  fontSize: isMobile ? "12px" : "13px"
2028
2048
  }
2029
- }, (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", {
2049
+ }, selectedAppointment?.date || selectedAppointment?.appointmentDate || "N/A")), /*#__PURE__*/_react.default.createElement("div", {
2030
2050
  style: {
2031
2051
  textAlign: "right"
2032
2052
  }
@@ -2041,7 +2061,7 @@ const AppointmentPage = _ref7 => {
2041
2061
  fontWeight: "700",
2042
2062
  fontSize: isMobile ? "12px" : "13px"
2043
2063
  }
2044
- }, (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", {
2064
+ }, selectedAppointment?.time || selectedAppointment?.appointmentTime || "N/A"))), /*#__PURE__*/_react.default.createElement("div", {
2045
2065
  style: {
2046
2066
  display: "flex",
2047
2067
  justifyContent: "space-between"
@@ -2061,7 +2081,7 @@ const AppointmentPage = _ref7 => {
2061
2081
  fontWeight: "700",
2062
2082
  fontSize: isMobile ? "12px" : "13px"
2063
2083
  }
2064
- }, (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", {
2084
+ }, selectedAppointment?.doctor || selectedAppointment?.doctorName || "N/A"))), /*#__PURE__*/_react.default.createElement("div", {
2065
2085
  style: {
2066
2086
  display: "flex",
2067
2087
  justifyContent: "space-between"
@@ -2081,7 +2101,7 @@ const AppointmentPage = _ref7 => {
2081
2101
  fontWeight: "700",
2082
2102
  fontSize: isMobile ? "12px" : "13px"
2083
2103
  }
2084
- }, (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", {
2104
+ }, selectedAppointment?.hospital || selectedAppointment?.hospitalName || "N/A"))), /*#__PURE__*/_react.default.createElement("div", {
2085
2105
  style: {
2086
2106
  display: "flex",
2087
2107
  justifyContent: "space-between"
@@ -2102,7 +2122,7 @@ const AppointmentPage = _ref7 => {
2102
2122
  fontSize: isMobile ? "11px" : "12px",
2103
2123
  lineHeight: "1.4"
2104
2124
  }
2105
- }, (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.reason) || (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.reasonForAppointment) || "No reason provided"))), (activeTab === "upcoming" || activeTab === "completed" && isWithinJoinWindow(selectedAppointment)) && /*#__PURE__*/_react.default.createElement("div", {
2125
+ }, selectedAppointment?.reason || selectedAppointment?.reasonForAppointment || "No reason provided"))), (activeTab === "upcoming" || activeTab === "completed" && isWithinJoinWindow(selectedAppointment)) && /*#__PURE__*/_react.default.createElement("div", {
2106
2126
  style: {
2107
2127
  display: "flex",
2108
2128
  flexDirection: isMobile ? "column" : "row",
@@ -2155,12 +2175,12 @@ const AppointmentPage = _ref7 => {
2155
2175
  }, "Select an appointment to view details"))))))), showPipVideo && /*#__PURE__*/_react.default.createElement("div", {
2156
2176
  style: {
2157
2177
  position: "fixed",
2158
- left: isPipFullscreen ? "0" : isMobile ? "10px" : "".concat(pipPosition.x, "px"),
2159
- top: isPipFullscreen ? "0" : isMobile ? "70px" : "".concat(pipPosition.y, "px"),
2178
+ left: isPipFullscreen ? "0" : isMobile ? "10px" : `${pipPosition.x}px`,
2179
+ top: isPipFullscreen ? "0" : isMobile ? "70px" : `${pipPosition.y}px`,
2160
2180
  right: isPipFullscreen ? "0" : isMobile ? "10px" : "auto",
2161
2181
  bottom: isPipFullscreen ? "0" : "auto",
2162
- width: isPipFullscreen ? "100vw" : isMobile ? "calc(100vw - 20px)" : isPipMinimized ? "350px" : "".concat(pipSize.width, "px"),
2163
- height: isPipFullscreen ? "100vh" : isPipMinimized ? "auto" : isMobile ? "300px" : "".concat(pipSize.height, "px"),
2182
+ width: isPipFullscreen ? "100vw" : isMobile ? "calc(100vw - 20px)" : isPipMinimized ? "350px" : `${pipSize.width}px`,
2183
+ height: isPipFullscreen ? "100vh" : isPipMinimized ? "auto" : isMobile ? "300px" : `${pipSize.height}px`,
2164
2184
  background: "#FFFFFF",
2165
2185
  borderRadius: isPipFullscreen ? "0" : "8px",
2166
2186
  boxShadow: "0 8px 24px rgba(0, 0, 0, 0.3)",
@@ -2211,7 +2231,7 @@ const AppointmentPage = _ref7 => {
2211
2231
  textOverflow: "ellipsis",
2212
2232
  whiteSpace: "nowrap"
2213
2233
  }
2214
- }, "Video Call - ", (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.patientName) || "Patient")), /*#__PURE__*/_react.default.createElement("div", {
2234
+ }, "Video Call - ", selectedAppointment?.patientName || "Patient")), /*#__PURE__*/_react.default.createElement("div", {
2215
2235
  style: {
2216
2236
  display: "flex",
2217
2237
  gap: isMobile ? "4px" : "6px",
@@ -2340,7 +2360,7 @@ const AppointmentPage = _ref7 => {
2340
2360
  src: (() => {
2341
2361
  if (!callToken) return "";
2342
2362
  const base = String(joinCallUrlBase || "");
2343
- return "".concat(base).concat(callToken);
2363
+ return `${base}${callToken}`;
2344
2364
  })(),
2345
2365
  style: {
2346
2366
  width: "100%",
@@ -2411,7 +2431,12 @@ const AppointmentPage = _ref7 => {
2411
2431
  background: "transparent",
2412
2432
  zIndex: 10001
2413
2433
  }
2414
- })), /*#__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", {
2434
+ })), /*#__PURE__*/_react.default.createElement("style", null, `
2435
+ @keyframes pulse {
2436
+ 0%, 100% { opacity: 1; }
2437
+ 50% { opacity: 0.5; }
2438
+ }
2439
+ `))), showAuthError && /*#__PURE__*/_react.default.createElement("div", {
2415
2440
  style: {
2416
2441
  position: "fixed",
2417
2442
  inset: 0,