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