pih-appointment-widget 0.0.35 → 0.0.36
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 +9 -10
- package/dist/Example.js +2 -1
- package/dist/components/AppointmentPage.js +62 -87
- package/dist/components/ICD10Assistant.js +898 -0
- package/dist/constants/apiConfig.js +2 -1
- package/dist/doctor-appointments-widget.umd.js +119 -115
- package/dist/doctor-appointments-widget.umd.min.js +1 -1
- package/dist/hooks/useClipboard.js +41 -0
- package/dist/pih-appointment-widget.umd.js +123 -122
- package/dist/pih-appointment-widget.umd.min.js +1 -1
- package/dist/services/appointmentService.js +20 -20
- package/dist/services/httpService.js +18 -14
- package/dist/services/icdService.js +87 -0
- 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 +48 -48
- package/src/Example.js +14 -11
- package/src/components/AppointmentPage.js +2498 -2502
- package/src/components/ICD10Assistant.jsx +855 -0
- package/src/constants/apiConfig.js +29 -28
- package/src/hooks/useClipboard.js +35 -0
- 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 -0
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,21 +19,20 @@ 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
|
|
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; }
|
|
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); }
|
|
24
23
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
25
24
|
let bookingWidgetInstance = null;
|
|
26
25
|
|
|
27
26
|
// SDK for embedding appointment widget
|
|
28
27
|
const BookingSDK = {
|
|
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
|
|
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
|
|
37
36
|
*/
|
|
38
37
|
showWidget: (config, onAction) => {
|
|
39
38
|
if (!bookingWidgetInstance) {
|
package/dist/Example.js
CHANGED
|
@@ -5,8 +5,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _AppointmentPage = _interopRequireDefault(require("./components/AppointmentPage.js"));
|
|
8
|
+
var _ICD10Assistant = _interopRequireDefault(require("./components/ICD10Assistant.jsx"));
|
|
8
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
10
|
const Example = () => {
|
|
10
|
-
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(_AppointmentPage.default, null));
|
|
11
|
+
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(_AppointmentPage.default, null), /*#__PURE__*/React.createElement(_ICD10Assistant.default, null));
|
|
11
12
|
};
|
|
12
13
|
var _default = exports.default = Example;
|
|
@@ -8,8 +8,10 @@ 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
|
|
12
|
-
function
|
|
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); }
|
|
13
15
|
// Decode JWT payload (no verification; for display only). Returns {} on invalid/missing.
|
|
14
16
|
function getJwtPayload(token) {
|
|
15
17
|
if (!token || typeof token !== "string") return {};
|
|
@@ -19,7 +21,7 @@ function getJwtPayload(token) {
|
|
|
19
21
|
const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
20
22
|
const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
|
|
21
23
|
return JSON.parse(atob(padded));
|
|
22
|
-
} catch {
|
|
24
|
+
} catch (_unused) {
|
|
23
25
|
return {};
|
|
24
26
|
}
|
|
25
27
|
}
|
|
@@ -39,26 +41,32 @@ const PIH_APPOINTMENT_WIDGET_DATA_ATTR = "data-pih-widget";
|
|
|
39
41
|
|
|
40
42
|
// Extract from SSO login response (not from appToken JWT — these are only in login response)
|
|
41
43
|
function extractAppToken(response) {
|
|
44
|
+
var _ref, _ref2, _ref3, _response$data$access, _response$data, _response$data2;
|
|
42
45
|
if (!response || response.err) return null;
|
|
43
|
-
return response.data
|
|
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;
|
|
44
47
|
}
|
|
45
48
|
function extractDoctorIdFromLoginResponse(response) {
|
|
46
|
-
|
|
47
|
-
|
|
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;
|
|
48
52
|
console.log(id, 'extractDoctorIdFromLoginResponse -> id');
|
|
49
53
|
return id != null ? String(id) : null;
|
|
50
54
|
}
|
|
51
55
|
function extractUserNameFromLoginResponse(response) {
|
|
52
|
-
|
|
53
|
-
|
|
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;
|
|
54
59
|
return name != null ? String(name) : null;
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
// Error boundary so a render error never shows a blank screen
|
|
58
63
|
class AppointmentErrorBoundary extends _react.Component {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
constructor() {
|
|
65
|
+
super(...arguments);
|
|
66
|
+
_defineProperty(this, "state", {
|
|
67
|
+
hasError: false
|
|
68
|
+
});
|
|
69
|
+
}
|
|
62
70
|
static getDerivedStateFromError() {
|
|
63
71
|
return {
|
|
64
72
|
hasError: true
|
|
@@ -115,21 +123,21 @@ class AppointmentErrorBoundary extends _react.Component {
|
|
|
115
123
|
}
|
|
116
124
|
|
|
117
125
|
// SDK Component - accepts configuration from parent app
|
|
118
|
-
const AppointmentPage =
|
|
126
|
+
const AppointmentPage = _ref7 => {
|
|
119
127
|
let {
|
|
120
128
|
config = {}
|
|
121
|
-
} =
|
|
129
|
+
} = _ref7;
|
|
122
130
|
const [storedApiBaseUrl, setStoredApiBaseUrl] = (0, _react.useState)(() => {
|
|
123
131
|
try {
|
|
124
132
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_API_BASE_URL) : null;
|
|
125
|
-
} catch {
|
|
133
|
+
} catch (_unused2) {
|
|
126
134
|
return null;
|
|
127
135
|
}
|
|
128
136
|
});
|
|
129
137
|
const [storedHospitalId, setStoredHospitalId] = (0, _react.useState)(() => {
|
|
130
138
|
try {
|
|
131
139
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_HOSPITAL_ID) : null;
|
|
132
|
-
} catch {
|
|
140
|
+
} catch (_unused3) {
|
|
133
141
|
return null;
|
|
134
142
|
}
|
|
135
143
|
});
|
|
@@ -140,14 +148,14 @@ const AppointmentPage = _ref => {
|
|
|
140
148
|
const [storedIdToken, setStoredIdToken] = (0, _react.useState)(() => {
|
|
141
149
|
try {
|
|
142
150
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_ID_TOKEN) : null;
|
|
143
|
-
} catch {
|
|
151
|
+
} catch (_unused4) {
|
|
144
152
|
return null;
|
|
145
153
|
}
|
|
146
154
|
});
|
|
147
155
|
const [storedEmail, setStoredEmail] = (0, _react.useState)(() => {
|
|
148
156
|
try {
|
|
149
157
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_EMAIL) : null;
|
|
150
|
-
} catch {
|
|
158
|
+
} catch (_unused5) {
|
|
151
159
|
return null;
|
|
152
160
|
}
|
|
153
161
|
});
|
|
@@ -162,14 +170,12 @@ const AppointmentPage = _ref => {
|
|
|
162
170
|
if (token && String(token).trim()) {
|
|
163
171
|
const prevToken = localStorage.getItem(STORAGE_KEY_ID_TOKEN);
|
|
164
172
|
if (prevToken !== token) {
|
|
165
|
-
// New token from parent (e.g. Flutter re-login) — clear
|
|
166
|
-
//
|
|
167
|
-
// if appToken is already absent, the SSO effect will fire naturally via !appToken.
|
|
168
|
-
const hadAppToken = !!localStorage.getItem(STORAGE_KEY_APP_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.
|
|
169
175
|
setAppToken(null);
|
|
170
176
|
setDoctorIdFromLogin(null);
|
|
171
177
|
setUserName(null);
|
|
172
|
-
|
|
178
|
+
setRefreshLoginTrigger(t => t + 1);
|
|
173
179
|
localStorage.removeItem(STORAGE_KEY_APP_TOKEN);
|
|
174
180
|
localStorage.removeItem(STORAGE_KEY_DOCTOR_ID);
|
|
175
181
|
localStorage.removeItem(STORAGE_KEY_USER_NAME);
|
|
@@ -194,21 +200,21 @@ const AppointmentPage = _ref => {
|
|
|
194
200
|
const [appToken, setAppToken] = (0, _react.useState)(() => {
|
|
195
201
|
try {
|
|
196
202
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_APP_TOKEN) : null;
|
|
197
|
-
} catch {
|
|
203
|
+
} catch (_unused6) {
|
|
198
204
|
return null;
|
|
199
205
|
}
|
|
200
206
|
});
|
|
201
207
|
const [doctorIdFromLogin, setDoctorIdFromLogin] = (0, _react.useState)(() => {
|
|
202
208
|
try {
|
|
203
209
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_DOCTOR_ID) : null;
|
|
204
|
-
} catch {
|
|
210
|
+
} catch (_unused7) {
|
|
205
211
|
return null;
|
|
206
212
|
}
|
|
207
213
|
});
|
|
208
214
|
const [userName, setUserName] = (0, _react.useState)(() => {
|
|
209
215
|
try {
|
|
210
216
|
return typeof localStorage !== "undefined" ? localStorage.getItem(STORAGE_KEY_USER_NAME) : null;
|
|
211
|
-
} catch {
|
|
217
|
+
} catch (_unused8) {
|
|
212
218
|
return null;
|
|
213
219
|
}
|
|
214
220
|
});
|
|
@@ -219,7 +225,7 @@ const AppointmentPage = _ref => {
|
|
|
219
225
|
const hasId = localStorage.getItem(STORAGE_KEY_ID_TOKEN);
|
|
220
226
|
const hasEmail = localStorage.getItem(STORAGE_KEY_EMAIL);
|
|
221
227
|
return !hasApp && !!(hasId && hasEmail);
|
|
222
|
-
} catch {
|
|
228
|
+
} catch (_unused9) {
|
|
223
229
|
return false;
|
|
224
230
|
}
|
|
225
231
|
});
|
|
@@ -281,7 +287,7 @@ const AppointmentPage = _ref => {
|
|
|
281
287
|
const y = date.getFullYear();
|
|
282
288
|
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
283
289
|
const d = String(date.getDate()).padStart(2, "0");
|
|
284
|
-
return
|
|
290
|
+
return "".concat(y, "-").concat(m, "-").concat(d);
|
|
285
291
|
};
|
|
286
292
|
const getDateRange = option => {
|
|
287
293
|
const today = new Date();
|
|
@@ -312,8 +318,8 @@ const AppointmentPage = _ref => {
|
|
|
312
318
|
to = formatLocalDate(lastOfMonth);
|
|
313
319
|
break;
|
|
314
320
|
case "currentYear":
|
|
315
|
-
from =
|
|
316
|
-
to =
|
|
321
|
+
from = "".concat(today.getFullYear(), "-01-01");
|
|
322
|
+
to = "".concat(today.getFullYear(), "-12-31");
|
|
317
323
|
break;
|
|
318
324
|
default:
|
|
319
325
|
from = to = getTodayDate();
|
|
@@ -338,7 +344,7 @@ const AppointmentPage = _ref => {
|
|
|
338
344
|
case "currentYear":
|
|
339
345
|
return "Current Year";
|
|
340
346
|
case "custom":
|
|
341
|
-
return isMobile ? "Custom" :
|
|
347
|
+
return isMobile ? "Custom" : "".concat(fromDate, " to ").concat(toDate);
|
|
342
348
|
default:
|
|
343
349
|
return "Today";
|
|
344
350
|
}
|
|
@@ -423,12 +429,12 @@ const AppointmentPage = _ref => {
|
|
|
423
429
|
|
|
424
430
|
// Helper to get unique identifier from appointment
|
|
425
431
|
const getAppointmentId = appointment => {
|
|
426
|
-
return 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);
|
|
427
433
|
};
|
|
428
434
|
|
|
429
435
|
// Generate avatar with first letter if no image
|
|
430
436
|
const getPatientAvatar = appointment => {
|
|
431
|
-
if (appointment
|
|
437
|
+
if (appointment !== null && appointment !== void 0 && appointment.image) {
|
|
432
438
|
return appointment.image;
|
|
433
439
|
}
|
|
434
440
|
// Return null to use the letter avatar component
|
|
@@ -549,8 +555,8 @@ const AppointmentPage = _ref => {
|
|
|
549
555
|
// Returns true if the current time is within 2 hours after the appointment's scheduled slot time.
|
|
550
556
|
// Handles date format: "Sun, 15 Mar 2026" and time format: "12:15 PM"
|
|
551
557
|
const isWithinJoinWindow = appointment => {
|
|
552
|
-
const dateStr = appointment
|
|
553
|
-
const timeStr = 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);
|
|
554
560
|
if (!dateStr || !timeStr) return false;
|
|
555
561
|
try {
|
|
556
562
|
// Parse "12:15 PM" or "9:30 AM" into 24-hour h/m values
|
|
@@ -570,11 +576,11 @@ const AppointmentPage = _ref => {
|
|
|
570
576
|
}
|
|
571
577
|
if (isNaN(h) || isNaN(m)) return false;
|
|
572
578
|
// "Sun, 15 Mar 2026 12:15:00" — space-separated; JS parses RFC-like date strings correctly
|
|
573
|
-
const appointmentDate = new Date(
|
|
579
|
+
const appointmentDate = new Date("".concat(dateStr, " ").concat(String(h).padStart(2, "0"), ":").concat(String(m).padStart(2, "0"), ":00"));
|
|
574
580
|
if (isNaN(appointmentDate.getTime())) return false;
|
|
575
581
|
const windowEnd = new Date(appointmentDate.getTime() + 2 * 60 * 60 * 1000);
|
|
576
582
|
return new Date() <= windowEnd;
|
|
577
|
-
} catch {
|
|
583
|
+
} catch (_unused0) {
|
|
578
584
|
return false;
|
|
579
585
|
}
|
|
580
586
|
};
|
|
@@ -585,6 +591,7 @@ const AppointmentPage = _ref => {
|
|
|
585
591
|
setCallLoading(true);
|
|
586
592
|
setCallError(null);
|
|
587
593
|
try {
|
|
594
|
+
var _response$data3;
|
|
588
595
|
const callConfig = {
|
|
589
596
|
apiBaseUrl,
|
|
590
597
|
hospitalId,
|
|
@@ -612,7 +619,7 @@ const AppointmentPage = _ref => {
|
|
|
612
619
|
setCallError("Session expired. Re-authenticating...");
|
|
613
620
|
return;
|
|
614
621
|
}
|
|
615
|
-
if (response.err || !response.data
|
|
622
|
+
if (response.err || !((_response$data3 = response.data) !== null && _response$data3 !== void 0 && _response$data3.token)) {
|
|
616
623
|
setCallError(String(response.err || "Failed to initiate call"));
|
|
617
624
|
return;
|
|
618
625
|
}
|
|
@@ -835,7 +842,6 @@ const AppointmentPage = _ref => {
|
|
|
835
842
|
setAppToken(null);
|
|
836
843
|
setDoctorIdFromLogin(null);
|
|
837
844
|
setUserName(null);
|
|
838
|
-
setRefreshLoginTrigger(0); // reset trigger even on failure to prevent infinite retry loops
|
|
839
845
|
try {
|
|
840
846
|
if (typeof localStorage !== "undefined") {
|
|
841
847
|
localStorage.removeItem(STORAGE_KEY_APP_TOKEN);
|
|
@@ -852,7 +858,6 @@ const AppointmentPage = _ref => {
|
|
|
852
858
|
setUserName(name);
|
|
853
859
|
setTokenError(null);
|
|
854
860
|
setRedirectToHome(false);
|
|
855
|
-
setRefreshLoginTrigger(0); // reset one-shot trigger so SSO doesn't re-fire on next dep change
|
|
856
861
|
try {
|
|
857
862
|
if (typeof localStorage !== "undefined") {
|
|
858
863
|
localStorage.setItem(STORAGE_KEY_APP_TOKEN, token);
|
|
@@ -863,7 +868,7 @@ const AppointmentPage = _ref => {
|
|
|
863
868
|
}
|
|
864
869
|
}).catch(err => {
|
|
865
870
|
if (!cancelled) {
|
|
866
|
-
setTokenError(err
|
|
871
|
+
setTokenError((err === null || err === void 0 ? void 0 : err.message) || "Authentication failed. Please try again.");
|
|
867
872
|
setAppToken(null);
|
|
868
873
|
}
|
|
869
874
|
}).finally(() => {
|
|
@@ -895,32 +900,7 @@ const AppointmentPage = _ref => {
|
|
|
895
900
|
|
|
896
901
|
// Add responsive styles and animations
|
|
897
902
|
const style = document.createElement("style");
|
|
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
|
-
`;
|
|
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 ";
|
|
924
904
|
document.head.appendChild(style);
|
|
925
905
|
|
|
926
906
|
// Handle window resize
|
|
@@ -973,7 +953,7 @@ const AppointmentPage = _ref => {
|
|
|
973
953
|
justifyContent: "center",
|
|
974
954
|
padding: "24px"
|
|
975
955
|
}
|
|
976
|
-
}, /*#__PURE__*/_react.default.createElement("style", null,
|
|
956
|
+
}, /*#__PURE__*/_react.default.createElement("style", null, "@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }"), /*#__PURE__*/_react.default.createElement("div", {
|
|
977
957
|
style: {
|
|
978
958
|
width: "40px",
|
|
979
959
|
height: "40px",
|
|
@@ -1732,7 +1712,7 @@ const AppointmentPage = _ref => {
|
|
|
1732
1712
|
style: {
|
|
1733
1713
|
fontSize: "13px"
|
|
1734
1714
|
}
|
|
1735
|
-
}, searchQuery ?
|
|
1715
|
+
}, searchQuery ? "No appointments found for \"".concat(searchQuery, "\"") : "No appointments found"), searchQuery && /*#__PURE__*/_react.default.createElement("button", {
|
|
1736
1716
|
onClick: () => setSearchQuery(""),
|
|
1737
1717
|
style: {
|
|
1738
1718
|
marginTop: "12px",
|
|
@@ -2011,7 +1991,7 @@ const AppointmentPage = _ref => {
|
|
|
2011
1991
|
fontWeight: "700",
|
|
2012
1992
|
fontSize: isMobile ? "12px" : "13px"
|
|
2013
1993
|
}
|
|
2014
|
-
}, selectedAppointment
|
|
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", {
|
|
2015
1995
|
style: {
|
|
2016
1996
|
textAlign: "right"
|
|
2017
1997
|
}
|
|
@@ -2026,7 +2006,7 @@ const AppointmentPage = _ref => {
|
|
|
2026
2006
|
fontWeight: "700",
|
|
2027
2007
|
fontSize: isMobile ? "12px" : "13px"
|
|
2028
2008
|
}
|
|
2029
|
-
}, selectedAppointment
|
|
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", {
|
|
2030
2010
|
style: {
|
|
2031
2011
|
display: "flex",
|
|
2032
2012
|
justifyContent: "space-between"
|
|
@@ -2046,7 +2026,7 @@ const AppointmentPage = _ref => {
|
|
|
2046
2026
|
fontWeight: "700",
|
|
2047
2027
|
fontSize: isMobile ? "12px" : "13px"
|
|
2048
2028
|
}
|
|
2049
|
-
}, selectedAppointment
|
|
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", {
|
|
2050
2030
|
style: {
|
|
2051
2031
|
textAlign: "right"
|
|
2052
2032
|
}
|
|
@@ -2061,7 +2041,7 @@ const AppointmentPage = _ref => {
|
|
|
2061
2041
|
fontWeight: "700",
|
|
2062
2042
|
fontSize: isMobile ? "12px" : "13px"
|
|
2063
2043
|
}
|
|
2064
|
-
}, selectedAppointment
|
|
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", {
|
|
2065
2045
|
style: {
|
|
2066
2046
|
display: "flex",
|
|
2067
2047
|
justifyContent: "space-between"
|
|
@@ -2081,7 +2061,7 @@ const AppointmentPage = _ref => {
|
|
|
2081
2061
|
fontWeight: "700",
|
|
2082
2062
|
fontSize: isMobile ? "12px" : "13px"
|
|
2083
2063
|
}
|
|
2084
|
-
}, selectedAppointment
|
|
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", {
|
|
2085
2065
|
style: {
|
|
2086
2066
|
display: "flex",
|
|
2087
2067
|
justifyContent: "space-between"
|
|
@@ -2101,7 +2081,7 @@ const AppointmentPage = _ref => {
|
|
|
2101
2081
|
fontWeight: "700",
|
|
2102
2082
|
fontSize: isMobile ? "12px" : "13px"
|
|
2103
2083
|
}
|
|
2104
|
-
}, selectedAppointment
|
|
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", {
|
|
2105
2085
|
style: {
|
|
2106
2086
|
display: "flex",
|
|
2107
2087
|
justifyContent: "space-between"
|
|
@@ -2122,7 +2102,7 @@ const AppointmentPage = _ref => {
|
|
|
2122
2102
|
fontSize: isMobile ? "11px" : "12px",
|
|
2123
2103
|
lineHeight: "1.4"
|
|
2124
2104
|
}
|
|
2125
|
-
}, selectedAppointment
|
|
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", {
|
|
2126
2106
|
style: {
|
|
2127
2107
|
display: "flex",
|
|
2128
2108
|
flexDirection: isMobile ? "column" : "row",
|
|
@@ -2175,12 +2155,12 @@ const AppointmentPage = _ref => {
|
|
|
2175
2155
|
}, "Select an appointment to view details"))))))), showPipVideo && /*#__PURE__*/_react.default.createElement("div", {
|
|
2176
2156
|
style: {
|
|
2177
2157
|
position: "fixed",
|
|
2178
|
-
left: isPipFullscreen ? "0" : isMobile ? "10px" :
|
|
2179
|
-
top: isPipFullscreen ? "0" : isMobile ? "70px" :
|
|
2158
|
+
left: isPipFullscreen ? "0" : isMobile ? "10px" : "".concat(pipPosition.x, "px"),
|
|
2159
|
+
top: isPipFullscreen ? "0" : isMobile ? "70px" : "".concat(pipPosition.y, "px"),
|
|
2180
2160
|
right: isPipFullscreen ? "0" : isMobile ? "10px" : "auto",
|
|
2181
2161
|
bottom: isPipFullscreen ? "0" : "auto",
|
|
2182
|
-
width: isPipFullscreen ? "100vw" : isMobile ? "calc(100vw - 20px)" : isPipMinimized ? "350px" :
|
|
2183
|
-
height: isPipFullscreen ? "100vh" : isPipMinimized ? "auto" : isMobile ? "300px" :
|
|
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"),
|
|
2184
2164
|
background: "#FFFFFF",
|
|
2185
2165
|
borderRadius: isPipFullscreen ? "0" : "8px",
|
|
2186
2166
|
boxShadow: "0 8px 24px rgba(0, 0, 0, 0.3)",
|
|
@@ -2231,7 +2211,7 @@ const AppointmentPage = _ref => {
|
|
|
2231
2211
|
textOverflow: "ellipsis",
|
|
2232
2212
|
whiteSpace: "nowrap"
|
|
2233
2213
|
}
|
|
2234
|
-
}, "Video Call - ", selectedAppointment
|
|
2214
|
+
}, "Video Call - ", (selectedAppointment === null || selectedAppointment === void 0 ? void 0 : selectedAppointment.patientName) || "Patient")), /*#__PURE__*/_react.default.createElement("div", {
|
|
2235
2215
|
style: {
|
|
2236
2216
|
display: "flex",
|
|
2237
2217
|
gap: isMobile ? "4px" : "6px",
|
|
@@ -2360,7 +2340,7 @@ const AppointmentPage = _ref => {
|
|
|
2360
2340
|
src: (() => {
|
|
2361
2341
|
if (!callToken) return "";
|
|
2362
2342
|
const base = String(joinCallUrlBase || "");
|
|
2363
|
-
return
|
|
2343
|
+
return "".concat(base).concat(callToken);
|
|
2364
2344
|
})(),
|
|
2365
2345
|
style: {
|
|
2366
2346
|
width: "100%",
|
|
@@ -2431,12 +2411,7 @@ const AppointmentPage = _ref => {
|
|
|
2431
2411
|
background: "transparent",
|
|
2432
2412
|
zIndex: 10001
|
|
2433
2413
|
}
|
|
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", {
|
|
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", {
|
|
2440
2415
|
style: {
|
|
2441
2416
|
position: "fixed",
|
|
2442
2417
|
inset: 0,
|