pih-appointment-widget 0.0.38 → 0.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -70
- package/babel.config.js +5 -5
- package/dist/App.js +10 -9
- package/dist/components/AppointmentPage.js +87 -62
- package/dist/components/ICD10Assistant.js +43 -46
- 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 +185 -191
- 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/icdIcons.js +23 -23
- package/src/components/AppointmentPage.js +2502 -2498
- package/src/components/ICD10Assistant.jsx +923 -923
- 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
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
// API Configuration Constants
|
|
2
|
-
// All values are hardcoded defaults
|
|
3
|
-
// When used as SDK, parent app can override via config prop
|
|
4
|
-
// Later: These will be fetched from auth API
|
|
5
|
-
|
|
6
|
-
// Base API URL - hardcoded default (can be overridden via config prop)
|
|
7
|
-
export const API_BASE_URL = "https://afiyaapiqa.powermindinc.com";
|
|
8
|
-
|
|
9
|
-
// API Paths
|
|
10
|
-
export const API_PATHS = {
|
|
11
|
-
APPOINTMENTS: "/appointment/V1/consultant/all-appointments",
|
|
12
|
-
APPOINTMENT_DETAILS: "/appointments",
|
|
13
|
-
JOIN_CALL: "/appointments",
|
|
14
|
-
INITIATE_CALL: "/notification/V1/consultation/online/initiate",
|
|
15
|
-
ICD_SUGGEST: "/insurance/api/icd/suggest",
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Default request parameters (will be fetched from auth API later)
|
|
19
|
-
export const DEFAULT_PARAMS = {
|
|
20
|
-
hospitalId: "dMtEGhak"
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// Request timeout (milliseconds)
|
|
24
|
-
export const REQUEST_TIMEOUT = 10000;
|
|
25
|
-
|
|
26
|
-
// Join call URL (will be dynamic from auth API later)
|
|
27
|
-
export const JOIN_CALL_URL = "https://ittisalqa.powermindinc.com/call?token=";
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
// API Configuration Constants
|
|
2
|
+
// All values are hardcoded defaults
|
|
3
|
+
// When used as SDK, parent app can override via config prop
|
|
4
|
+
// Later: These will be fetched from auth API
|
|
5
|
+
|
|
6
|
+
// Base API URL - hardcoded default (can be overridden via config prop)
|
|
7
|
+
export const API_BASE_URL = "https://afiyaapiqa.powermindinc.com";
|
|
8
|
+
|
|
9
|
+
// API Paths
|
|
10
|
+
export const API_PATHS = {
|
|
11
|
+
APPOINTMENTS: "/appointment/V1/consultant/all-appointments",
|
|
12
|
+
APPOINTMENT_DETAILS: "/appointments",
|
|
13
|
+
JOIN_CALL: "/appointments",
|
|
14
|
+
INITIATE_CALL: "/notification/V1/consultation/online/initiate",
|
|
15
|
+
ICD_SUGGEST: "/insurance/api/icd/suggest",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Default request parameters (will be fetched from auth API later)
|
|
19
|
+
export const DEFAULT_PARAMS = {
|
|
20
|
+
hospitalId: "dMtEGhak"
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Request timeout (milliseconds)
|
|
24
|
+
export const REQUEST_TIMEOUT = 10000;
|
|
25
|
+
|
|
26
|
+
// Join call URL (will be dynamic from auth API later)
|
|
27
|
+
export const JOIN_CALL_URL = "https://ittisalqa.powermindinc.com/call?token=";
|
|
28
|
+
|
|
29
|
+
|
|
30
30
|
export const WEB_URL = "https://afiyaproqa.powermindinc.com/";
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useClipboard.js
|
|
3
|
-
* Tiny hook for clipboard copy with transient "Copied!" feedback.
|
|
4
|
-
*/
|
|
5
|
-
import { useState, useCallback } from "react";
|
|
6
|
-
|
|
7
|
-
export function useClipboard(resetMs = 1800) {
|
|
8
|
-
const [copiedKey, setCopiedKey] = useState(null);
|
|
9
|
-
|
|
10
|
-
const copy = useCallback(
|
|
11
|
-
(text, key = "default") => {
|
|
12
|
-
if (navigator.clipboard) {
|
|
13
|
-
navigator.clipboard.writeText(text).then(() => {
|
|
14
|
-
setCopiedKey(key);
|
|
15
|
-
setTimeout(() => setCopiedKey(null), resetMs);
|
|
16
|
-
});
|
|
17
|
-
} else {
|
|
18
|
-
// Fallback for older browsers / WebViews
|
|
19
|
-
const el = document.createElement("textarea");
|
|
20
|
-
el.value = text;
|
|
21
|
-
el.style.position = "fixed";
|
|
22
|
-
el.style.opacity = "0";
|
|
23
|
-
document.body.appendChild(el);
|
|
24
|
-
el.select();
|
|
25
|
-
document.execCommand("copy");
|
|
26
|
-
document.body.removeChild(el);
|
|
27
|
-
setCopiedKey(key);
|
|
28
|
-
setTimeout(() => setCopiedKey(null), resetMs);
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
[resetMs]
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
return { copy, copiedKey };
|
|
35
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* useClipboard.js
|
|
3
|
+
* Tiny hook for clipboard copy with transient "Copied!" feedback.
|
|
4
|
+
*/
|
|
5
|
+
import { useState, useCallback } from "react";
|
|
6
|
+
|
|
7
|
+
export function useClipboard(resetMs = 1800) {
|
|
8
|
+
const [copiedKey, setCopiedKey] = useState(null);
|
|
9
|
+
|
|
10
|
+
const copy = useCallback(
|
|
11
|
+
(text, key = "default") => {
|
|
12
|
+
if (navigator.clipboard) {
|
|
13
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
14
|
+
setCopiedKey(key);
|
|
15
|
+
setTimeout(() => setCopiedKey(null), resetMs);
|
|
16
|
+
});
|
|
17
|
+
} else {
|
|
18
|
+
// Fallback for older browsers / WebViews
|
|
19
|
+
const el = document.createElement("textarea");
|
|
20
|
+
el.value = text;
|
|
21
|
+
el.style.position = "fixed";
|
|
22
|
+
el.style.opacity = "0";
|
|
23
|
+
document.body.appendChild(el);
|
|
24
|
+
el.select();
|
|
25
|
+
document.execCommand("copy");
|
|
26
|
+
document.body.removeChild(el);
|
|
27
|
+
setCopiedKey(key);
|
|
28
|
+
setTimeout(() => setCopiedKey(null), resetMs);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
[resetMs]
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return { copy, copiedKey };
|
|
35
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import ReactDOM from "react-dom/client";
|
|
3
|
-
import Example from "./Example";
|
|
4
|
-
|
|
5
|
-
const root = ReactDOM.createRoot(document.getElementById("root"));
|
|
6
|
-
root.render(<Example />);
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ReactDOM from "react-dom/client";
|
|
3
|
+
import Example from "./Example";
|
|
4
|
+
|
|
5
|
+
const root = ReactDOM.createRoot(document.getElementById("root"));
|
|
6
|
+
root.render(<Example />);
|
|
@@ -1,92 +1,92 @@
|
|
|
1
|
-
import { getApi, postApi } from "./httpService";
|
|
2
|
-
import {
|
|
3
|
-
API_BASE_URL,
|
|
4
|
-
API_PATHS,
|
|
5
|
-
DEFAULT_PARAMS,
|
|
6
|
-
} from "../constants/apiConfig";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Fetch appointments by status
|
|
10
|
-
* @param {string} status - Appointment status (inprogress, completed, cancelled, upcoming)
|
|
11
|
-
* @param {string} fromDate - Start date in YYYY-MM-DD format
|
|
12
|
-
* @param {string} toDate - End date in YYYY-MM-DD format
|
|
13
|
-
* @param {object} config - Optional configuration { apiBaseUrl, hospitalId, doctorId }
|
|
14
|
-
* @returns {Promise} Appointments data
|
|
15
|
-
*/
|
|
16
|
-
export const getAppointmentsByStatus = async (status, fromDate, toDate, config = {}) => {
|
|
17
|
-
// Map status to API format
|
|
18
|
-
let apiStatus = (status || "").toUpperCase();
|
|
19
|
-
|
|
20
|
-
if (apiStatus === "INPROGRESS") {
|
|
21
|
-
apiStatus = "IN_PROGRESS";
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (apiStatus === "UPCOMING") {
|
|
25
|
-
apiStatus = "UPCOMING,RESCHEDULED";
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const baseURL = config.apiBaseUrl;
|
|
29
|
-
const hospitalId = config.hospitalId;
|
|
30
|
-
const doctorId = config.doctorId;
|
|
31
|
-
const token = config.token || '';
|
|
32
|
-
|
|
33
|
-
const params = { hospitalId, doctorId, fromDate, toDate, statuses: apiStatus };
|
|
34
|
-
// if (type && String(type).toUpperCase() !== "ALL") {
|
|
35
|
-
// params.appointmentType = String(type).toUpperCase();
|
|
36
|
-
// }
|
|
37
|
-
params.appointmentType = 'ONLINE';
|
|
38
|
-
const url = `${baseURL}${API_PATHS.APPOINTMENTS}`;
|
|
39
|
-
|
|
40
|
-
// Return raw response (including status) so caller can detect 401 and re-login
|
|
41
|
-
const response = await getApi(url, params, "PIH-Appointment-Widget", token);
|
|
42
|
-
return response;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Fetch appointment details by ID
|
|
47
|
-
* @param {string|number} appointmentId - The appointment ID
|
|
48
|
-
* @param {object} config - Optional configuration { apiBaseUrl }
|
|
49
|
-
* @returns {Promise} Appointment details
|
|
50
|
-
*/
|
|
51
|
-
export const getAppointmentDetails = async (appointmentId, config = {}) => {
|
|
52
|
-
try {
|
|
53
|
-
const baseURL = config.apiBaseUrl;
|
|
54
|
-
const url = `${baseURL}${API_PATHS.APPOINTMENT_DETAILS}/${appointmentId}`;
|
|
55
|
-
|
|
56
|
-
const response = await getApi(url, {}, "PIH-Appointment-Widget");
|
|
57
|
-
|
|
58
|
-
if (response.err) {
|
|
59
|
-
throw new Error(response.err);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return response;
|
|
63
|
-
} catch (error) {
|
|
64
|
-
console.error("Error fetching appointment details:", error);
|
|
65
|
-
throw error;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Initiate an online consultation — returns LiveKit room token + wss URL.
|
|
71
|
-
* @param {object} appointment - Selected appointment object
|
|
72
|
-
* @param {object} config - { apiBaseUrl, hospitalId, doctorId, doctorName, appToken }
|
|
73
|
-
* @returns {Promise<{ data: { token, url, roomName, participantName }, err?, status? }>}
|
|
74
|
-
*/
|
|
75
|
-
export const initiateConsultation = async (appointment, config = {}) => {
|
|
76
|
-
console.log("initiateConsultation -> config", config)
|
|
77
|
-
const baseURL = (config.apiBaseUrl).replace(/\/$/, "");
|
|
78
|
-
const url = `${baseURL}${API_PATHS.INITIATE_CALL}`;
|
|
79
|
-
const appToken = config.appToken || "";
|
|
80
|
-
|
|
81
|
-
const body = {
|
|
82
|
-
patientId: String(appointment.patientId || ""),
|
|
83
|
-
primaryPatientId: String(appointment.primaryPatientId || appointment.patientId || ""),
|
|
84
|
-
hospitalId: config.hospitalId,
|
|
85
|
-
doctorId: String(config.doctorId),
|
|
86
|
-
patientName: appointment.patientName || appointment.name || "",
|
|
87
|
-
doctorName: appointment.doctorName || config.doctorName,
|
|
88
|
-
appointmentId: String(appointment.id || appointment.appointmentId || appointment._id || ""),
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
return postApi(url, body, "PIH-Appointment-Widget", {}, appToken);
|
|
92
|
-
};
|
|
1
|
+
import { getApi, postApi } from "./httpService";
|
|
2
|
+
import {
|
|
3
|
+
API_BASE_URL,
|
|
4
|
+
API_PATHS,
|
|
5
|
+
DEFAULT_PARAMS,
|
|
6
|
+
} from "../constants/apiConfig";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Fetch appointments by status
|
|
10
|
+
* @param {string} status - Appointment status (inprogress, completed, cancelled, upcoming)
|
|
11
|
+
* @param {string} fromDate - Start date in YYYY-MM-DD format
|
|
12
|
+
* @param {string} toDate - End date in YYYY-MM-DD format
|
|
13
|
+
* @param {object} config - Optional configuration { apiBaseUrl, hospitalId, doctorId }
|
|
14
|
+
* @returns {Promise} Appointments data
|
|
15
|
+
*/
|
|
16
|
+
export const getAppointmentsByStatus = async (status, fromDate, toDate, config = {}) => {
|
|
17
|
+
// Map status to API format
|
|
18
|
+
let apiStatus = (status || "").toUpperCase();
|
|
19
|
+
|
|
20
|
+
if (apiStatus === "INPROGRESS") {
|
|
21
|
+
apiStatus = "IN_PROGRESS";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (apiStatus === "UPCOMING") {
|
|
25
|
+
apiStatus = "UPCOMING,RESCHEDULED";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const baseURL = config.apiBaseUrl;
|
|
29
|
+
const hospitalId = config.hospitalId;
|
|
30
|
+
const doctorId = config.doctorId;
|
|
31
|
+
const token = config.token || '';
|
|
32
|
+
|
|
33
|
+
const params = { hospitalId, doctorId, fromDate, toDate, statuses: apiStatus };
|
|
34
|
+
// if (type && String(type).toUpperCase() !== "ALL") {
|
|
35
|
+
// params.appointmentType = String(type).toUpperCase();
|
|
36
|
+
// }
|
|
37
|
+
params.appointmentType = 'ONLINE';
|
|
38
|
+
const url = `${baseURL}${API_PATHS.APPOINTMENTS}`;
|
|
39
|
+
|
|
40
|
+
// Return raw response (including status) so caller can detect 401 and re-login
|
|
41
|
+
const response = await getApi(url, params, "PIH-Appointment-Widget", token);
|
|
42
|
+
return response;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Fetch appointment details by ID
|
|
47
|
+
* @param {string|number} appointmentId - The appointment ID
|
|
48
|
+
* @param {object} config - Optional configuration { apiBaseUrl }
|
|
49
|
+
* @returns {Promise} Appointment details
|
|
50
|
+
*/
|
|
51
|
+
export const getAppointmentDetails = async (appointmentId, config = {}) => {
|
|
52
|
+
try {
|
|
53
|
+
const baseURL = config.apiBaseUrl;
|
|
54
|
+
const url = `${baseURL}${API_PATHS.APPOINTMENT_DETAILS}/${appointmentId}`;
|
|
55
|
+
|
|
56
|
+
const response = await getApi(url, {}, "PIH-Appointment-Widget");
|
|
57
|
+
|
|
58
|
+
if (response.err) {
|
|
59
|
+
throw new Error(response.err);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return response;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error("Error fetching appointment details:", error);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Initiate an online consultation — returns LiveKit room token + wss URL.
|
|
71
|
+
* @param {object} appointment - Selected appointment object
|
|
72
|
+
* @param {object} config - { apiBaseUrl, hospitalId, doctorId, doctorName, appToken }
|
|
73
|
+
* @returns {Promise<{ data: { token, url, roomName, participantName }, err?, status? }>}
|
|
74
|
+
*/
|
|
75
|
+
export const initiateConsultation = async (appointment, config = {}) => {
|
|
76
|
+
console.log("initiateConsultation -> config", config)
|
|
77
|
+
const baseURL = (config.apiBaseUrl).replace(/\/$/, "");
|
|
78
|
+
const url = `${baseURL}${API_PATHS.INITIATE_CALL}`;
|
|
79
|
+
const appToken = config.appToken || "";
|
|
80
|
+
|
|
81
|
+
const body = {
|
|
82
|
+
patientId: String(appointment.patientId || ""),
|
|
83
|
+
primaryPatientId: String(appointment.primaryPatientId || appointment.patientId || ""),
|
|
84
|
+
hospitalId: config.hospitalId,
|
|
85
|
+
doctorId: String(config.doctorId),
|
|
86
|
+
patientName: appointment.patientName || appointment.name || "",
|
|
87
|
+
doctorName: appointment.doctorName || config.doctorName,
|
|
88
|
+
appointmentId: String(appointment.id || appointment.appointmentId || appointment._id || ""),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return postApi(url, body, "PIH-Appointment-Widget", {}, appToken);
|
|
92
|
+
};
|
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
export const getApi = async (url, params = {}, header, token = '') => {
|
|
2
|
-
const urlWithParams = new URL(url);
|
|
3
|
-
urlWithParams.search = new URLSearchParams(params).toString();
|
|
4
|
-
|
|
5
|
-
const options = {
|
|
6
|
-
method: "GET",
|
|
7
|
-
headers: {
|
|
8
|
-
"Content-Type": "application/json",
|
|
9
|
-
"Authorization": `${token}`,
|
|
10
|
-
// "X-CLIENT-APP": header,
|
|
11
|
-
},
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
return fetch(urlWithParams, options)
|
|
15
|
-
.then(async (response) => {
|
|
16
|
-
const data = await response.json().catch(() => ({}));
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
return {
|
|
19
|
-
err: data?.resultInfo?.message || "Something went wrong!",
|
|
20
|
-
status: response.status,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
return data;
|
|
24
|
-
})
|
|
25
|
-
.catch((error) => {
|
|
26
|
-
console.error("Fetch error:", error);
|
|
27
|
-
return { err: error?.message || String(error) || "Network error" };
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
export const postApi = async (url, body = {}, header, params = {}, token) => {
|
|
31
|
-
const urlWithParams = new URL(url);
|
|
32
|
-
Object.keys(params).forEach((key) => {
|
|
33
|
-
urlWithParams.searchParams.append(key, params[key]);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const headers = { "Content-Type": "application/json" };
|
|
37
|
-
if (token) headers["Authorization"] = token;
|
|
38
|
-
|
|
39
|
-
const options = {
|
|
40
|
-
method: "POST",
|
|
41
|
-
headers,
|
|
42
|
-
body: JSON.stringify(body),
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
return fetch(urlWithParams.toString(), options)
|
|
46
|
-
.then(async (response) => {
|
|
47
|
-
const data = await response.json().catch(() => ({}));
|
|
48
|
-
if (!response.ok) {
|
|
49
|
-
return {
|
|
50
|
-
err: data?.resultInfo?.message || "Something went wrong!",
|
|
51
|
-
status: response.status,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
return data;
|
|
55
|
-
})
|
|
56
|
-
.catch((error) => {
|
|
57
|
-
console.error("Fetch error:", error);
|
|
58
|
-
return { err: error.message || "Network error" };
|
|
59
|
-
});
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* SSO login: exchange idToken + email for app token.
|
|
64
|
-
* @param {string} apiBaseUrl - e.g. https://afiyaapiqa.powermindinc.com
|
|
65
|
-
* @param {string} hospitalId - e.g. dMtEGhak
|
|
66
|
-
* @param {string} idToken - JWT id token from auth provider
|
|
67
|
-
* @param {string} email - User email
|
|
68
|
-
* @returns {Promise<{ token?: string, err?: string, ... }>} - Response with token on success, or { err } on failure
|
|
69
|
-
*/
|
|
70
|
-
export const getTokenFromSso = async (apiBaseUrl, hospitalId, idToken, email) => {
|
|
71
|
-
const base = apiBaseUrl.replace(/\/$/, "");
|
|
72
|
-
const url = `${base}/um/user/V1/sso/login?hospitalId=${encodeURIComponent(hospitalId)}`;
|
|
73
|
-
|
|
74
|
-
const options = {
|
|
75
|
-
method: "POST",
|
|
76
|
-
headers: {
|
|
77
|
-
"Content-Type": "application/json",
|
|
78
|
-
},
|
|
79
|
-
body: JSON.stringify({ idToken, email }),
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
console.log("[getTokenFromSso] request", { url, body: { idToken: idToken ? idToken.slice(0, 50) + "..." : null, email } });
|
|
83
|
-
return fetch(url, options)
|
|
84
|
-
.then((response) => {
|
|
85
|
-
console.log("[getTokenFromSso] response status", response.status, response.statusText);
|
|
86
|
-
if (!response.ok) {
|
|
87
|
-
return response.json().then((errorData) => {
|
|
88
|
-
const errorMessage =
|
|
89
|
-
errorData?.resultInfo?.message || "SSO login failed";
|
|
90
|
-
console.log("[getTokenFromSso] error body", errorData);
|
|
91
|
-
return { err: errorMessage, status: response.status };
|
|
92
|
-
}).catch(() => ({ err: "Something went wrong!", status: response.status }));
|
|
93
|
-
}
|
|
94
|
-
return response.json().then((data) => {
|
|
95
|
-
console.log("[getTokenFromSso] success", { hasData: !!data, dataKeys: data ? Object.keys(data) : [], hasAccessToken: !!(data?.data?.access_token) });
|
|
96
|
-
return data;
|
|
97
|
-
});
|
|
98
|
-
})
|
|
99
|
-
.catch((error) => {
|
|
100
|
-
console.error("[getTokenFromSso] catch", error);
|
|
101
|
-
return { err: error.message || "Network error" };
|
|
102
|
-
});
|
|
103
|
-
};
|
|
1
|
+
export const getApi = async (url, params = {}, header, token = '') => {
|
|
2
|
+
const urlWithParams = new URL(url);
|
|
3
|
+
urlWithParams.search = new URLSearchParams(params).toString();
|
|
4
|
+
|
|
5
|
+
const options = {
|
|
6
|
+
method: "GET",
|
|
7
|
+
headers: {
|
|
8
|
+
"Content-Type": "application/json",
|
|
9
|
+
"Authorization": `${token}`,
|
|
10
|
+
// "X-CLIENT-APP": header,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
return fetch(urlWithParams, options)
|
|
15
|
+
.then(async (response) => {
|
|
16
|
+
const data = await response.json().catch(() => ({}));
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
return {
|
|
19
|
+
err: data?.resultInfo?.message || "Something went wrong!",
|
|
20
|
+
status: response.status,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return data;
|
|
24
|
+
})
|
|
25
|
+
.catch((error) => {
|
|
26
|
+
console.error("Fetch error:", error);
|
|
27
|
+
return { err: error?.message || String(error) || "Network error" };
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
export const postApi = async (url, body = {}, header, params = {}, token) => {
|
|
31
|
+
const urlWithParams = new URL(url);
|
|
32
|
+
Object.keys(params).forEach((key) => {
|
|
33
|
+
urlWithParams.searchParams.append(key, params[key]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const headers = { "Content-Type": "application/json" };
|
|
37
|
+
if (token) headers["Authorization"] = token;
|
|
38
|
+
|
|
39
|
+
const options = {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers,
|
|
42
|
+
body: JSON.stringify(body),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return fetch(urlWithParams.toString(), options)
|
|
46
|
+
.then(async (response) => {
|
|
47
|
+
const data = await response.json().catch(() => ({}));
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
return {
|
|
50
|
+
err: data?.resultInfo?.message || "Something went wrong!",
|
|
51
|
+
status: response.status,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return data;
|
|
55
|
+
})
|
|
56
|
+
.catch((error) => {
|
|
57
|
+
console.error("Fetch error:", error);
|
|
58
|
+
return { err: error.message || "Network error" };
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* SSO login: exchange idToken + email for app token.
|
|
64
|
+
* @param {string} apiBaseUrl - e.g. https://afiyaapiqa.powermindinc.com
|
|
65
|
+
* @param {string} hospitalId - e.g. dMtEGhak
|
|
66
|
+
* @param {string} idToken - JWT id token from auth provider
|
|
67
|
+
* @param {string} email - User email
|
|
68
|
+
* @returns {Promise<{ token?: string, err?: string, ... }>} - Response with token on success, or { err } on failure
|
|
69
|
+
*/
|
|
70
|
+
export const getTokenFromSso = async (apiBaseUrl, hospitalId, idToken, email) => {
|
|
71
|
+
const base = apiBaseUrl.replace(/\/$/, "");
|
|
72
|
+
const url = `${base}/um/user/V1/sso/login?hospitalId=${encodeURIComponent(hospitalId)}`;
|
|
73
|
+
|
|
74
|
+
const options = {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: {
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
},
|
|
79
|
+
body: JSON.stringify({ idToken, email }),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
console.log("[getTokenFromSso] request", { url, body: { idToken: idToken ? idToken.slice(0, 50) + "..." : null, email } });
|
|
83
|
+
return fetch(url, options)
|
|
84
|
+
.then((response) => {
|
|
85
|
+
console.log("[getTokenFromSso] response status", response.status, response.statusText);
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
return response.json().then((errorData) => {
|
|
88
|
+
const errorMessage =
|
|
89
|
+
errorData?.resultInfo?.message || "SSO login failed";
|
|
90
|
+
console.log("[getTokenFromSso] error body", errorData);
|
|
91
|
+
return { err: errorMessage, status: response.status };
|
|
92
|
+
}).catch(() => ({ err: "Something went wrong!", status: response.status }));
|
|
93
|
+
}
|
|
94
|
+
return response.json().then((data) => {
|
|
95
|
+
console.log("[getTokenFromSso] success", { hasData: !!data, dataKeys: data ? Object.keys(data) : [], hasAccessToken: !!(data?.data?.access_token) });
|
|
96
|
+
return data;
|
|
97
|
+
});
|
|
98
|
+
})
|
|
99
|
+
.catch((error) => {
|
|
100
|
+
console.error("[getTokenFromSso] catch", error);
|
|
101
|
+
return { err: error.message || "Network error" };
|
|
102
|
+
});
|
|
103
|
+
};
|