pih-appointment-widget 0.0.37 → 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 +70 -70
- package/babel.config.js +5 -5
- package/dist/App.js +10 -9
- package/dist/assets/icons/icdIcons.js +30 -0
- package/dist/components/AppointmentPage.js +87 -62
- package/dist/components/ICD10Assistant.js +144 -63
- package/dist/doctor-appointments-widget.umd.js +115 -119
- package/dist/doctor-appointments-widget.umd.min.js +1 -1
- package/dist/hooks/useClipboard.js +3 -3
- package/dist/pih-appointment-widget.umd.js +309 -208
- package/dist/pih-appointment-widget.umd.min.js +1 -1
- package/dist/services/appointmentService.js +20 -20
- package/dist/services/httpService.js +14 -18
- package/dist/services/icdService.js +21 -23
- package/package.json +67 -67
- package/public/index.html +43 -43
- package/public/manifest.json +25 -25
- package/public/robots.txt +3 -3
- package/rollup.config.js +43 -43
- package/src/App.js +50 -50
- package/src/Example.js +14 -14
- package/src/assets/icons/icdIcon.png +0 -0
- package/src/assets/icons/icdIcons.js +23 -0
- package/src/components/AppointmentPage.js +2502 -2498
- package/src/components/ICD10Assistant.jsx +923 -855
- package/src/constants/apiConfig.js +29 -29
- package/src/hooks/useClipboard.js +35 -35
- package/src/index.js +6 -6
- package/src/services/appointmentService.js +92 -92
- package/src/services/httpService.js +103 -103
- package/src/services/icdService.js +76 -76
|
@@ -9,29 +9,6 @@
|
|
|
9
9
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
10
10
|
var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
|
|
11
11
|
|
|
12
|
-
function _defineProperty(e, r, t) {
|
|
13
|
-
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
14
|
-
value: t,
|
|
15
|
-
enumerable: !0,
|
|
16
|
-
configurable: !0,
|
|
17
|
-
writable: !0
|
|
18
|
-
}) : e[r] = t, e;
|
|
19
|
-
}
|
|
20
|
-
function _toPrimitive(t, r) {
|
|
21
|
-
if ("object" != typeof t || !t) return t;
|
|
22
|
-
var e = t[Symbol.toPrimitive];
|
|
23
|
-
if (void 0 !== e) {
|
|
24
|
-
var i = e.call(t, r || "default");
|
|
25
|
-
if ("object" != typeof i) return i;
|
|
26
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
27
|
-
}
|
|
28
|
-
return ("string" === r ? String : Number)(t);
|
|
29
|
-
}
|
|
30
|
-
function _toPropertyKey(t) {
|
|
31
|
-
var i = _toPrimitive(t, "string");
|
|
32
|
-
return "symbol" == typeof i ? i : i + "";
|
|
33
|
-
}
|
|
34
|
-
|
|
35
12
|
const getApi = async function (url) {
|
|
36
13
|
let params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
37
14
|
let token = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';
|
|
@@ -41,16 +18,15 @@
|
|
|
41
18
|
method: "GET",
|
|
42
19
|
headers: {
|
|
43
20
|
"Content-Type": "application/json",
|
|
44
|
-
"Authorization":
|
|
21
|
+
"Authorization": `${token}`
|
|
45
22
|
// "X-CLIENT-APP": header,
|
|
46
23
|
}
|
|
47
24
|
};
|
|
48
25
|
return fetch(urlWithParams, options).then(async response => {
|
|
49
26
|
const data = await response.json().catch(() => ({}));
|
|
50
27
|
if (!response.ok) {
|
|
51
|
-
var _data$resultInfo;
|
|
52
28
|
return {
|
|
53
|
-
err:
|
|
29
|
+
err: data?.resultInfo?.message || "Something went wrong!",
|
|
54
30
|
status: response.status
|
|
55
31
|
};
|
|
56
32
|
}
|
|
@@ -58,7 +34,7 @@
|
|
|
58
34
|
}).catch(error => {
|
|
59
35
|
console.error("Fetch error:", error);
|
|
60
36
|
return {
|
|
61
|
-
err:
|
|
37
|
+
err: error?.message || String(error) || "Network error"
|
|
62
38
|
};
|
|
63
39
|
});
|
|
64
40
|
};
|
|
@@ -82,9 +58,8 @@
|
|
|
82
58
|
return fetch(urlWithParams.toString(), options).then(async response => {
|
|
83
59
|
const data = await response.json().catch(() => ({}));
|
|
84
60
|
if (!response.ok) {
|
|
85
|
-
var _data$resultInfo2;
|
|
86
61
|
return {
|
|
87
|
-
err:
|
|
62
|
+
err: data?.resultInfo?.message || "Something went wrong!",
|
|
88
63
|
status: response.status
|
|
89
64
|
};
|
|
90
65
|
}
|
|
@@ -97,17 +72,17 @@
|
|
|
97
72
|
});
|
|
98
73
|
};
|
|
99
74
|
|
|
100
|
-
/**
|
|
101
|
-
* SSO login: exchange idToken + email for app token.
|
|
102
|
-
* @param {string} apiBaseUrl - e.g. https://afiyaapiqa.powermindinc.com
|
|
103
|
-
* @param {string} hospitalId - e.g. dMtEGhak
|
|
104
|
-
* @param {string} idToken - JWT id token from auth provider
|
|
105
|
-
* @param {string} email - User email
|
|
106
|
-
* @returns {Promise<{ token?: string, err?: string, ... }>} - Response with token on success, or { err } on failure
|
|
75
|
+
/**
|
|
76
|
+
* SSO login: exchange idToken + email for app token.
|
|
77
|
+
* @param {string} apiBaseUrl - e.g. https://afiyaapiqa.powermindinc.com
|
|
78
|
+
* @param {string} hospitalId - e.g. dMtEGhak
|
|
79
|
+
* @param {string} idToken - JWT id token from auth provider
|
|
80
|
+
* @param {string} email - User email
|
|
81
|
+
* @returns {Promise<{ token?: string, err?: string, ... }>} - Response with token on success, or { err } on failure
|
|
107
82
|
*/
|
|
108
83
|
const getTokenFromSso = async (apiBaseUrl, hospitalId, idToken, email) => {
|
|
109
84
|
const base = apiBaseUrl.replace(/\/$/, "");
|
|
110
|
-
const url =
|
|
85
|
+
const url = `${base}/um/user/V1/sso/login?hospitalId=${encodeURIComponent(hospitalId)}`;
|
|
111
86
|
const options = {
|
|
112
87
|
method: "POST",
|
|
113
88
|
headers: {
|
|
@@ -129,8 +104,7 @@
|
|
|
129
104
|
console.log("[getTokenFromSso] response status", response.status, response.statusText);
|
|
130
105
|
if (!response.ok) {
|
|
131
106
|
return response.json().then(errorData => {
|
|
132
|
-
|
|
133
|
-
const errorMessage = (errorData === null || errorData === void 0 || (_errorData$resultInfo = errorData.resultInfo) === null || _errorData$resultInfo === void 0 ? void 0 : _errorData$resultInfo.message) || "SSO login failed";
|
|
107
|
+
const errorMessage = errorData?.resultInfo?.message || "SSO login failed";
|
|
134
108
|
console.log("[getTokenFromSso] error body", errorData);
|
|
135
109
|
return {
|
|
136
110
|
err: errorMessage,
|
|
@@ -142,11 +116,10 @@
|
|
|
142
116
|
}));
|
|
143
117
|
}
|
|
144
118
|
return response.json().then(data => {
|
|
145
|
-
var _data$data;
|
|
146
119
|
console.log("[getTokenFromSso] success", {
|
|
147
120
|
hasData: !!data,
|
|
148
121
|
dataKeys: data ? Object.keys(data) : [],
|
|
149
|
-
hasAccessToken: !!
|
|
122
|
+
hasAccessToken: !!data?.data?.access_token
|
|
150
123
|
});
|
|
151
124
|
return data;
|
|
152
125
|
});
|
|
@@ -178,13 +151,13 @@
|
|
|
178
151
|
const JOIN_CALL_URL = "https://ittisal.powermindinc.com/call?token=";
|
|
179
152
|
const WEB_URL = "https://afiyapro.powermindinc.com/";
|
|
180
153
|
|
|
181
|
-
/**
|
|
182
|
-
* Fetch appointments by status
|
|
183
|
-
* @param {string} status - Appointment status (inprogress, completed, cancelled, upcoming)
|
|
184
|
-
* @param {string} fromDate - Start date in YYYY-MM-DD format
|
|
185
|
-
* @param {string} toDate - End date in YYYY-MM-DD format
|
|
186
|
-
* @param {object} config - Optional configuration { apiBaseUrl, hospitalId, doctorId }
|
|
187
|
-
* @returns {Promise} Appointments data
|
|
154
|
+
/**
|
|
155
|
+
* Fetch appointments by status
|
|
156
|
+
* @param {string} status - Appointment status (inprogress, completed, cancelled, upcoming)
|
|
157
|
+
* @param {string} fromDate - Start date in YYYY-MM-DD format
|
|
158
|
+
* @param {string} toDate - End date in YYYY-MM-DD format
|
|
159
|
+
* @param {object} config - Optional configuration { apiBaseUrl, hospitalId, doctorId }
|
|
160
|
+
* @returns {Promise} Appointments data
|
|
188
161
|
*/
|
|
189
162
|
const getAppointmentsByStatus = async function (status, fromDate, toDate) {
|
|
190
163
|
let config = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
@@ -211,24 +184,24 @@
|
|
|
211
184
|
// params.appointmentType = String(type).toUpperCase();
|
|
212
185
|
// }
|
|
213
186
|
params.appointmentType = 'ONLINE';
|
|
214
|
-
const url =
|
|
187
|
+
const url = `${baseURL}${API_PATHS.APPOINTMENTS}`;
|
|
215
188
|
|
|
216
189
|
// Return raw response (including status) so caller can detect 401 and re-login
|
|
217
190
|
const response = await getApi(url, params, "PIH-Appointment-Widget", token);
|
|
218
191
|
return response;
|
|
219
192
|
};
|
|
220
193
|
|
|
221
|
-
/**
|
|
222
|
-
* Initiate an online consultation — returns LiveKit room token + wss URL.
|
|
223
|
-
* @param {object} appointment - Selected appointment object
|
|
224
|
-
* @param {object} config - { apiBaseUrl, hospitalId, doctorId, doctorName, appToken }
|
|
225
|
-
* @returns {Promise<{ data: { token, url, roomName, participantName }, err?, status? }>}
|
|
194
|
+
/**
|
|
195
|
+
* Initiate an online consultation — returns LiveKit room token + wss URL.
|
|
196
|
+
* @param {object} appointment - Selected appointment object
|
|
197
|
+
* @param {object} config - { apiBaseUrl, hospitalId, doctorId, doctorName, appToken }
|
|
198
|
+
* @returns {Promise<{ data: { token, url, roomName, participantName }, err?, status? }>}
|
|
226
199
|
*/
|
|
227
200
|
const initiateConsultation = async function (appointment) {
|
|
228
201
|
let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
229
202
|
console.log("initiateConsultation -> config", config);
|
|
230
203
|
const baseURL = config.apiBaseUrl.replace(/\/$/, "");
|
|
231
|
-
const url =
|
|
204
|
+
const url = `${baseURL}${API_PATHS.INITIATE_CALL}`;
|
|
232
205
|
const appToken = config.appToken || "";
|
|
233
206
|
const body = {
|
|
234
207
|
patientId: String(appointment.patientId || ""),
|
|
@@ -251,7 +224,7 @@
|
|
|
251
224
|
const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
252
225
|
const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
|
|
253
226
|
return JSON.parse(atob(padded));
|
|
254
|
-
} catch
|
|
227
|
+
} catch {
|
|
255
228
|
return {};
|
|
256
229
|
}
|
|
257
230
|
}
|
|
@@ -271,32 +244,26 @@
|
|
|
271
244
|
|
|
272
245
|
// Extract from SSO login response (not from appToken JWT — these are only in login response)
|
|
273
246
|
function extractAppToken(response) {
|
|
274
|
-
var _ref, _ref2, _ref3, _response$data$access, _response$data, _response$data2;
|
|
275
247
|
if (!response || response.err) return null;
|
|
276
|
-
return
|
|
248
|
+
return response.data?.access_token ?? response.data?.token ?? response.token ?? response.accessToken ?? null;
|
|
277
249
|
}
|
|
278
250
|
function extractDoctorIdFromLoginResponse(response) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
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;
|
|
251
|
+
if (!response?.data) return null;
|
|
252
|
+
const id = response.data.doctor_id ?? response.data.doctorId ?? null;
|
|
282
253
|
console.log(id, 'extractDoctorIdFromLoginResponse -> id');
|
|
283
254
|
return id != null ? String(id) : null;
|
|
284
255
|
}
|
|
285
256
|
function extractUserNameFromLoginResponse(response) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
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;
|
|
257
|
+
if (!response?.data) return null;
|
|
258
|
+
const name = response.data.name ?? response.data.doctor_name ?? response.data.userName ?? null;
|
|
289
259
|
return name != null ? String(name) : null;
|
|
290
260
|
}
|
|
291
261
|
|
|
292
262
|
// Error boundary so a render error never shows a blank screen
|
|
293
263
|
class AppointmentErrorBoundary extends React.Component {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
hasError: false
|
|
298
|
-
});
|
|
299
|
-
}
|
|
264
|
+
state = {
|
|
265
|
+
hasError: false
|
|
266
|
+
};
|
|
300
267
|
static getDerivedStateFromError() {
|
|
301
268
|
return {
|
|
302
269
|
hasError: true
|
|
@@ -353,21 +320,21 @@
|
|
|
353
320
|
}
|
|
354
321
|
|
|
355
322
|
// SDK Component - accepts configuration from parent app
|
|
356
|
-
const AppointmentPage =
|
|
323
|
+
const AppointmentPage = _ref => {
|
|
357
324
|
let {
|
|
358
325
|
config = {}
|
|
359
|
-
} =
|
|
326
|
+
} = _ref;
|
|
360
327
|
const [storedApiBaseUrl, setStoredApiBaseUrl] = React.useState(() => {
|
|
361
328
|
try {
|
|
362
329
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_API_BASE_URL) : null;
|
|
363
|
-
} catch
|
|
330
|
+
} catch {
|
|
364
331
|
return null;
|
|
365
332
|
}
|
|
366
333
|
});
|
|
367
334
|
const [storedHospitalId, setStoredHospitalId] = React.useState(() => {
|
|
368
335
|
try {
|
|
369
336
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_HOSPITAL_ID) : null;
|
|
370
|
-
} catch
|
|
337
|
+
} catch {
|
|
371
338
|
return null;
|
|
372
339
|
}
|
|
373
340
|
});
|
|
@@ -378,14 +345,14 @@
|
|
|
378
345
|
const [storedIdToken, setStoredIdToken] = React.useState(() => {
|
|
379
346
|
try {
|
|
380
347
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_ID_TOKEN) : null;
|
|
381
|
-
} catch
|
|
348
|
+
} catch {
|
|
382
349
|
return null;
|
|
383
350
|
}
|
|
384
351
|
});
|
|
385
352
|
const [storedEmail, setStoredEmail] = React.useState(() => {
|
|
386
353
|
try {
|
|
387
354
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_EMAIL) : null;
|
|
388
|
-
} catch
|
|
355
|
+
} catch {
|
|
389
356
|
return null;
|
|
390
357
|
}
|
|
391
358
|
});
|
|
@@ -430,21 +397,21 @@
|
|
|
430
397
|
const [appToken, setAppToken] = React.useState(() => {
|
|
431
398
|
try {
|
|
432
399
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_APP_TOKEN) : null;
|
|
433
|
-
} catch
|
|
400
|
+
} catch {
|
|
434
401
|
return null;
|
|
435
402
|
}
|
|
436
403
|
});
|
|
437
404
|
const [doctorIdFromLogin, setDoctorIdFromLogin] = React.useState(() => {
|
|
438
405
|
try {
|
|
439
406
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_DOCTOR_ID) : null;
|
|
440
|
-
} catch
|
|
407
|
+
} catch {
|
|
441
408
|
return null;
|
|
442
409
|
}
|
|
443
410
|
});
|
|
444
411
|
const [userName, setUserName] = React.useState(() => {
|
|
445
412
|
try {
|
|
446
413
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_USER_NAME) : null;
|
|
447
|
-
} catch
|
|
414
|
+
} catch {
|
|
448
415
|
return null;
|
|
449
416
|
}
|
|
450
417
|
});
|
|
@@ -455,7 +422,7 @@
|
|
|
455
422
|
const hasId = localStorage.getItem(STORAGE_KEY_ID_TOKEN);
|
|
456
423
|
const hasEmail = localStorage.getItem(STORAGE_KEY_EMAIL);
|
|
457
424
|
return !hasApp && !!(hasId && hasEmail);
|
|
458
|
-
} catch
|
|
425
|
+
} catch {
|
|
459
426
|
return false;
|
|
460
427
|
}
|
|
461
428
|
});
|
|
@@ -517,7 +484,7 @@
|
|
|
517
484
|
const y = date.getFullYear();
|
|
518
485
|
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
519
486
|
const d = String(date.getDate()).padStart(2, "0");
|
|
520
|
-
return
|
|
487
|
+
return `${y}-${m}-${d}`;
|
|
521
488
|
};
|
|
522
489
|
const getDateRange = option => {
|
|
523
490
|
const today = new Date();
|
|
@@ -548,8 +515,8 @@
|
|
|
548
515
|
to = formatLocalDate(lastOfMonth);
|
|
549
516
|
break;
|
|
550
517
|
case "currentYear":
|
|
551
|
-
from =
|
|
552
|
-
to =
|
|
518
|
+
from = `${today.getFullYear()}-01-01`;
|
|
519
|
+
to = `${today.getFullYear()}-12-31`;
|
|
553
520
|
break;
|
|
554
521
|
default:
|
|
555
522
|
from = to = getTodayDate();
|
|
@@ -574,7 +541,7 @@
|
|
|
574
541
|
case "currentYear":
|
|
575
542
|
return "Current Year";
|
|
576
543
|
case "custom":
|
|
577
|
-
return isMobile ? "Custom" :
|
|
544
|
+
return isMobile ? "Custom" : `${fromDate} to ${toDate}`;
|
|
578
545
|
default:
|
|
579
546
|
return "Today";
|
|
580
547
|
}
|
|
@@ -659,12 +626,12 @@
|
|
|
659
626
|
|
|
660
627
|
// Helper to get unique identifier from appointment
|
|
661
628
|
const getAppointmentId = appointment => {
|
|
662
|
-
return
|
|
629
|
+
return appointment?.id || appointment?._id || appointment?.appointmentId || appointment?.patientId || JSON.stringify(appointment);
|
|
663
630
|
};
|
|
664
631
|
|
|
665
632
|
// Generate avatar with first letter if no image
|
|
666
633
|
const getPatientAvatar = appointment => {
|
|
667
|
-
if (appointment
|
|
634
|
+
if (appointment?.image) {
|
|
668
635
|
return appointment.image;
|
|
669
636
|
}
|
|
670
637
|
// Return null to use the letter avatar component
|
|
@@ -703,7 +670,7 @@
|
|
|
703
670
|
}
|
|
704
671
|
};
|
|
705
672
|
const fetchAppointments = React.useCallback(async () => {
|
|
706
|
-
console.log(appToken, '
|
|
673
|
+
console.log(appToken, 'fetchAppointmentsProd -> appToken');
|
|
707
674
|
if (!appToken) {
|
|
708
675
|
// No token available — force SSO re-login so the next render re-fetches automatically.
|
|
709
676
|
if (idToken && email) setRefreshLoginTrigger(t => t + 1);
|
|
@@ -765,8 +732,8 @@
|
|
|
765
732
|
// Returns true if the current time is within 2 hours after the appointment's scheduled slot time.
|
|
766
733
|
// Handles date format: "Sun, 15 Mar 2026" and time format: "12:15 PM"
|
|
767
734
|
const isWithinJoinWindow = appointment => {
|
|
768
|
-
const dateStr =
|
|
769
|
-
const timeStr =
|
|
735
|
+
const dateStr = appointment?.date || appointment?.appointmentDate;
|
|
736
|
+
const timeStr = appointment?.time || appointment?.appointmentTime;
|
|
770
737
|
if (!dateStr || !timeStr) return false;
|
|
771
738
|
try {
|
|
772
739
|
// Parse "12:15 PM" or "9:30 AM" into 24-hour h/m values
|
|
@@ -786,11 +753,11 @@
|
|
|
786
753
|
}
|
|
787
754
|
if (isNaN(h) || isNaN(m)) return false;
|
|
788
755
|
// "Sun, 15 Mar 2026 12:15:00" — space-separated; JS parses RFC-like date strings correctly
|
|
789
|
-
const appointmentDate = new Date(
|
|
756
|
+
const appointmentDate = new Date(`${dateStr} ${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:00`);
|
|
790
757
|
if (isNaN(appointmentDate.getTime())) return false;
|
|
791
758
|
const windowEnd = new Date(appointmentDate.getTime() + 2 * 60 * 60 * 1000);
|
|
792
759
|
return new Date() <= windowEnd;
|
|
793
|
-
} catch
|
|
760
|
+
} catch {
|
|
794
761
|
return false;
|
|
795
762
|
}
|
|
796
763
|
};
|
|
@@ -801,7 +768,6 @@
|
|
|
801
768
|
setCallLoading(true);
|
|
802
769
|
setCallError(null);
|
|
803
770
|
try {
|
|
804
|
-
var _response$data3;
|
|
805
771
|
const callConfig = {
|
|
806
772
|
apiBaseUrl,
|
|
807
773
|
hospitalId,
|
|
@@ -829,7 +795,7 @@
|
|
|
829
795
|
setCallError("Session expired. Re-authenticating...");
|
|
830
796
|
return;
|
|
831
797
|
}
|
|
832
|
-
if (response.err || !
|
|
798
|
+
if (response.err || !response.data?.token) {
|
|
833
799
|
setCallError(String(response.err || "Failed to initiate call"));
|
|
834
800
|
return;
|
|
835
801
|
}
|
|
@@ -1078,7 +1044,7 @@
|
|
|
1078
1044
|
}
|
|
1079
1045
|
}).catch(err => {
|
|
1080
1046
|
if (!cancelled) {
|
|
1081
|
-
setTokenError(
|
|
1047
|
+
setTokenError(err?.message || "Authentication failed. Please try again.");
|
|
1082
1048
|
setAppToken(null);
|
|
1083
1049
|
}
|
|
1084
1050
|
}).finally(() => {
|
|
@@ -1110,7 +1076,32 @@
|
|
|
1110
1076
|
|
|
1111
1077
|
// Add responsive styles and animations
|
|
1112
1078
|
const style = document.createElement("style");
|
|
1113
|
-
style.innerHTML =
|
|
1079
|
+
style.innerHTML = `
|
|
1080
|
+
@keyframes spin {
|
|
1081
|
+
0% { transform: rotate(0deg); }
|
|
1082
|
+
100% { transform: rotate(360deg); }
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
@media (max-width: 768px) {
|
|
1086
|
+
.appointments-grid {
|
|
1087
|
+
grid-template-columns: 1.5fr 1fr 0.8fr !important;
|
|
1088
|
+
}
|
|
1089
|
+
.appointments-header-grid {
|
|
1090
|
+
grid-template-columns: 1.5fr 1fr 0.8fr !important;
|
|
1091
|
+
}
|
|
1092
|
+
.hide-on-mobile {
|
|
1093
|
+
display: none !important;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
@media (max-width: 480px) {
|
|
1097
|
+
.appointments-header-grid {
|
|
1098
|
+
font-size: 10px !important;
|
|
1099
|
+
}
|
|
1100
|
+
.appointments-grid {
|
|
1101
|
+
font-size: 11px !important;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
`;
|
|
1114
1105
|
document.head.appendChild(style);
|
|
1115
1106
|
|
|
1116
1107
|
// Handle window resize
|
|
@@ -1162,7 +1153,7 @@
|
|
|
1162
1153
|
justifyContent: "center",
|
|
1163
1154
|
padding: "24px"
|
|
1164
1155
|
}
|
|
1165
|
-
}, /*#__PURE__*/React__default["default"].createElement("style", null,
|
|
1156
|
+
}, /*#__PURE__*/React__default["default"].createElement("style", null, `@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`), /*#__PURE__*/React__default["default"].createElement("div", {
|
|
1166
1157
|
style: {
|
|
1167
1158
|
width: "40px",
|
|
1168
1159
|
height: "40px",
|
|
@@ -1775,7 +1766,7 @@
|
|
|
1775
1766
|
style: {
|
|
1776
1767
|
fontSize: "13px"
|
|
1777
1768
|
}
|
|
1778
|
-
}, searchQuery ?
|
|
1769
|
+
}, searchQuery ? `No appointments found for "${searchQuery}"` : "No appointments found"), searchQuery && /*#__PURE__*/React__default["default"].createElement("button", {
|
|
1779
1770
|
onClick: () => setSearchQuery(""),
|
|
1780
1771
|
style: {
|
|
1781
1772
|
marginTop: "12px",
|
|
@@ -2054,7 +2045,7 @@
|
|
|
2054
2045
|
fontWeight: "700",
|
|
2055
2046
|
fontSize: isMobile ? "12px" : "13px"
|
|
2056
2047
|
}
|
|
2057
|
-
},
|
|
2048
|
+
}, selectedAppointment?.specialisation || selectedAppointment?.speciality || "N/A")), /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2058
2049
|
style: {
|
|
2059
2050
|
textAlign: "right"
|
|
2060
2051
|
}
|
|
@@ -2069,7 +2060,7 @@
|
|
|
2069
2060
|
fontWeight: "700",
|
|
2070
2061
|
fontSize: isMobile ? "12px" : "13px"
|
|
2071
2062
|
}
|
|
2072
|
-
},
|
|
2063
|
+
}, selectedAppointment?.type || selectedAppointment?.appointmentType || "Online"))), /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2073
2064
|
style: {
|
|
2074
2065
|
display: "flex",
|
|
2075
2066
|
justifyContent: "space-between"
|
|
@@ -2089,7 +2080,7 @@
|
|
|
2089
2080
|
fontWeight: "700",
|
|
2090
2081
|
fontSize: isMobile ? "12px" : "13px"
|
|
2091
2082
|
}
|
|
2092
|
-
},
|
|
2083
|
+
}, selectedAppointment?.date || selectedAppointment?.appointmentDate || "N/A")), /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2093
2084
|
style: {
|
|
2094
2085
|
textAlign: "right"
|
|
2095
2086
|
}
|
|
@@ -2104,7 +2095,7 @@
|
|
|
2104
2095
|
fontWeight: "700",
|
|
2105
2096
|
fontSize: isMobile ? "12px" : "13px"
|
|
2106
2097
|
}
|
|
2107
|
-
},
|
|
2098
|
+
}, selectedAppointment?.time || selectedAppointment?.appointmentTime || "N/A"))), /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2108
2099
|
style: {
|
|
2109
2100
|
display: "flex",
|
|
2110
2101
|
justifyContent: "space-between"
|
|
@@ -2124,7 +2115,7 @@
|
|
|
2124
2115
|
fontWeight: "700",
|
|
2125
2116
|
fontSize: isMobile ? "12px" : "13px"
|
|
2126
2117
|
}
|
|
2127
|
-
},
|
|
2118
|
+
}, selectedAppointment?.doctor || selectedAppointment?.doctorName || "N/A"))), /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2128
2119
|
style: {
|
|
2129
2120
|
display: "flex",
|
|
2130
2121
|
justifyContent: "space-between"
|
|
@@ -2144,7 +2135,7 @@
|
|
|
2144
2135
|
fontWeight: "700",
|
|
2145
2136
|
fontSize: isMobile ? "12px" : "13px"
|
|
2146
2137
|
}
|
|
2147
|
-
},
|
|
2138
|
+
}, selectedAppointment?.hospital || selectedAppointment?.hospitalName || "N/A"))), /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2148
2139
|
style: {
|
|
2149
2140
|
display: "flex",
|
|
2150
2141
|
justifyContent: "space-between"
|
|
@@ -2165,7 +2156,7 @@
|
|
|
2165
2156
|
fontSize: isMobile ? "11px" : "12px",
|
|
2166
2157
|
lineHeight: "1.4"
|
|
2167
2158
|
}
|
|
2168
|
-
},
|
|
2159
|
+
}, selectedAppointment?.reason || selectedAppointment?.reasonForAppointment || "No reason provided"))), (activeTab === "upcoming" || activeTab === "completed" && isWithinJoinWindow(selectedAppointment)) && /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2169
2160
|
style: {
|
|
2170
2161
|
display: "flex",
|
|
2171
2162
|
flexDirection: isMobile ? "column" : "row",
|
|
@@ -2218,12 +2209,12 @@
|
|
|
2218
2209
|
}, "Select an appointment to view details"))))))), showPipVideo && /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2219
2210
|
style: {
|
|
2220
2211
|
position: "fixed",
|
|
2221
|
-
left: isPipFullscreen ? "0" : isMobile ? "10px" :
|
|
2222
|
-
top: isPipFullscreen ? "0" : isMobile ? "70px" :
|
|
2212
|
+
left: isPipFullscreen ? "0" : isMobile ? "10px" : `${pipPosition.x}px`,
|
|
2213
|
+
top: isPipFullscreen ? "0" : isMobile ? "70px" : `${pipPosition.y}px`,
|
|
2223
2214
|
right: isPipFullscreen ? "0" : isMobile ? "10px" : "auto",
|
|
2224
2215
|
bottom: isPipFullscreen ? "0" : "auto",
|
|
2225
|
-
width: isPipFullscreen ? "100vw" : isMobile ? "calc(100vw - 20px)" : isPipMinimized ? "350px" :
|
|
2226
|
-
height: isPipFullscreen ? "100vh" : isPipMinimized ? "auto" : isMobile ? "300px" :
|
|
2216
|
+
width: isPipFullscreen ? "100vw" : isMobile ? "calc(100vw - 20px)" : isPipMinimized ? "350px" : `${pipSize.width}px`,
|
|
2217
|
+
height: isPipFullscreen ? "100vh" : isPipMinimized ? "auto" : isMobile ? "300px" : `${pipSize.height}px`,
|
|
2227
2218
|
background: "#FFFFFF",
|
|
2228
2219
|
borderRadius: isPipFullscreen ? "0" : "8px",
|
|
2229
2220
|
boxShadow: "0 8px 24px rgba(0, 0, 0, 0.3)",
|
|
@@ -2274,7 +2265,7 @@
|
|
|
2274
2265
|
textOverflow: "ellipsis",
|
|
2275
2266
|
whiteSpace: "nowrap"
|
|
2276
2267
|
}
|
|
2277
|
-
}, "Video Call - ",
|
|
2268
|
+
}, "Video Call - ", selectedAppointment?.patientName || "Patient")), /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2278
2269
|
style: {
|
|
2279
2270
|
display: "flex",
|
|
2280
2271
|
gap: isMobile ? "4px" : "6px",
|
|
@@ -2403,7 +2394,7 @@
|
|
|
2403
2394
|
src: (() => {
|
|
2404
2395
|
if (!callToken) return "";
|
|
2405
2396
|
const base = String(joinCallUrlBase || "");
|
|
2406
|
-
return
|
|
2397
|
+
return `${base}${callToken}`;
|
|
2407
2398
|
})(),
|
|
2408
2399
|
style: {
|
|
2409
2400
|
width: "100%",
|
|
@@ -2474,7 +2465,12 @@
|
|
|
2474
2465
|
background: "transparent",
|
|
2475
2466
|
zIndex: 10001
|
|
2476
2467
|
}
|
|
2477
|
-
})), /*#__PURE__*/React__default["default"].createElement("style", null,
|
|
2468
|
+
})), /*#__PURE__*/React__default["default"].createElement("style", null, `
|
|
2469
|
+
@keyframes pulse {
|
|
2470
|
+
0%, 100% { opacity: 1; }
|
|
2471
|
+
50% { opacity: 0.5; }
|
|
2472
|
+
}
|
|
2473
|
+
`))), showAuthError && /*#__PURE__*/React__default["default"].createElement("div", {
|
|
2478
2474
|
style: {
|
|
2479
2475
|
position: "fixed",
|
|
2480
2476
|
inset: 0,
|
|
@@ -2525,14 +2521,14 @@
|
|
|
2525
2521
|
|
|
2526
2522
|
// SDK for embedding appointment widget
|
|
2527
2523
|
const BookingSDK = {
|
|
2528
|
-
/**
|
|
2529
|
-
* Show appointment widget with configuration
|
|
2530
|
-
* @param {object} config - Configuration object
|
|
2531
|
-
* @param {string} config.apiBaseUrl - Base URL for API
|
|
2532
|
-
* @param {string} config.hospitalId - Hospital ID
|
|
2533
|
-
* @param {number} config.doctorId - Doctor ID
|
|
2534
|
-
* @param {string} config.joinCallUrl - Video call URL
|
|
2535
|
-
* @param {function} onAction - Optional callback for actions
|
|
2524
|
+
/**
|
|
2525
|
+
* Show appointment widget with configuration
|
|
2526
|
+
* @param {object} config - Configuration object
|
|
2527
|
+
* @param {string} config.apiBaseUrl - Base URL for API
|
|
2528
|
+
* @param {string} config.hospitalId - Hospital ID
|
|
2529
|
+
* @param {number} config.doctorId - Doctor ID
|
|
2530
|
+
* @param {string} config.joinCallUrl - Video call URL
|
|
2531
|
+
* @param {function} onAction - Optional callback for actions
|
|
2536
2532
|
*/
|
|
2537
2533
|
showWidget: (config, onAction) => {
|
|
2538
2534
|
if (!bookingWidgetInstance) {
|