medos-sdk 1.1.5 → 1.1.7
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/dist/components/AppointmentCalender.js +13 -2
- package/dist/components/AppointmentConfirmationStep.d.ts +24 -0
- package/dist/components/AppointmentConfirmationStep.js +110 -0
- package/dist/components/ContactPreferenceStep.js +1 -7
- package/dist/components/EnquiryForm.js +3 -3
- package/dist/components/Icons/SuccessIcon.d.ts +8 -0
- package/dist/components/Icons/SuccessIcon.js +14 -0
- package/dist/services/EnquiryService.js +12 -12
- package/dist/services/WorkspaceService.d.ts +9 -0
- package/dist/services/WorkspaceService.js +17 -0
- package/dist/vanilla/AppointmentCalendarWidget.d.ts +4 -0
- package/dist/vanilla/AppointmentCalendarWidget.js +110 -9
- package/dist/vanilla/EnquiryFormWidget.d.ts +1 -0
- package/dist/vanilla/EnquiryFormWidget.js +74 -20
- package/dist/vanilla/components/AppointmentConfirmationStep.d.ts +24 -0
- package/dist/vanilla/components/Icons/SuccessIcon.d.ts +8 -0
- package/dist/vanilla/enquiry-widget.js +86 -32
- package/dist/vanilla/services/WorkspaceService.d.ts +9 -0
- package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +4 -0
- package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +1 -0
- package/dist/vanilla/widget.js +196 -41
- package/package.json +1 -1
|
@@ -6,12 +6,12 @@ import { AppointmentDateTimeModal } from "./AppointmentDateTimeModal";
|
|
|
6
6
|
import { DoctorSelectModal } from "./DoctorSelectModal";
|
|
7
7
|
import { PhoneVerificationStep } from "./PhoneVerificationStep";
|
|
8
8
|
import { PatientDetailsStep } from "./PatientDetailsStep";
|
|
9
|
-
import { SuccessStep } from "./SuccessStep";
|
|
10
9
|
import { INITIAL_STATE, } from "./types";
|
|
11
10
|
import { validatePhoneNumber, validateCountryCode } from "./validation";
|
|
12
11
|
import { formatDateToISO, parsePatientName } from "./utils";
|
|
13
12
|
import { useTheme } from "../react/hooks/useTheme";
|
|
14
13
|
import MedosLogo from "./Icons/MedosLogo";
|
|
14
|
+
import AppointmentConfirmationStep from "./AppointmentConfirmationStep";
|
|
15
15
|
const appointmentReducer = (state, action) => {
|
|
16
16
|
switch (action.type) {
|
|
17
17
|
case "SET_STEP":
|
|
@@ -365,7 +365,18 @@ export const AppointmentCalender = ({ onError, }) => {
|
|
|
365
365
|
}, []);
|
|
366
366
|
const theme = useTheme();
|
|
367
367
|
const styles = getStyles(theme);
|
|
368
|
-
return (_jsx("div", { style: styles.container, children: _jsxs("div", { style: styles.card, children: [_jsx("div", { style: styles.header, children: _jsx("h2", { style: styles.title, children: "Book Appointment" }) }), _jsx("hr", {}), _jsxs("div", { style: styles.content, children: [state.loading && _jsx("div", { style: { marginBottom: 12 }, children: "Loading..." }), state.error && _jsx("div", { style: styles.errorMessage, children: state.error }), state.step === 0 && (_jsx(DoctorSelectModal, { onCancel: () => dispatch({ type: "SET_STEP", payload: 0 }), onContinue: handleDoctorSelect })), state.step === 1 && (_jsx(AppointmentDateTimeModal, { onlineFee: 500, offlineFee: 300, slots: state.slots, onCancel: goBack, onDateChange: handleDateChange, onContinue: handleDateTimeModalContinue })), state.step === 3 && (_jsx(PhoneVerificationStep, { state: state, dispatch: dispatch, onSendOtp: sendOtp, onVerifyOtp: verifyOtp, onBack: goBack, onContinue: goToNext })), state.step === 4 && (_jsx(PatientDetailsStep, { state: state, dispatch: dispatch, onBack: goBack, onSubmit: submitAppointment })), state.step === 5 &&
|
|
368
|
+
return (_jsx("div", { style: styles.container, children: _jsxs("div", { style: styles.card, children: [_jsx("div", { style: styles.header, children: _jsx("h2", { style: styles.title, children: "Book Appointment" }) }), _jsx("hr", {}), _jsxs("div", { style: styles.content, children: [state.loading && _jsx("div", { style: { marginBottom: 12 }, children: "Loading..." }), state.error && _jsx("div", { style: styles.errorMessage, children: state.error }), state.step === 0 && (_jsx(DoctorSelectModal, { onCancel: () => dispatch({ type: "SET_STEP", payload: 0 }), onContinue: handleDoctorSelect })), state.step === 1 && (_jsx(AppointmentDateTimeModal, { onlineFee: 500, offlineFee: 300, slots: state.slots, onCancel: goBack, onDateChange: handleDateChange, onContinue: handleDateTimeModalContinue })), state.step === 3 && (_jsx(PhoneVerificationStep, { state: state, dispatch: dispatch, onSendOtp: sendOtp, onVerifyOtp: verifyOtp, onBack: goBack, onContinue: goToNext })), state.step === 4 && (_jsx(PatientDetailsStep, { state: state, dispatch: dispatch, onBack: goBack, onSubmit: submitAppointment })), state.step === 5 && (_jsx(AppointmentConfirmationStep, { appointment: {
|
|
369
|
+
patientName: state.patientName,
|
|
370
|
+
visitationType: state.consultationMode === "ONLINE" ? "Online Consultation" : "In-Person Visit",
|
|
371
|
+
appointmentDate: formatDateToISO(state.selectedDate),
|
|
372
|
+
fromTime: state.selectedSlot?.start ? new Date(state.selectedSlot.start).toTimeString().slice(0, 5) : "",
|
|
373
|
+
toTime: state.selectedSlot?.end ? new Date(state.selectedSlot.end).toTimeString().slice(0, 5) : "",
|
|
374
|
+
location: state.addresses.find(addr => addr.id === state.selectedAddress)?.label || "Clinic",
|
|
375
|
+
mode: state.consultationMode,
|
|
376
|
+
paymentMode: "Cash"
|
|
377
|
+
}, patient: {
|
|
378
|
+
patientName: state.patientName
|
|
379
|
+
}, onClose: resetForm })), _jsxs("div", { style: styles.branding, children: [_jsx("span", { style: styles.poweredBy, children: "Powered by" }), _jsx("a", { href: "https://medos.one", target: "_blank", rel: "noopener noreferrer", children: _jsx(MedosLogo, { style: { height: 50, width: "auto" } }) })] })] })] }) }));
|
|
369
380
|
};
|
|
370
381
|
const getStyles = (theme) => ({
|
|
371
382
|
container: {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface AppointmentDetails {
|
|
3
|
+
patientName?: string;
|
|
4
|
+
visitationType?: string;
|
|
5
|
+
appointmentDate?: string;
|
|
6
|
+
fromTime?: string;
|
|
7
|
+
toTime?: string;
|
|
8
|
+
duration?: number;
|
|
9
|
+
location?: string;
|
|
10
|
+
mode?: string;
|
|
11
|
+
paymentMode?: string;
|
|
12
|
+
}
|
|
13
|
+
interface AppointmentConfirmationStepProps {
|
|
14
|
+
appointment: AppointmentDetails;
|
|
15
|
+
patient: {
|
|
16
|
+
firstName?: string;
|
|
17
|
+
middleName?: string;
|
|
18
|
+
lastName?: string;
|
|
19
|
+
patientName?: string;
|
|
20
|
+
};
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
}
|
|
23
|
+
declare const AppointmentConfirmationStep: React.FC<AppointmentConfirmationStepProps>;
|
|
24
|
+
export default AppointmentConfirmationStep;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useTheme } from "../react/hooks/useTheme";
|
|
3
|
+
import { SuccessIcon } from "./Icons/SuccessIcon";
|
|
4
|
+
const AppointmentConfirmationStep = ({ appointment, patient, onClose, }) => {
|
|
5
|
+
const theme = useTheme();
|
|
6
|
+
const calculateDuration = () => {
|
|
7
|
+
if (appointment.duration)
|
|
8
|
+
return appointment.duration;
|
|
9
|
+
if (appointment.fromTime && appointment.toTime) {
|
|
10
|
+
const start = new Date(`2000-01-01T${appointment.fromTime}`);
|
|
11
|
+
const end = new Date(`2000-01-01T${appointment.toTime}`);
|
|
12
|
+
const diffMs = end.getTime() - start.getTime();
|
|
13
|
+
const diffMinutes = Math.round(diffMs / (1000 * 60));
|
|
14
|
+
return diffMinutes;
|
|
15
|
+
}
|
|
16
|
+
return 60;
|
|
17
|
+
};
|
|
18
|
+
const getPatientName = () => {
|
|
19
|
+
if (appointment.patientName)
|
|
20
|
+
return appointment.patientName;
|
|
21
|
+
if (patient.patientName)
|
|
22
|
+
return patient.patientName;
|
|
23
|
+
const parts = [patient.firstName, patient.middleName, patient.lastName].filter(Boolean);
|
|
24
|
+
return parts.join(" ") || "Patient";
|
|
25
|
+
};
|
|
26
|
+
const formatDate = (dateStr) => {
|
|
27
|
+
try {
|
|
28
|
+
const date = new Date(dateStr);
|
|
29
|
+
return date.toLocaleDateString('en-US', {
|
|
30
|
+
weekday: 'long',
|
|
31
|
+
year: 'numeric',
|
|
32
|
+
month: 'long',
|
|
33
|
+
day: 'numeric'
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return dateStr;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const formatTime = (timeStr) => {
|
|
41
|
+
try {
|
|
42
|
+
const time = new Date(`2000-01-01T${timeStr}`);
|
|
43
|
+
return time.toLocaleTimeString('en-US', {
|
|
44
|
+
hour: 'numeric',
|
|
45
|
+
minute: '2-digit',
|
|
46
|
+
hour12: true
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return timeStr;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const duration = calculateDuration();
|
|
54
|
+
const patientName = getPatientName();
|
|
55
|
+
return (_jsxs("div", { style: {
|
|
56
|
+
display: "flex",
|
|
57
|
+
flexDirection: "column",
|
|
58
|
+
padding: "0",
|
|
59
|
+
fontFamily: theme.typography.fontFamily,
|
|
60
|
+
background: theme.colors.background,
|
|
61
|
+
minHeight: "500px"
|
|
62
|
+
}, children: [_jsx("div", { style: {
|
|
63
|
+
padding: "20px 24px",
|
|
64
|
+
fontSize: 24,
|
|
65
|
+
fontWeight: "bold",
|
|
66
|
+
color: theme.colors.primary,
|
|
67
|
+
borderBottom: `2px solid ${theme.colors.border}`,
|
|
68
|
+
background: theme.colors.surface
|
|
69
|
+
}, children: "Appointment Confirmed" }), _jsxs("div", { style: {
|
|
70
|
+
flex: 1,
|
|
71
|
+
display: "flex",
|
|
72
|
+
flexDirection: "column",
|
|
73
|
+
alignItems: "center",
|
|
74
|
+
justifyContent: "center",
|
|
75
|
+
padding: "40px 24px",
|
|
76
|
+
border: `2px solid ${theme.colors.border}`,
|
|
77
|
+
borderTop: "none",
|
|
78
|
+
background: theme.colors.surface,
|
|
79
|
+
textAlign: "center"
|
|
80
|
+
}, children: [_jsx("h2", { style: {
|
|
81
|
+
fontSize: 20,
|
|
82
|
+
fontWeight: "600",
|
|
83
|
+
color: theme.colors.success,
|
|
84
|
+
margin: "0 0 24px 0"
|
|
85
|
+
}, children: "Appointment Confirmed" }), _jsx("div", { style: { marginBottom: 32 }, children: _jsx(SuccessIcon, { size: 64, checkColor: "white", shapeColor: theme.colors.success }) }), _jsxs("div", { style: {
|
|
86
|
+
width: "100%",
|
|
87
|
+
maxWidth: 500,
|
|
88
|
+
marginBottom: 32
|
|
89
|
+
}, children: [_jsx("h3", { style: {
|
|
90
|
+
fontSize: 18,
|
|
91
|
+
fontWeight: "600",
|
|
92
|
+
color: theme.colors.success,
|
|
93
|
+
marginBottom: 24
|
|
94
|
+
}, children: "Appointment Details" }), _jsxs("div", { style: {
|
|
95
|
+
display: "flex",
|
|
96
|
+
flexDirection: "column",
|
|
97
|
+
gap: 12,
|
|
98
|
+
fontSize: 16,
|
|
99
|
+
lineHeight: 1.6,
|
|
100
|
+
color: theme.colors.text
|
|
101
|
+
}, children: [_jsxs("div", { children: [_jsx("strong", { style: { color: theme.colors.success }, children: "Patient:" }), " ", patientName] }), appointment.visitationType && (_jsxs("div", { children: [_jsx("strong", { style: { color: theme.colors.success }, children: "Visitation Type:" }), " ", appointment.visitationType] })), appointment.appointmentDate && (_jsxs("div", { children: [_jsx("strong", { style: { color: theme.colors.success }, children: "Date:" }), " ", formatDate(appointment.appointmentDate)] })), appointment.fromTime && (_jsxs("div", { children: [_jsx("strong", { style: { color: theme.colors.success }, children: "Time:" }), " ", formatTime(appointment.fromTime)] })), _jsxs("div", { children: [_jsx("strong", { style: { color: theme.colors.success }, children: "Duration:" }), " ~", duration, " minutes"] }), appointment.location && (_jsxs("div", { children: [_jsx("strong", { style: { color: theme.colors.success }, children: "Location:" }), " ", appointment.location] }))] })] }), _jsx("div", { style: {
|
|
102
|
+
fontSize: 16,
|
|
103
|
+
fontStyle: "italic",
|
|
104
|
+
color: theme.colors.textSecondary,
|
|
105
|
+
textAlign: "center",
|
|
106
|
+
maxWidth: 600,
|
|
107
|
+
lineHeight: 1.5
|
|
108
|
+
}, children: "A confirmation email has been sent to the Patient's Email address." })] })] }));
|
|
109
|
+
};
|
|
110
|
+
export default AppointmentConfirmationStep;
|
|
@@ -6,11 +6,5 @@ export const ContactPreferenceStep = ({ preferredContactMethod, onContactMethodC
|
|
|
6
6
|
const PHONE_VERIFY_STYLES = getPhoneVerifyStyles(theme);
|
|
7
7
|
const BUTTON_STYLES = getButtonStyles(theme);
|
|
8
8
|
const CONTAINER_STYLES = getContainerStyles(theme);
|
|
9
|
-
return (_jsxs("div", { children: [_jsxs("div", { style: { marginBottom: "16px" }, children: [_jsx("label", { style: PHONE_VERIFY_STYLES.label, children: "Preferred Contact Method" }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [_jsxs("label", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsx("input", { type: "radio", name: "contactMethod", value: "PHONE", checked: preferredContactMethod === "PHONE", onChange: (e) => onContactMethodChange(e.target.value) }), "Phone"] }), _jsxs("label", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsx("input", { type: "radio", name: "contactMethod", value: "EMAIL", checked: preferredContactMethod === "EMAIL", onChange: (e) => onContactMethodChange(e.target.value) }), "Email"] }), _jsxs("label", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsx("input", { type: "radio", name: "contactMethod", value: "BOTH", checked: preferredContactMethod === "BOTH", onChange: (e) => onContactMethodChange(e.target.value) }), "Both"] })] })] }), _jsxs("div", { style: CONTAINER_STYLES.actions, children: [_jsx("button", { onClick: onBack, style: BUTTON_STYLES.secondary, children: "Back" }), _jsx("button", { onClick: onSubmit,
|
|
10
|
-
...BUTTON_STYLES.primary,
|
|
11
|
-
backgroundColor: isLoading
|
|
12
|
-
? "#ccc"
|
|
13
|
-
: BUTTON_STYLES.primary.backgroundColor,
|
|
14
|
-
cursor: isLoading ? "not-allowed" : "pointer",
|
|
15
|
-
}, children: isLoading ? "Submitting..." : "Submit" })] })] }));
|
|
9
|
+
return (_jsxs("div", { children: [_jsxs("div", { style: { marginBottom: "16px" }, children: [_jsx("label", { style: PHONE_VERIFY_STYLES.label, children: "Preferred Contact Method" }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [_jsxs("label", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsx("input", { type: "radio", name: "contactMethod", value: "PHONE", checked: preferredContactMethod === "PHONE", onChange: (e) => onContactMethodChange(e.target.value) }), "Phone"] }), _jsxs("label", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsx("input", { type: "radio", name: "contactMethod", value: "EMAIL", checked: preferredContactMethod === "EMAIL", onChange: (e) => onContactMethodChange(e.target.value) }), "Email"] }), _jsxs("label", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsx("input", { type: "radio", name: "contactMethod", value: "BOTH", checked: preferredContactMethod === "BOTH", onChange: (e) => onContactMethodChange(e.target.value) }), "Both"] })] })] }), _jsxs("div", { style: CONTAINER_STYLES.actions, children: [_jsx("button", { onClick: onBack, style: BUTTON_STYLES.secondary, children: "Back" }), _jsx("button", { onClick: onSubmit, style: BUTTON_STYLES.primary, children: isLoading ? "Submitting..." : "Submit" })] })] }));
|
|
16
10
|
};
|
|
@@ -120,6 +120,9 @@ export const EnquiryForm = ({ onSuccess, onError, }) => {
|
|
|
120
120
|
const goBack = useCallback(() => {
|
|
121
121
|
dispatch({ type: "SET_STEP", payload: Math.max(0, state.step - 1) });
|
|
122
122
|
}, [state.step]);
|
|
123
|
+
const resetForm = useCallback(() => {
|
|
124
|
+
dispatch({ type: "RESET_FORM" });
|
|
125
|
+
}, []);
|
|
123
126
|
const submitEnquiry = useCallback(async () => {
|
|
124
127
|
dispatch({ type: "SET_ERROR", payload: null });
|
|
125
128
|
if (!validateContactStep() || !validateInquiryStep()) {
|
|
@@ -149,9 +152,6 @@ export const EnquiryForm = ({ onSuccess, onError, }) => {
|
|
|
149
152
|
dispatch({ type: "SET_LOADING", payload: false });
|
|
150
153
|
}
|
|
151
154
|
}, [state, validateContactStep, validateInquiryStep, onSuccess, onError]);
|
|
152
|
-
const resetForm = useCallback(() => {
|
|
153
|
-
dispatch({ type: "RESET_FORM" });
|
|
154
|
-
}, []);
|
|
155
155
|
const theme = useTheme();
|
|
156
156
|
const styles = getStyles(theme);
|
|
157
157
|
return (_jsx("div", { style: styles.container, children: _jsxs("div", { style: styles.card, children: [_jsxs("div", { style: styles.header, children: [_jsx("h2", { style: styles.title, children: "Submit Inquiry" }), _jsxs("p", { style: styles.stepIndicator, children: ["Step ", state.step + 1, " of 4"] })] }), _jsxs("div", { style: styles.content, children: [state.loading && _jsx("div", { style: { marginBottom: 12 }, children: "Loading..." }), state.error && _jsx("div", { style: styles.errorMessage, children: state.error }), state.step === 0 && (_jsx(ContactInformationStep, { patientName: state.patientName, patientEmail: state.patientEmail, countryCode: state.countryCode, patientPhone: state.patientPhone, onNameChange: (value) => dispatch({ type: "SET_PATIENT_NAME", payload: value }), onEmailChange: (value) => dispatch({ type: "SET_PATIENT_EMAIL", payload: value }), onCountryCodeChange: (value) => dispatch({ type: "SET_COUNTRY_CODE", payload: value }), onPhoneChange: (value) => dispatch({ type: "SET_PATIENT_PHONE", payload: value }), onNext: goToNext })), state.step === 1 && (_jsx(InquiryDetailsStep, { inquirySubject: state.inquirySubject, inquiryMessage: state.inquiryMessage, onSubjectChange: (value) => dispatch({ type: "SET_INQUIRY_SUBJECT", payload: value }), onMessageChange: (value) => dispatch({ type: "SET_INQUIRY_MESSAGE", payload: value }), onBack: goBack, onNext: goToNext })), state.step === 2 && (_jsx(ContactPreferenceStep, { preferredContactMethod: state.preferredContactMethod, onContactMethodChange: (method) => dispatch({
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export const SuccessIcon = ({ size = 64, checkColor = "white", shapeColor = "#006E0F", }) => {
|
|
3
|
+
const checkScale = size / 41;
|
|
4
|
+
const checkSize = {
|
|
5
|
+
width: 16 * checkScale,
|
|
6
|
+
height: 12 * checkScale,
|
|
7
|
+
};
|
|
8
|
+
return (_jsxs("div", { style: { position: "relative", display: "inline-block" }, children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 41 41", fill: "none", children: _jsx("path", { d: "M31.1309 4.90254C32.388 4.98797 33.0166 5.03069 33.5247 5.25288C34.2598 5.57438 34.8467 6.16126 35.1682 6.8964C35.3904 7.40445 35.4331 8.03302 35.5185 9.29016L35.7135 12.159C35.748 12.6674 35.7653 12.9217 35.8206 13.1645C35.9004 13.5154 36.0391 13.8503 36.2308 14.1549C36.3634 14.3657 36.531 14.5576 36.8661 14.9416L38.7568 17.108C39.5853 18.0574 39.9996 18.532 40.2017 19.0484C40.4942 19.7955 40.4942 20.6255 40.2017 21.3727C39.9996 21.889 39.5853 22.3637 38.7568 23.313L36.8661 25.4795C36.531 25.8634 36.3634 26.0554 36.2308 26.2662C36.0391 26.5708 35.9004 26.9056 35.8206 27.2566C35.7653 27.4994 35.748 27.7536 35.7135 28.2621L35.5185 31.1309C35.4331 32.388 35.3904 33.0166 35.1682 33.5247C34.8467 34.2598 34.2598 34.8467 33.5247 35.1682C33.0166 35.3904 32.388 35.4331 31.1309 35.5185L28.2621 35.7135C27.7536 35.748 27.4994 35.7653 27.2566 35.8206C26.9056 35.9004 26.5708 36.0391 26.2662 36.2308C26.0554 36.3634 25.8634 36.531 25.4795 36.8661L23.313 38.7568C22.3637 39.5853 21.889 39.9996 21.3727 40.2017C20.6255 40.4942 19.7955 40.4942 19.0484 40.2017C18.532 39.9996 18.0574 39.5853 17.108 38.7568L14.9416 36.8661C14.5576 36.531 14.3657 36.3634 14.1549 36.2308C13.8503 36.0391 13.5154 35.9004 13.1645 35.8206C12.9217 35.7653 12.6674 35.748 12.159 35.7135L9.29016 35.5185C8.03302 35.4331 7.40445 35.3904 6.8964 35.1682C6.16126 34.8467 5.57438 34.2598 5.25288 33.5247C5.03069 33.0166 4.98797 32.388 4.90254 31.1309L4.70759 28.2621C4.67304 27.7536 4.65576 27.4994 4.60049 27.2566C4.52063 26.9056 4.38193 26.5708 4.19028 26.2662C4.05764 26.0554 3.89009 25.8634 3.555 25.4795L1.66428 23.313C0.83576 22.3637 0.421499 21.889 0.219363 21.3727C-0.073121 20.6255 -0.0731209 19.7955 0.219363 19.0484C0.421499 18.532 0.83576 18.0574 1.66428 17.108L3.555 14.9416C3.89009 14.5576 4.05764 14.3657 4.19027 14.1549C4.38193 13.8503 4.52063 13.5154 4.60049 13.1645C4.65576 12.9217 4.67304 12.6674 4.70759 12.159L4.90254 9.29016C4.98797 8.03302 5.03069 7.40445 5.25288 6.8964C5.57438 6.16126 6.16126 5.57438 6.8964 5.25288C7.40445 5.03069 8.03302 4.98797 9.29016 4.90254L12.159 4.70759C12.6674 4.67304 12.9217 4.65577 13.1645 4.6005C13.5154 4.52063 13.8503 4.38193 14.1549 4.19028C14.3657 4.05764 14.5576 3.89009 14.9416 3.555L17.108 1.66428C18.0574 0.83576 18.532 0.421499 19.0484 0.219363C19.7955 -0.073121 20.6255 -0.073121 21.3727 0.219363C21.889 0.421499 22.3637 0.83576 23.313 1.66428L25.4795 3.555C25.8634 3.89009 26.0554 4.05764 26.2662 4.19028C26.5708 4.38193 26.9056 4.52063 27.2566 4.6005C27.4994 4.65577 27.7536 4.67304 28.2621 4.70759L31.1309 4.90254Z", fill: shapeColor }) }), _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: checkSize.width, height: checkSize.height, viewBox: "0 0 16 12", fill: "none", style: {
|
|
9
|
+
position: "absolute",
|
|
10
|
+
top: "50%",
|
|
11
|
+
left: "50%",
|
|
12
|
+
transform: "translate(-50%, -50%)",
|
|
13
|
+
}, children: _jsx("path", { d: "M5.472 11.544L0 6.072L1.368 4.704L5.472 8.808L14.28 0L15.648 1.368L5.472 11.544Z", fill: checkColor }) })] }));
|
|
14
|
+
};
|
|
@@ -3,20 +3,20 @@ const EnquiryService = {
|
|
|
3
3
|
async submitEnquiry(payload) {
|
|
4
4
|
try {
|
|
5
5
|
const client = await MedosClient.ensureInitialized();
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
preferredContactMethod: payload.preferredContactMethod,
|
|
6
|
+
const enquiryPayload = {
|
|
7
|
+
type: "ENQUIRY",
|
|
8
|
+
subject: payload.inquirySubject,
|
|
9
|
+
description: payload.inquiryMessage,
|
|
10
|
+
senderName: payload.patientName,
|
|
11
|
+
senderEmail: payload.patientEmail,
|
|
12
|
+
senderPhone: `${payload.countryCode}${payload.patientPhone}`,
|
|
14
13
|
};
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
14
|
+
const formData = new FormData();
|
|
15
|
+
const jsonBlob = new Blob([JSON.stringify(enquiryPayload)], {
|
|
16
|
+
type: "application/json",
|
|
19
17
|
});
|
|
18
|
+
formData.append("payload", jsonBlob);
|
|
19
|
+
const res = await client.post("/inbox/create", formData);
|
|
20
20
|
return res.data;
|
|
21
21
|
}
|
|
22
22
|
catch (error) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MedosClient } from "../client/MedosClient";
|
|
2
|
+
const WorkspaceService = {
|
|
3
|
+
async fetchWorkspace() {
|
|
4
|
+
try {
|
|
5
|
+
const client = await MedosClient.ensureInitialized();
|
|
6
|
+
const res = await client.get("/workspaces");
|
|
7
|
+
if (!res.data || typeof res.data.id !== "number") {
|
|
8
|
+
throw new Error("Invalid workspace response");
|
|
9
|
+
}
|
|
10
|
+
return res.data;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
throw new Error(`Failed to fetch workspace: ${error.message}`);
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
export { WorkspaceService };
|
|
@@ -32,6 +32,10 @@ declare class AppointmentCalendarWidget {
|
|
|
32
32
|
private renderStep2;
|
|
33
33
|
private renderStep3;
|
|
34
34
|
private renderStep4;
|
|
35
|
+
private renderSuccessIcon;
|
|
36
|
+
private formatDate;
|
|
37
|
+
private formatTime;
|
|
38
|
+
private calculateDuration;
|
|
35
39
|
private renderStep5;
|
|
36
40
|
private attachEventListeners;
|
|
37
41
|
private escapeHtml;
|
|
@@ -382,9 +382,10 @@ class AppointmentCalendarWidget {
|
|
|
382
382
|
this.state.step = Math.max(0, this.state.step - 1);
|
|
383
383
|
this.render();
|
|
384
384
|
}
|
|
385
|
-
reset() {
|
|
385
|
+
async reset() {
|
|
386
386
|
this.state = { ...INITIAL_STATE };
|
|
387
387
|
this.doctors = [];
|
|
388
|
+
await this.loadAddresses();
|
|
388
389
|
this.render();
|
|
389
390
|
}
|
|
390
391
|
setState(updates) {
|
|
@@ -639,19 +640,119 @@ class AppointmentCalendarWidget {
|
|
|
639
640
|
</div>
|
|
640
641
|
`;
|
|
641
642
|
}
|
|
643
|
+
renderSuccessIcon() {
|
|
644
|
+
return `
|
|
645
|
+
<div style="position: relative; display: inline-block;">
|
|
646
|
+
<svg width="64" height="64" viewBox="0 0 41 41" fill="none">
|
|
647
|
+
<path
|
|
648
|
+
d="M31.1309 4.90254C32.388 4.98797 33.0166 5.03069 33.5247 5.25288C34.2598 5.57438 34.8467 6.16126 35.1682 6.8964C35.3904 7.40445 35.4331 8.03302 35.5185 9.29016L35.7135 12.159C35.748 12.6674 35.7653 12.9217 35.8206 13.1645C35.9004 13.5154 36.0391 13.8503 36.2308 14.1549C36.3634 14.3657 36.531 14.5576 36.8661 14.9416L38.7568 17.108C39.5853 18.0574 39.9996 18.532 40.2017 19.0484C40.4942 19.7955 40.4942 20.6255 40.2017 21.3727C39.9996 21.889 39.5853 22.3637 38.7568 23.313L36.8661 25.4795C36.531 25.8634 36.3634 26.0554 36.2308 26.2662C36.0391 26.5708 35.9004 26.9056 35.8206 27.2566C35.7653 27.4994 35.748 27.7536 35.7135 28.2621L35.5185 31.1309C35.4331 32.388 35.3904 33.0166 35.1682 33.5247C34.8467 34.2598 34.2598 34.8467 33.5247 35.1682C33.0166 35.3904 32.388 35.4331 31.1309 35.5185L28.2621 35.7135C27.7536 35.748 27.4994 35.7653 27.2566 35.8206C26.9056 35.9004 26.5708 36.0391 26.2662 36.2308C26.0554 36.3634 25.8634 36.531 25.4795 36.8661L23.313 38.7568C22.3637 39.5853 21.889 39.9996 21.3727 40.2017C20.6255 40.4942 19.7955 40.4942 19.0484 40.2017C18.532 39.9996 18.0574 39.5853 17.108 38.7568L14.9416 36.8661C14.5576 36.531 14.3657 36.3634 14.1549 36.2308C13.8503 36.0391 13.5154 35.9004 13.1645 35.8206C12.9217 35.7653 12.6674 35.748 12.159 35.7135L9.29016 35.5185C8.03302 35.4331 7.40445 35.3904 6.8964 35.1682C6.16126 34.8467 5.57438 34.2598 5.25288 33.5247C5.03069 33.0166 4.98797 32.388 4.90254 31.1309L4.70759 28.2621C4.67304 27.7536 4.65576 27.4994 4.60049 27.2566C4.52063 26.9056 4.38193 26.5708 4.19028 26.2662C4.05764 26.0554 3.89009 25.8634 3.555 25.4795L1.66428 23.313C0.83576 22.3637 0.421499 21.889 0.219363 21.3727C-0.073121 20.6255 -0.0731209 19.7955 0.219363 19.0484C0.421499 18.532 0.83576 18.0574 1.66428 17.108L3.555 14.9416C3.89009 14.5576 4.05764 14.3657 4.19027 14.1549C4.38193 13.8503 4.52063 13.5154 4.60049 13.1645C4.65576 12.9217 4.67304 12.6674 4.70759 12.159L4.90254 9.29016C4.98797 8.03302 5.03069 7.40445 5.25288 6.8964C5.57438 6.16126 6.16126 5.57438 6.8964 5.25288C7.40445 5.03069 8.03302 4.98797 9.29016 4.90254L12.159 4.70759C12.6674 4.67304 12.9217 4.65577 13.1645 4.6005C13.5154 4.52063 13.8503 4.38193 14.1549 4.19028C14.3657 4.05764 14.5576 3.89009 14.9416 3.555L17.108 1.66428C18.0574 0.83576 18.532 0.421499 19.0484 0.219363C19.7955 -0.073121 20.6255 -0.073121 21.3727 0.219363C21.889 0.421499 22.3637 0.83576 23.313 1.66428L25.4795 3.555C25.8634 3.89009 26.0554 4.05764 26.2662 4.19028C26.5708 4.38193 26.9056 4.52063 27.2566 4.6005C27.4994 4.65577 27.7536 4.67304 28.2621 4.70759L31.1309 4.90254Z"
|
|
649
|
+
fill="#006E0F"
|
|
650
|
+
/>
|
|
651
|
+
</svg>
|
|
652
|
+
<svg width="16" height="12" viewBox="0 0 16 12" fill="none" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
|
653
|
+
<path
|
|
654
|
+
d="M5.472 11.544L0 6.072L1.368 4.704L5.472 8.808L14.28 0L15.648 1.368L5.472 11.544Z"
|
|
655
|
+
fill="white"
|
|
656
|
+
/>
|
|
657
|
+
</svg>
|
|
658
|
+
</div>
|
|
659
|
+
`;
|
|
660
|
+
}
|
|
661
|
+
formatDate(dateStr) {
|
|
662
|
+
try {
|
|
663
|
+
const date = new Date(dateStr);
|
|
664
|
+
return date.toLocaleDateString("en-US", {
|
|
665
|
+
weekday: "long",
|
|
666
|
+
year: "numeric",
|
|
667
|
+
month: "long",
|
|
668
|
+
day: "numeric",
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
catch {
|
|
672
|
+
return dateStr;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
formatTime(timeStr) {
|
|
676
|
+
try {
|
|
677
|
+
const time = new Date(`2000-01-01T${timeStr}`);
|
|
678
|
+
return time.toLocaleTimeString("en-US", {
|
|
679
|
+
hour: "numeric",
|
|
680
|
+
minute: "2-digit",
|
|
681
|
+
hour12: true,
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
catch {
|
|
685
|
+
return timeStr;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
calculateDuration() {
|
|
689
|
+
if (this.state.selectedSlot) {
|
|
690
|
+
const start = new Date(this.state.selectedSlot.start);
|
|
691
|
+
const end = new Date(this.state.selectedSlot.end);
|
|
692
|
+
const diffMs = end.getTime() - start.getTime();
|
|
693
|
+
return Math.round(diffMs / (1000 * 60));
|
|
694
|
+
}
|
|
695
|
+
return 60;
|
|
696
|
+
}
|
|
642
697
|
renderStep5() {
|
|
698
|
+
const duration = this.calculateDuration();
|
|
699
|
+
const selectedAddress = this.state.addresses.find((addr) => addr.id === this.state.selectedAddress);
|
|
700
|
+
const appointmentDate = this.state.selectedDate
|
|
701
|
+
? this.formatDate(formatDateToISO(this.state.selectedDate))
|
|
702
|
+
: "";
|
|
703
|
+
const startTime = this.state.selectedSlot?.start
|
|
704
|
+
? this.formatTime(new Date(this.state.selectedSlot.start).toTimeString().slice(0, 5))
|
|
705
|
+
: "";
|
|
643
706
|
return `
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
707
|
+
<div style="display: flex; flex-direction: column; padding: 0; font-family: Arial, sans-serif; background: #f8f9fa; min-height: 500px;">
|
|
708
|
+
<!-- Header with border -->
|
|
709
|
+
<div style="padding: 20px 24px; font-size: 24px; font-weight: bold; color: #1a365d; border-bottom: 2px solid #e2e8f0; background: white;">
|
|
710
|
+
Appointment Confirmed
|
|
711
|
+
</div>
|
|
712
|
+
|
|
713
|
+
<!-- Main content with border -->
|
|
714
|
+
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 24px; border: 2px solid #e2e8f0; border-top: none; background: white; text-align: center;">
|
|
715
|
+
<!-- Success Title -->
|
|
716
|
+
<h2 style="font-size: 20px; font-weight: 600; color: #006E0F; margin: 0 0 24px 0;">
|
|
717
|
+
Appointment Confirmed
|
|
718
|
+
</h2>
|
|
719
|
+
|
|
720
|
+
<!-- Success Icon -->
|
|
721
|
+
<div style="margin-bottom: 32px;">
|
|
722
|
+
${this.renderSuccessIcon()}
|
|
723
|
+
</div>
|
|
724
|
+
|
|
725
|
+
<!-- Appointment Details -->
|
|
726
|
+
<div style="width: 100%; max-width: 500px; margin-bottom: 32px;">
|
|
727
|
+
<h3 style="font-size: 18px; font-weight: 600; color: #006E0F; margin-bottom: 24px;">
|
|
728
|
+
Appointment Details
|
|
729
|
+
</h3>
|
|
730
|
+
|
|
731
|
+
<div style="display: flex; flex-direction: column; gap: 12px; font-size: 16px; line-height: 1.6; color: #4a5568;">
|
|
732
|
+
<div><strong style="color: #006E0F;">Patient:</strong> ${this.escapeHtml(this.state.patientName || "Patient")}</div>
|
|
733
|
+
<div><strong style="color: #006E0F;">Visitation Type:</strong> ${this.state.consultationMode === "ONLINE"
|
|
734
|
+
? "Online Consultation"
|
|
735
|
+
: "General"}</div>
|
|
736
|
+
${appointmentDate
|
|
737
|
+
? `<div><strong style="color: #006E0F;">Date:</strong> ${appointmentDate}</div>`
|
|
738
|
+
: ""}
|
|
739
|
+
${startTime
|
|
740
|
+
? `<div><strong style="color: #006E0F;">Time:</strong> ${startTime}</div>`
|
|
741
|
+
: ""}
|
|
742
|
+
<div><strong style="color: #006E0F;">Duration:</strong> ~${duration} minutes</div>
|
|
743
|
+
${selectedAddress?.label
|
|
744
|
+
? `<div><strong style="color: #006E0F;">Location:</strong> ${this.escapeHtml(selectedAddress.label)}</div>`
|
|
745
|
+
: ""}
|
|
746
|
+
</div>
|
|
649
747
|
</div>
|
|
650
|
-
|
|
651
|
-
|
|
748
|
+
|
|
749
|
+
<!-- Confirmation Message -->
|
|
750
|
+
<div style="font-size: 16px; font-style: italic; color: #718096; text-align: center; max-width: 600px; line-height: 1.5;">
|
|
751
|
+
A confirmation email has been sent to the Patient's Email address.
|
|
652
752
|
</div>
|
|
653
753
|
</div>
|
|
654
|
-
|
|
754
|
+
</div>
|
|
755
|
+
`;
|
|
655
756
|
}
|
|
656
757
|
attachEventListeners() {
|
|
657
758
|
const addressSelect = this.container.querySelector("#medos-address-select");
|
|
@@ -125,6 +125,9 @@ class EnquiryFormWidget {
|
|
|
125
125
|
await EnquiryService.submitEnquiry(payload);
|
|
126
126
|
this.state.step = 3;
|
|
127
127
|
this.options.onSuccess?.(payload);
|
|
128
|
+
setTimeout(() => {
|
|
129
|
+
this.resetForm();
|
|
130
|
+
}, 5000);
|
|
128
131
|
}
|
|
129
132
|
catch (e) {
|
|
130
133
|
const msg = e.message || "Failed to submit enquiry";
|
|
@@ -161,16 +164,20 @@ class EnquiryFormWidget {
|
|
|
161
164
|
this.container.innerHTML = `
|
|
162
165
|
<div class="medos-enquiry-container">
|
|
163
166
|
<div class="medos-enquiry-card">
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
<
|
|
167
|
-
|
|
167
|
+
${this.state.step !== 3
|
|
168
|
+
? `
|
|
169
|
+
<div class="medos-enquiry-header">
|
|
170
|
+
<h2 class="medos-enquiry-title">Submit Inquiry</h2>
|
|
171
|
+
<p class="medos-enquiry-step-indicator">Step ${this.state.step + 1} of 4</p>
|
|
172
|
+
</div>
|
|
168
173
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
+
${this.state.loading
|
|
175
|
+
? '<div class="medos-enquiry-loading">Loading...</div>'
|
|
176
|
+
: ""}
|
|
177
|
+
${this.state.error
|
|
178
|
+
? `<div class="medos-enquiry-error">${this.escapeHtml(this.state.error)}</div>`
|
|
179
|
+
: ""}
|
|
180
|
+
`
|
|
174
181
|
: ""}
|
|
175
182
|
|
|
176
183
|
${this.renderStep()}
|
|
@@ -314,18 +321,69 @@ class EnquiryFormWidget {
|
|
|
314
321
|
}
|
|
315
322
|
renderStep3() {
|
|
316
323
|
return `
|
|
317
|
-
<div
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
<div class="medos-enquiry-success-message">Thank you, ${this.escapeHtml(this.state.patientName || "Patient")}. We have received your inquiry and will get back to you soon.</div>
|
|
324
|
+
<div style="display: flex; flex-direction: column; padding: 0; font-family: Arial, sans-serif; background: #f8f9fa; min-height: 500px;">
|
|
325
|
+
<!-- Header with border -->
|
|
326
|
+
<div style="padding: 20px 24px; font-size: 24px; font-weight: bold; color: #1a365d; border-bottom: 2px solid #e2e8f0; background: white;">
|
|
327
|
+
Inquiry Confirmed
|
|
322
328
|
</div>
|
|
323
|
-
|
|
324
|
-
|
|
329
|
+
|
|
330
|
+
<!-- Main content with border -->
|
|
331
|
+
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 24px; border: 2px solid #e2e8f0; border-top: none; background: white; text-align: center;">
|
|
332
|
+
<!-- Success Title -->
|
|
333
|
+
<h2 style="font-size: 20px; font-weight: 600; color: #006E0F; margin: 0 0 24px 0;">
|
|
334
|
+
Inquiry Submitted Successfully
|
|
335
|
+
</h2>
|
|
336
|
+
|
|
337
|
+
<!-- Success Icon -->
|
|
338
|
+
<div style="margin-bottom: 32px;">
|
|
339
|
+
${this.renderSuccessIcon()}
|
|
340
|
+
</div>
|
|
341
|
+
|
|
342
|
+
<!-- Inquiry Details -->
|
|
343
|
+
<div style="width: 100%; max-width: 500px; margin-bottom: 32px;">
|
|
344
|
+
<h3 style="font-size: 18px; font-weight: 600; color: #006E0F; margin-bottom: 24px;">
|
|
345
|
+
Inquiry Details
|
|
346
|
+
</h3>
|
|
347
|
+
|
|
348
|
+
<div style="display: flex; flex-direction: column; gap: 12px; font-size: 16px; line-height: 1.6; color: #4a5568;">
|
|
349
|
+
<div><strong style="color: #006E0F;">Name:</strong> ${this.escapeHtml(this.state.patientName || "Patient")}</div>
|
|
350
|
+
<div><strong style="color: #006E0F;">Email:</strong> ${this.escapeHtml(this.state.patientEmail)}</div>
|
|
351
|
+
<div><strong style="color: #006E0F;">Phone:</strong> ${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</div>
|
|
352
|
+
<div><strong style="color: #006E0F;">Subject:</strong> ${this.escapeHtml(this.state.inquirySubject)}</div>
|
|
353
|
+
<div><strong style="color: #006E0F;">Preferred Contact:</strong> ${this.state.preferredContactMethod === "PHONE"
|
|
354
|
+
? "Phone"
|
|
355
|
+
: this.state.preferredContactMethod === "EMAIL"
|
|
356
|
+
? "Email"
|
|
357
|
+
: "Both"}</div>
|
|
358
|
+
</div>
|
|
359
|
+
</div>
|
|
360
|
+
|
|
361
|
+
<!-- Confirmation Message -->
|
|
362
|
+
<div style="font-size: 16px; font-style: italic; color: #718096; text-align: center; max-width: 600px; line-height: 1.5;">
|
|
363
|
+
Thank you for your inquiry. We have received your message and will get back to you soon via your preferred contact method.
|
|
364
|
+
</div>
|
|
325
365
|
</div>
|
|
326
366
|
</div>
|
|
327
367
|
`;
|
|
328
368
|
}
|
|
369
|
+
renderSuccessIcon() {
|
|
370
|
+
return `
|
|
371
|
+
<div style="position: relative; display: inline-block;">
|
|
372
|
+
<svg width="64" height="64" viewBox="0 0 41 41" fill="none">
|
|
373
|
+
<path
|
|
374
|
+
d="M31.1309 4.90254C32.388 4.98797 33.0166 5.03069 33.5247 5.25288C34.2598 5.57438 34.8467 6.16126 35.1682 6.8964C35.3904 7.40445 35.4331 8.03302 35.5185 9.29016L35.7135 12.159C35.748 12.6674 35.7653 12.9217 35.8206 13.1645C35.9004 13.5154 36.0391 13.8503 36.2308 14.1549C36.3634 14.3657 36.531 14.5576 36.8661 14.9416L38.7568 17.108C39.5853 18.0574 39.9996 18.532 40.2017 19.0484C40.4942 19.7955 40.4942 20.6255 40.2017 21.3727C39.9996 21.889 39.5853 22.3637 38.7568 23.313L36.8661 25.4795C36.531 25.8634 36.3634 26.0554 36.2308 26.2662C36.0391 26.5708 35.9004 26.9056 35.8206 27.2566C35.7653 27.4994 35.748 27.7536 35.7135 28.2621L35.5185 31.1309C35.4331 32.388 35.3904 33.0166 35.1682 33.5247C34.8467 34.2598 34.2598 34.8467 33.5247 35.1682C33.0166 35.3904 32.388 35.4331 31.1309 35.5185L28.2621 35.7135C27.7536 35.748 27.4994 35.7653 27.2566 35.8206C26.9056 35.9004 26.5708 36.0391 26.2662 36.2308C26.0554 36.3634 25.8634 36.531 25.4795 36.8661L23.313 38.7568C22.3637 39.5853 21.889 39.9996 21.3727 40.2017C20.6255 40.4942 19.7955 40.4942 19.0484 40.2017C18.532 39.9996 18.0574 39.5853 17.108 38.7568L14.9416 36.8661C14.5576 36.531 14.3657 36.3634 14.1549 36.2308C13.8503 36.0391 13.5154 35.9004 13.1645 35.8206C12.9217 35.7653 12.6674 35.748 12.159 35.7135L9.29016 35.5185C8.03302 35.4331 7.40445 35.3904 6.8964 35.1682C6.16126 34.8467 5.57438 34.2598 5.25288 33.5247C5.03069 33.0166 4.98797 32.388 4.90254 31.1309L4.70759 28.2621C4.67304 27.7536 4.65576 27.4994 4.60049 27.2566C4.52063 26.9056 4.38193 26.5708 4.19028 26.2662C4.05764 26.0554 3.89009 25.8634 3.555 25.4795L1.66428 23.313C0.83576 22.3637 0.421499 21.889 0.219363 21.3727C-0.073121 20.6255 -0.0731209 19.7955 0.219363 19.0484C0.421499 18.532 0.83576 18.0574 1.66428 17.108L3.555 14.9416C3.89009 14.5576 4.05764 14.3657 4.19027 14.1549C4.38193 13.8503 4.52063 13.5154 4.60049 13.1645C4.65576 12.9217 4.67304 12.6674 4.70759 12.159L4.90254 9.29016C4.98797 8.03302 5.03069 7.40445 5.25288 6.8964C5.57438 6.16126 6.16126 5.57438 6.8964 5.25288C7.40445 5.03069 8.03302 4.98797 9.29016 4.90254L12.159 4.70759C12.6674 4.67304 12.9217 4.65577 13.1645 4.6005C13.5154 4.52063 13.8503 4.38193 14.1549 4.19028C14.3657 4.05764 14.5576 3.89009 14.9416 3.555L17.108 1.66428C18.0574 0.83576 18.532 0.421499 19.0484 0.219363C19.7955 -0.073121 20.6255 -0.073121 21.3727 0.219363C21.889 0.421499 22.3637 0.83576 23.313 1.66428L25.4795 3.555C25.8634 3.89009 26.0554 4.05764 26.2662 4.19028C26.5708 4.38193 26.9056 4.52063 27.2566 4.6005C27.4994 4.65577 27.7536 4.67304 28.2621 4.70759L31.1309 4.90254Z"
|
|
375
|
+
fill="#006E0F"
|
|
376
|
+
/>
|
|
377
|
+
</svg>
|
|
378
|
+
<svg width="16" height="12" viewBox="0 0 16 12" fill="none" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
|
379
|
+
<path
|
|
380
|
+
d="M5.472 11.544L0 6.072L1.368 4.704L5.472 8.808L14.28 0L15.648 1.368L5.472 11.544Z"
|
|
381
|
+
fill="white"
|
|
382
|
+
/>
|
|
383
|
+
</svg>
|
|
384
|
+
</div>
|
|
385
|
+
`;
|
|
386
|
+
}
|
|
329
387
|
attachEventListeners() {
|
|
330
388
|
const nameInput = this.container.querySelector("#medos-enquiry-name");
|
|
331
389
|
if (nameInput) {
|
|
@@ -400,10 +458,6 @@ class EnquiryFormWidget {
|
|
|
400
458
|
if (cancelBtn) {
|
|
401
459
|
cancelBtn.addEventListener("click", () => this.resetForm());
|
|
402
460
|
}
|
|
403
|
-
const submitAnotherBtn = this.container.querySelector("#medos-enquiry-btn-submit-another");
|
|
404
|
-
if (submitAnotherBtn) {
|
|
405
|
-
submitAnotherBtn.addEventListener("click", () => this.resetForm());
|
|
406
|
-
}
|
|
407
461
|
}
|
|
408
462
|
escapeHtml(text) {
|
|
409
463
|
const div = document.createElement("div");
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface AppointmentDetails {
|
|
3
|
+
patientName?: string;
|
|
4
|
+
visitationType?: string;
|
|
5
|
+
appointmentDate?: string;
|
|
6
|
+
fromTime?: string;
|
|
7
|
+
toTime?: string;
|
|
8
|
+
duration?: number;
|
|
9
|
+
location?: string;
|
|
10
|
+
mode?: string;
|
|
11
|
+
paymentMode?: string;
|
|
12
|
+
}
|
|
13
|
+
interface AppointmentConfirmationStepProps {
|
|
14
|
+
appointment: AppointmentDetails;
|
|
15
|
+
patient: {
|
|
16
|
+
firstName?: string;
|
|
17
|
+
middleName?: string;
|
|
18
|
+
lastName?: string;
|
|
19
|
+
patientName?: string;
|
|
20
|
+
};
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
}
|
|
23
|
+
declare const AppointmentConfirmationStep: React.FC<AppointmentConfirmationStepProps>;
|
|
24
|
+
export default AppointmentConfirmationStep;
|
|
@@ -4177,20 +4177,20 @@
|
|
|
4177
4177
|
async submitEnquiry(payload) {
|
|
4178
4178
|
try {
|
|
4179
4179
|
const client = await MedosClient.ensureInitialized();
|
|
4180
|
-
const
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
preferredContactMethod: payload.preferredContactMethod,
|
|
4180
|
+
const enquiryPayload = {
|
|
4181
|
+
type: "ENQUIRY",
|
|
4182
|
+
subject: payload.inquirySubject,
|
|
4183
|
+
description: payload.inquiryMessage,
|
|
4184
|
+
senderName: payload.patientName,
|
|
4185
|
+
senderEmail: payload.patientEmail,
|
|
4186
|
+
senderPhone: `${payload.countryCode}${payload.patientPhone}`,
|
|
4188
4187
|
};
|
|
4189
|
-
const
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
},
|
|
4188
|
+
const formData = new FormData();
|
|
4189
|
+
const jsonBlob = new Blob([JSON.stringify(enquiryPayload)], {
|
|
4190
|
+
type: "application/json",
|
|
4193
4191
|
});
|
|
4192
|
+
formData.append("payload", jsonBlob);
|
|
4193
|
+
const res = await client.post("/inbox/create", formData);
|
|
4194
4194
|
return res.data;
|
|
4195
4195
|
}
|
|
4196
4196
|
catch (error) {
|
|
@@ -4348,6 +4348,9 @@
|
|
|
4348
4348
|
await EnquiryService.submitEnquiry(payload);
|
|
4349
4349
|
this.state.step = 3;
|
|
4350
4350
|
this.options.onSuccess?.(payload);
|
|
4351
|
+
setTimeout(() => {
|
|
4352
|
+
this.resetForm();
|
|
4353
|
+
}, 5000);
|
|
4351
4354
|
}
|
|
4352
4355
|
catch (e) {
|
|
4353
4356
|
const msg = e.message || "Failed to submit enquiry";
|
|
@@ -4384,16 +4387,20 @@
|
|
|
4384
4387
|
this.container.innerHTML = `
|
|
4385
4388
|
<div class="medos-enquiry-container">
|
|
4386
4389
|
<div class="medos-enquiry-card">
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
<
|
|
4390
|
-
|
|
4390
|
+
${this.state.step !== 3
|
|
4391
|
+
? `
|
|
4392
|
+
<div class="medos-enquiry-header">
|
|
4393
|
+
<h2 class="medos-enquiry-title">Submit Inquiry</h2>
|
|
4394
|
+
<p class="medos-enquiry-step-indicator">Step ${this.state.step + 1} of 4</p>
|
|
4395
|
+
</div>
|
|
4391
4396
|
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
+
${this.state.loading
|
|
4398
|
+
? '<div class="medos-enquiry-loading">Loading...</div>'
|
|
4399
|
+
: ""}
|
|
4400
|
+
${this.state.error
|
|
4401
|
+
? `<div class="medos-enquiry-error">${this.escapeHtml(this.state.error)}</div>`
|
|
4402
|
+
: ""}
|
|
4403
|
+
`
|
|
4397
4404
|
: ""}
|
|
4398
4405
|
|
|
4399
4406
|
${this.renderStep()}
|
|
@@ -4537,16 +4544,67 @@
|
|
|
4537
4544
|
}
|
|
4538
4545
|
renderStep3() {
|
|
4539
4546
|
return `
|
|
4540
|
-
<div
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
<div class="medos-enquiry-success-message">Thank you, ${this.escapeHtml(this.state.patientName || "Patient")}. We have received your inquiry and will get back to you soon.</div>
|
|
4547
|
+
<div style="display: flex; flex-direction: column; padding: 0; font-family: Arial, sans-serif; background: #f8f9fa; min-height: 500px;">
|
|
4548
|
+
<!-- Header with border -->
|
|
4549
|
+
<div style="padding: 20px 24px; font-size: 24px; font-weight: bold; color: #1a365d; border-bottom: 2px solid #e2e8f0; background: white;">
|
|
4550
|
+
Inquiry Confirmed
|
|
4545
4551
|
</div>
|
|
4546
|
-
|
|
4547
|
-
|
|
4552
|
+
|
|
4553
|
+
<!-- Main content with border -->
|
|
4554
|
+
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 24px; border: 2px solid #e2e8f0; border-top: none; background: white; text-align: center;">
|
|
4555
|
+
<!-- Success Title -->
|
|
4556
|
+
<h2 style="font-size: 20px; font-weight: 600; color: #006E0F; margin: 0 0 24px 0;">
|
|
4557
|
+
Inquiry Submitted Successfully
|
|
4558
|
+
</h2>
|
|
4559
|
+
|
|
4560
|
+
<!-- Success Icon -->
|
|
4561
|
+
<div style="margin-bottom: 32px;">
|
|
4562
|
+
${this.renderSuccessIcon()}
|
|
4563
|
+
</div>
|
|
4564
|
+
|
|
4565
|
+
<!-- Inquiry Details -->
|
|
4566
|
+
<div style="width: 100%; max-width: 500px; margin-bottom: 32px;">
|
|
4567
|
+
<h3 style="font-size: 18px; font-weight: 600; color: #006E0F; margin-bottom: 24px;">
|
|
4568
|
+
Inquiry Details
|
|
4569
|
+
</h3>
|
|
4570
|
+
|
|
4571
|
+
<div style="display: flex; flex-direction: column; gap: 12px; font-size: 16px; line-height: 1.6; color: #4a5568;">
|
|
4572
|
+
<div><strong style="color: #006E0F;">Name:</strong> ${this.escapeHtml(this.state.patientName || "Patient")}</div>
|
|
4573
|
+
<div><strong style="color: #006E0F;">Email:</strong> ${this.escapeHtml(this.state.patientEmail)}</div>
|
|
4574
|
+
<div><strong style="color: #006E0F;">Phone:</strong> ${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</div>
|
|
4575
|
+
<div><strong style="color: #006E0F;">Subject:</strong> ${this.escapeHtml(this.state.inquirySubject)}</div>
|
|
4576
|
+
<div><strong style="color: #006E0F;">Preferred Contact:</strong> ${this.state.preferredContactMethod === "PHONE"
|
|
4577
|
+
? "Phone"
|
|
4578
|
+
: this.state.preferredContactMethod === "EMAIL"
|
|
4579
|
+
? "Email"
|
|
4580
|
+
: "Both"}</div>
|
|
4581
|
+
</div>
|
|
4582
|
+
</div>
|
|
4583
|
+
|
|
4584
|
+
<!-- Confirmation Message -->
|
|
4585
|
+
<div style="font-size: 16px; font-style: italic; color: #718096; text-align: center; max-width: 600px; line-height: 1.5;">
|
|
4586
|
+
Thank you for your inquiry. We have received your message and will get back to you soon via your preferred contact method.
|
|
4587
|
+
</div>
|
|
4548
4588
|
</div>
|
|
4549
4589
|
</div>
|
|
4590
|
+
`;
|
|
4591
|
+
}
|
|
4592
|
+
renderSuccessIcon() {
|
|
4593
|
+
return `
|
|
4594
|
+
<div style="position: relative; display: inline-block;">
|
|
4595
|
+
<svg width="64" height="64" viewBox="0 0 41 41" fill="none">
|
|
4596
|
+
<path
|
|
4597
|
+
d="M31.1309 4.90254C32.388 4.98797 33.0166 5.03069 33.5247 5.25288C34.2598 5.57438 34.8467 6.16126 35.1682 6.8964C35.3904 7.40445 35.4331 8.03302 35.5185 9.29016L35.7135 12.159C35.748 12.6674 35.7653 12.9217 35.8206 13.1645C35.9004 13.5154 36.0391 13.8503 36.2308 14.1549C36.3634 14.3657 36.531 14.5576 36.8661 14.9416L38.7568 17.108C39.5853 18.0574 39.9996 18.532 40.2017 19.0484C40.4942 19.7955 40.4942 20.6255 40.2017 21.3727C39.9996 21.889 39.5853 22.3637 38.7568 23.313L36.8661 25.4795C36.531 25.8634 36.3634 26.0554 36.2308 26.2662C36.0391 26.5708 35.9004 26.9056 35.8206 27.2566C35.7653 27.4994 35.748 27.7536 35.7135 28.2621L35.5185 31.1309C35.4331 32.388 35.3904 33.0166 35.1682 33.5247C34.8467 34.2598 34.2598 34.8467 33.5247 35.1682C33.0166 35.3904 32.388 35.4331 31.1309 35.5185L28.2621 35.7135C27.7536 35.748 27.4994 35.7653 27.2566 35.8206C26.9056 35.9004 26.5708 36.0391 26.2662 36.2308C26.0554 36.3634 25.8634 36.531 25.4795 36.8661L23.313 38.7568C22.3637 39.5853 21.889 39.9996 21.3727 40.2017C20.6255 40.4942 19.7955 40.4942 19.0484 40.2017C18.532 39.9996 18.0574 39.5853 17.108 38.7568L14.9416 36.8661C14.5576 36.531 14.3657 36.3634 14.1549 36.2308C13.8503 36.0391 13.5154 35.9004 13.1645 35.8206C12.9217 35.7653 12.6674 35.748 12.159 35.7135L9.29016 35.5185C8.03302 35.4331 7.40445 35.3904 6.8964 35.1682C6.16126 34.8467 5.57438 34.2598 5.25288 33.5247C5.03069 33.0166 4.98797 32.388 4.90254 31.1309L4.70759 28.2621C4.67304 27.7536 4.65576 27.4994 4.60049 27.2566C4.52063 26.9056 4.38193 26.5708 4.19028 26.2662C4.05764 26.0554 3.89009 25.8634 3.555 25.4795L1.66428 23.313C0.83576 22.3637 0.421499 21.889 0.219363 21.3727C-0.073121 20.6255 -0.0731209 19.7955 0.219363 19.0484C0.421499 18.532 0.83576 18.0574 1.66428 17.108L3.555 14.9416C3.89009 14.5576 4.05764 14.3657 4.19027 14.1549C4.38193 13.8503 4.52063 13.5154 4.60049 13.1645C4.65576 12.9217 4.67304 12.6674 4.70759 12.159L4.90254 9.29016C4.98797 8.03302 5.03069 7.40445 5.25288 6.8964C5.57438 6.16126 6.16126 5.57438 6.8964 5.25288C7.40445 5.03069 8.03302 4.98797 9.29016 4.90254L12.159 4.70759C12.6674 4.67304 12.9217 4.65577 13.1645 4.6005C13.5154 4.52063 13.8503 4.38193 14.1549 4.19028C14.3657 4.05764 14.5576 3.89009 14.9416 3.555L17.108 1.66428C18.0574 0.83576 18.532 0.421499 19.0484 0.219363C19.7955 -0.073121 20.6255 -0.073121 21.3727 0.219363C21.889 0.421499 22.3637 0.83576 23.313 1.66428L25.4795 3.555C25.8634 3.89009 26.0554 4.05764 26.2662 4.19028C26.5708 4.38193 26.9056 4.52063 27.2566 4.6005C27.4994 4.65577 27.7536 4.67304 28.2621 4.70759L31.1309 4.90254Z"
|
|
4598
|
+
fill="#006E0F"
|
|
4599
|
+
/>
|
|
4600
|
+
</svg>
|
|
4601
|
+
<svg width="16" height="12" viewBox="0 0 16 12" fill="none" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
|
4602
|
+
<path
|
|
4603
|
+
d="M5.472 11.544L0 6.072L1.368 4.704L5.472 8.808L14.28 0L15.648 1.368L5.472 11.544Z"
|
|
4604
|
+
fill="white"
|
|
4605
|
+
/>
|
|
4606
|
+
</svg>
|
|
4607
|
+
</div>
|
|
4550
4608
|
`;
|
|
4551
4609
|
}
|
|
4552
4610
|
attachEventListeners() {
|
|
@@ -4623,10 +4681,6 @@
|
|
|
4623
4681
|
if (cancelBtn) {
|
|
4624
4682
|
cancelBtn.addEventListener("click", () => this.resetForm());
|
|
4625
4683
|
}
|
|
4626
|
-
const submitAnotherBtn = this.container.querySelector("#medos-enquiry-btn-submit-another");
|
|
4627
|
-
if (submitAnotherBtn) {
|
|
4628
|
-
submitAnotherBtn.addEventListener("click", () => this.resetForm());
|
|
4629
|
-
}
|
|
4630
4684
|
}
|
|
4631
4685
|
escapeHtml(text) {
|
|
4632
4686
|
const div = document.createElement("div");
|
|
@@ -32,6 +32,10 @@ declare class AppointmentCalendarWidget {
|
|
|
32
32
|
private renderStep2;
|
|
33
33
|
private renderStep3;
|
|
34
34
|
private renderStep4;
|
|
35
|
+
private renderSuccessIcon;
|
|
36
|
+
private formatDate;
|
|
37
|
+
private formatTime;
|
|
38
|
+
private calculateDuration;
|
|
35
39
|
private renderStep5;
|
|
36
40
|
private attachEventListeners;
|
|
37
41
|
private escapeHtml;
|
package/dist/vanilla/widget.js
CHANGED
|
@@ -4609,9 +4609,10 @@
|
|
|
4609
4609
|
this.state.step = Math.max(0, this.state.step - 1);
|
|
4610
4610
|
this.render();
|
|
4611
4611
|
}
|
|
4612
|
-
reset() {
|
|
4612
|
+
async reset() {
|
|
4613
4613
|
this.state = { ...INITIAL_STATE };
|
|
4614
4614
|
this.doctors = [];
|
|
4615
|
+
await this.loadAddresses();
|
|
4615
4616
|
this.render();
|
|
4616
4617
|
}
|
|
4617
4618
|
setState(updates) {
|
|
@@ -4866,19 +4867,119 @@
|
|
|
4866
4867
|
</div>
|
|
4867
4868
|
`;
|
|
4868
4869
|
}
|
|
4870
|
+
renderSuccessIcon() {
|
|
4871
|
+
return `
|
|
4872
|
+
<div style="position: relative; display: inline-block;">
|
|
4873
|
+
<svg width="64" height="64" viewBox="0 0 41 41" fill="none">
|
|
4874
|
+
<path
|
|
4875
|
+
d="M31.1309 4.90254C32.388 4.98797 33.0166 5.03069 33.5247 5.25288C34.2598 5.57438 34.8467 6.16126 35.1682 6.8964C35.3904 7.40445 35.4331 8.03302 35.5185 9.29016L35.7135 12.159C35.748 12.6674 35.7653 12.9217 35.8206 13.1645C35.9004 13.5154 36.0391 13.8503 36.2308 14.1549C36.3634 14.3657 36.531 14.5576 36.8661 14.9416L38.7568 17.108C39.5853 18.0574 39.9996 18.532 40.2017 19.0484C40.4942 19.7955 40.4942 20.6255 40.2017 21.3727C39.9996 21.889 39.5853 22.3637 38.7568 23.313L36.8661 25.4795C36.531 25.8634 36.3634 26.0554 36.2308 26.2662C36.0391 26.5708 35.9004 26.9056 35.8206 27.2566C35.7653 27.4994 35.748 27.7536 35.7135 28.2621L35.5185 31.1309C35.4331 32.388 35.3904 33.0166 35.1682 33.5247C34.8467 34.2598 34.2598 34.8467 33.5247 35.1682C33.0166 35.3904 32.388 35.4331 31.1309 35.5185L28.2621 35.7135C27.7536 35.748 27.4994 35.7653 27.2566 35.8206C26.9056 35.9004 26.5708 36.0391 26.2662 36.2308C26.0554 36.3634 25.8634 36.531 25.4795 36.8661L23.313 38.7568C22.3637 39.5853 21.889 39.9996 21.3727 40.2017C20.6255 40.4942 19.7955 40.4942 19.0484 40.2017C18.532 39.9996 18.0574 39.5853 17.108 38.7568L14.9416 36.8661C14.5576 36.531 14.3657 36.3634 14.1549 36.2308C13.8503 36.0391 13.5154 35.9004 13.1645 35.8206C12.9217 35.7653 12.6674 35.748 12.159 35.7135L9.29016 35.5185C8.03302 35.4331 7.40445 35.3904 6.8964 35.1682C6.16126 34.8467 5.57438 34.2598 5.25288 33.5247C5.03069 33.0166 4.98797 32.388 4.90254 31.1309L4.70759 28.2621C4.67304 27.7536 4.65576 27.4994 4.60049 27.2566C4.52063 26.9056 4.38193 26.5708 4.19028 26.2662C4.05764 26.0554 3.89009 25.8634 3.555 25.4795L1.66428 23.313C0.83576 22.3637 0.421499 21.889 0.219363 21.3727C-0.073121 20.6255 -0.0731209 19.7955 0.219363 19.0484C0.421499 18.532 0.83576 18.0574 1.66428 17.108L3.555 14.9416C3.89009 14.5576 4.05764 14.3657 4.19027 14.1549C4.38193 13.8503 4.52063 13.5154 4.60049 13.1645C4.65576 12.9217 4.67304 12.6674 4.70759 12.159L4.90254 9.29016C4.98797 8.03302 5.03069 7.40445 5.25288 6.8964C5.57438 6.16126 6.16126 5.57438 6.8964 5.25288C7.40445 5.03069 8.03302 4.98797 9.29016 4.90254L12.159 4.70759C12.6674 4.67304 12.9217 4.65577 13.1645 4.6005C13.5154 4.52063 13.8503 4.38193 14.1549 4.19028C14.3657 4.05764 14.5576 3.89009 14.9416 3.555L17.108 1.66428C18.0574 0.83576 18.532 0.421499 19.0484 0.219363C19.7955 -0.073121 20.6255 -0.073121 21.3727 0.219363C21.889 0.421499 22.3637 0.83576 23.313 1.66428L25.4795 3.555C25.8634 3.89009 26.0554 4.05764 26.2662 4.19028C26.5708 4.38193 26.9056 4.52063 27.2566 4.6005C27.4994 4.65577 27.7536 4.67304 28.2621 4.70759L31.1309 4.90254Z"
|
|
4876
|
+
fill="#006E0F"
|
|
4877
|
+
/>
|
|
4878
|
+
</svg>
|
|
4879
|
+
<svg width="16" height="12" viewBox="0 0 16 12" fill="none" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
|
4880
|
+
<path
|
|
4881
|
+
d="M5.472 11.544L0 6.072L1.368 4.704L5.472 8.808L14.28 0L15.648 1.368L5.472 11.544Z"
|
|
4882
|
+
fill="white"
|
|
4883
|
+
/>
|
|
4884
|
+
</svg>
|
|
4885
|
+
</div>
|
|
4886
|
+
`;
|
|
4887
|
+
}
|
|
4888
|
+
formatDate(dateStr) {
|
|
4889
|
+
try {
|
|
4890
|
+
const date = new Date(dateStr);
|
|
4891
|
+
return date.toLocaleDateString("en-US", {
|
|
4892
|
+
weekday: "long",
|
|
4893
|
+
year: "numeric",
|
|
4894
|
+
month: "long",
|
|
4895
|
+
day: "numeric",
|
|
4896
|
+
});
|
|
4897
|
+
}
|
|
4898
|
+
catch {
|
|
4899
|
+
return dateStr;
|
|
4900
|
+
}
|
|
4901
|
+
}
|
|
4902
|
+
formatTime(timeStr) {
|
|
4903
|
+
try {
|
|
4904
|
+
const time = new Date(`2000-01-01T${timeStr}`);
|
|
4905
|
+
return time.toLocaleTimeString("en-US", {
|
|
4906
|
+
hour: "numeric",
|
|
4907
|
+
minute: "2-digit",
|
|
4908
|
+
hour12: true,
|
|
4909
|
+
});
|
|
4910
|
+
}
|
|
4911
|
+
catch {
|
|
4912
|
+
return timeStr;
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4915
|
+
calculateDuration() {
|
|
4916
|
+
if (this.state.selectedSlot) {
|
|
4917
|
+
const start = new Date(this.state.selectedSlot.start);
|
|
4918
|
+
const end = new Date(this.state.selectedSlot.end);
|
|
4919
|
+
const diffMs = end.getTime() - start.getTime();
|
|
4920
|
+
return Math.round(diffMs / (1000 * 60));
|
|
4921
|
+
}
|
|
4922
|
+
return 60;
|
|
4923
|
+
}
|
|
4869
4924
|
renderStep5() {
|
|
4925
|
+
const duration = this.calculateDuration();
|
|
4926
|
+
const selectedAddress = this.state.addresses.find((addr) => addr.id === this.state.selectedAddress);
|
|
4927
|
+
const appointmentDate = this.state.selectedDate
|
|
4928
|
+
? this.formatDate(formatDateToISO(this.state.selectedDate))
|
|
4929
|
+
: "";
|
|
4930
|
+
const startTime = this.state.selectedSlot?.start
|
|
4931
|
+
? this.formatTime(new Date(this.state.selectedSlot.start).toTimeString().slice(0, 5))
|
|
4932
|
+
: "";
|
|
4870
4933
|
return `
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4934
|
+
<div style="display: flex; flex-direction: column; padding: 0; font-family: Arial, sans-serif; background: #f8f9fa; min-height: 500px;">
|
|
4935
|
+
<!-- Header with border -->
|
|
4936
|
+
<div style="padding: 20px 24px; font-size: 24px; font-weight: bold; color: #1a365d; border-bottom: 2px solid #e2e8f0; background: white;">
|
|
4937
|
+
Appointment Confirmed
|
|
4938
|
+
</div>
|
|
4939
|
+
|
|
4940
|
+
<!-- Main content with border -->
|
|
4941
|
+
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 24px; border: 2px solid #e2e8f0; border-top: none; background: white; text-align: center;">
|
|
4942
|
+
<!-- Success Title -->
|
|
4943
|
+
<h2 style="font-size: 20px; font-weight: 600; color: #006E0F; margin: 0 0 24px 0;">
|
|
4944
|
+
Appointment Confirmed
|
|
4945
|
+
</h2>
|
|
4946
|
+
|
|
4947
|
+
<!-- Success Icon -->
|
|
4948
|
+
<div style="margin-bottom: 32px;">
|
|
4949
|
+
${this.renderSuccessIcon()}
|
|
4950
|
+
</div>
|
|
4951
|
+
|
|
4952
|
+
<!-- Appointment Details -->
|
|
4953
|
+
<div style="width: 100%; max-width: 500px; margin-bottom: 32px;">
|
|
4954
|
+
<h3 style="font-size: 18px; font-weight: 600; color: #006E0F; margin-bottom: 24px;">
|
|
4955
|
+
Appointment Details
|
|
4956
|
+
</h3>
|
|
4957
|
+
|
|
4958
|
+
<div style="display: flex; flex-direction: column; gap: 12px; font-size: 16px; line-height: 1.6; color: #4a5568;">
|
|
4959
|
+
<div><strong style="color: #006E0F;">Patient:</strong> ${this.escapeHtml(this.state.patientName || "Patient")}</div>
|
|
4960
|
+
<div><strong style="color: #006E0F;">Visitation Type:</strong> ${this.state.consultationMode === "ONLINE"
|
|
4961
|
+
? "Online Consultation"
|
|
4962
|
+
: "General"}</div>
|
|
4963
|
+
${appointmentDate
|
|
4964
|
+
? `<div><strong style="color: #006E0F;">Date:</strong> ${appointmentDate}</div>`
|
|
4965
|
+
: ""}
|
|
4966
|
+
${startTime
|
|
4967
|
+
? `<div><strong style="color: #006E0F;">Time:</strong> ${startTime}</div>`
|
|
4968
|
+
: ""}
|
|
4969
|
+
<div><strong style="color: #006E0F;">Duration:</strong> ~${duration} minutes</div>
|
|
4970
|
+
${selectedAddress?.label
|
|
4971
|
+
? `<div><strong style="color: #006E0F;">Location:</strong> ${this.escapeHtml(selectedAddress.label)}</div>`
|
|
4972
|
+
: ""}
|
|
4973
|
+
</div>
|
|
4876
4974
|
</div>
|
|
4877
|
-
|
|
4878
|
-
|
|
4975
|
+
|
|
4976
|
+
<!-- Confirmation Message -->
|
|
4977
|
+
<div style="font-size: 16px; font-style: italic; color: #718096; text-align: center; max-width: 600px; line-height: 1.5;">
|
|
4978
|
+
A confirmation email has been sent to the Patient's Email address.
|
|
4879
4979
|
</div>
|
|
4880
4980
|
</div>
|
|
4881
|
-
|
|
4981
|
+
</div>
|
|
4982
|
+
`;
|
|
4882
4983
|
}
|
|
4883
4984
|
attachEventListeners() {
|
|
4884
4985
|
const addressSelect = this.container.querySelector("#medos-address-select");
|
|
@@ -5075,20 +5176,20 @@
|
|
|
5075
5176
|
async submitEnquiry(payload) {
|
|
5076
5177
|
try {
|
|
5077
5178
|
const client = await MedosClient.ensureInitialized();
|
|
5078
|
-
const
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
preferredContactMethod: payload.preferredContactMethod,
|
|
5179
|
+
const enquiryPayload = {
|
|
5180
|
+
type: "ENQUIRY",
|
|
5181
|
+
subject: payload.inquirySubject,
|
|
5182
|
+
description: payload.inquiryMessage,
|
|
5183
|
+
senderName: payload.patientName,
|
|
5184
|
+
senderEmail: payload.patientEmail,
|
|
5185
|
+
senderPhone: `${payload.countryCode}${payload.patientPhone}`,
|
|
5086
5186
|
};
|
|
5087
|
-
const
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
},
|
|
5187
|
+
const formData = new FormData();
|
|
5188
|
+
const jsonBlob = new Blob([JSON.stringify(enquiryPayload)], {
|
|
5189
|
+
type: "application/json",
|
|
5091
5190
|
});
|
|
5191
|
+
formData.append("payload", jsonBlob);
|
|
5192
|
+
const res = await client.post("/inbox/create", formData);
|
|
5092
5193
|
return res.data;
|
|
5093
5194
|
}
|
|
5094
5195
|
catch (error) {
|
|
@@ -5246,6 +5347,9 @@
|
|
|
5246
5347
|
await EnquiryService.submitEnquiry(payload);
|
|
5247
5348
|
this.state.step = 3;
|
|
5248
5349
|
this.options.onSuccess?.(payload);
|
|
5350
|
+
setTimeout(() => {
|
|
5351
|
+
this.resetForm();
|
|
5352
|
+
}, 5000);
|
|
5249
5353
|
}
|
|
5250
5354
|
catch (e) {
|
|
5251
5355
|
const msg = e.message || "Failed to submit enquiry";
|
|
@@ -5282,16 +5386,20 @@
|
|
|
5282
5386
|
this.container.innerHTML = `
|
|
5283
5387
|
<div class="medos-enquiry-container">
|
|
5284
5388
|
<div class="medos-enquiry-card">
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
<
|
|
5288
|
-
|
|
5389
|
+
${this.state.step !== 3
|
|
5390
|
+
? `
|
|
5391
|
+
<div class="medos-enquiry-header">
|
|
5392
|
+
<h2 class="medos-enquiry-title">Submit Inquiry</h2>
|
|
5393
|
+
<p class="medos-enquiry-step-indicator">Step ${this.state.step + 1} of 4</p>
|
|
5394
|
+
</div>
|
|
5289
5395
|
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5396
|
+
${this.state.loading
|
|
5397
|
+
? '<div class="medos-enquiry-loading">Loading...</div>'
|
|
5398
|
+
: ""}
|
|
5399
|
+
${this.state.error
|
|
5400
|
+
? `<div class="medos-enquiry-error">${this.escapeHtml(this.state.error)}</div>`
|
|
5401
|
+
: ""}
|
|
5402
|
+
`
|
|
5295
5403
|
: ""}
|
|
5296
5404
|
|
|
5297
5405
|
${this.renderStep()}
|
|
@@ -5435,16 +5543,67 @@
|
|
|
5435
5543
|
}
|
|
5436
5544
|
renderStep3() {
|
|
5437
5545
|
return `
|
|
5438
|
-
<div
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
<div class="medos-enquiry-success-message">Thank you, ${this.escapeHtml(this.state.patientName || "Patient")}. We have received your inquiry and will get back to you soon.</div>
|
|
5546
|
+
<div style="display: flex; flex-direction: column; padding: 0; font-family: Arial, sans-serif; background: #f8f9fa; min-height: 500px;">
|
|
5547
|
+
<!-- Header with border -->
|
|
5548
|
+
<div style="padding: 20px 24px; font-size: 24px; font-weight: bold; color: #1a365d; border-bottom: 2px solid #e2e8f0; background: white;">
|
|
5549
|
+
Inquiry Confirmed
|
|
5443
5550
|
</div>
|
|
5444
|
-
|
|
5445
|
-
|
|
5551
|
+
|
|
5552
|
+
<!-- Main content with border -->
|
|
5553
|
+
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 24px; border: 2px solid #e2e8f0; border-top: none; background: white; text-align: center;">
|
|
5554
|
+
<!-- Success Title -->
|
|
5555
|
+
<h2 style="font-size: 20px; font-weight: 600; color: #006E0F; margin: 0 0 24px 0;">
|
|
5556
|
+
Inquiry Submitted Successfully
|
|
5557
|
+
</h2>
|
|
5558
|
+
|
|
5559
|
+
<!-- Success Icon -->
|
|
5560
|
+
<div style="margin-bottom: 32px;">
|
|
5561
|
+
${this.renderSuccessIcon()}
|
|
5562
|
+
</div>
|
|
5563
|
+
|
|
5564
|
+
<!-- Inquiry Details -->
|
|
5565
|
+
<div style="width: 100%; max-width: 500px; margin-bottom: 32px;">
|
|
5566
|
+
<h3 style="font-size: 18px; font-weight: 600; color: #006E0F; margin-bottom: 24px;">
|
|
5567
|
+
Inquiry Details
|
|
5568
|
+
</h3>
|
|
5569
|
+
|
|
5570
|
+
<div style="display: flex; flex-direction: column; gap: 12px; font-size: 16px; line-height: 1.6; color: #4a5568;">
|
|
5571
|
+
<div><strong style="color: #006E0F;">Name:</strong> ${this.escapeHtml(this.state.patientName || "Patient")}</div>
|
|
5572
|
+
<div><strong style="color: #006E0F;">Email:</strong> ${this.escapeHtml(this.state.patientEmail)}</div>
|
|
5573
|
+
<div><strong style="color: #006E0F;">Phone:</strong> ${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</div>
|
|
5574
|
+
<div><strong style="color: #006E0F;">Subject:</strong> ${this.escapeHtml(this.state.inquirySubject)}</div>
|
|
5575
|
+
<div><strong style="color: #006E0F;">Preferred Contact:</strong> ${this.state.preferredContactMethod === "PHONE"
|
|
5576
|
+
? "Phone"
|
|
5577
|
+
: this.state.preferredContactMethod === "EMAIL"
|
|
5578
|
+
? "Email"
|
|
5579
|
+
: "Both"}</div>
|
|
5580
|
+
</div>
|
|
5581
|
+
</div>
|
|
5582
|
+
|
|
5583
|
+
<!-- Confirmation Message -->
|
|
5584
|
+
<div style="font-size: 16px; font-style: italic; color: #718096; text-align: center; max-width: 600px; line-height: 1.5;">
|
|
5585
|
+
Thank you for your inquiry. We have received your message and will get back to you soon via your preferred contact method.
|
|
5586
|
+
</div>
|
|
5446
5587
|
</div>
|
|
5447
5588
|
</div>
|
|
5589
|
+
`;
|
|
5590
|
+
}
|
|
5591
|
+
renderSuccessIcon() {
|
|
5592
|
+
return `
|
|
5593
|
+
<div style="position: relative; display: inline-block;">
|
|
5594
|
+
<svg width="64" height="64" viewBox="0 0 41 41" fill="none">
|
|
5595
|
+
<path
|
|
5596
|
+
d="M31.1309 4.90254C32.388 4.98797 33.0166 5.03069 33.5247 5.25288C34.2598 5.57438 34.8467 6.16126 35.1682 6.8964C35.3904 7.40445 35.4331 8.03302 35.5185 9.29016L35.7135 12.159C35.748 12.6674 35.7653 12.9217 35.8206 13.1645C35.9004 13.5154 36.0391 13.8503 36.2308 14.1549C36.3634 14.3657 36.531 14.5576 36.8661 14.9416L38.7568 17.108C39.5853 18.0574 39.9996 18.532 40.2017 19.0484C40.4942 19.7955 40.4942 20.6255 40.2017 21.3727C39.9996 21.889 39.5853 22.3637 38.7568 23.313L36.8661 25.4795C36.531 25.8634 36.3634 26.0554 36.2308 26.2662C36.0391 26.5708 35.9004 26.9056 35.8206 27.2566C35.7653 27.4994 35.748 27.7536 35.7135 28.2621L35.5185 31.1309C35.4331 32.388 35.3904 33.0166 35.1682 33.5247C34.8467 34.2598 34.2598 34.8467 33.5247 35.1682C33.0166 35.3904 32.388 35.4331 31.1309 35.5185L28.2621 35.7135C27.7536 35.748 27.4994 35.7653 27.2566 35.8206C26.9056 35.9004 26.5708 36.0391 26.2662 36.2308C26.0554 36.3634 25.8634 36.531 25.4795 36.8661L23.313 38.7568C22.3637 39.5853 21.889 39.9996 21.3727 40.2017C20.6255 40.4942 19.7955 40.4942 19.0484 40.2017C18.532 39.9996 18.0574 39.5853 17.108 38.7568L14.9416 36.8661C14.5576 36.531 14.3657 36.3634 14.1549 36.2308C13.8503 36.0391 13.5154 35.9004 13.1645 35.8206C12.9217 35.7653 12.6674 35.748 12.159 35.7135L9.29016 35.5185C8.03302 35.4331 7.40445 35.3904 6.8964 35.1682C6.16126 34.8467 5.57438 34.2598 5.25288 33.5247C5.03069 33.0166 4.98797 32.388 4.90254 31.1309L4.70759 28.2621C4.67304 27.7536 4.65576 27.4994 4.60049 27.2566C4.52063 26.9056 4.38193 26.5708 4.19028 26.2662C4.05764 26.0554 3.89009 25.8634 3.555 25.4795L1.66428 23.313C0.83576 22.3637 0.421499 21.889 0.219363 21.3727C-0.073121 20.6255 -0.0731209 19.7955 0.219363 19.0484C0.421499 18.532 0.83576 18.0574 1.66428 17.108L3.555 14.9416C3.89009 14.5576 4.05764 14.3657 4.19027 14.1549C4.38193 13.8503 4.52063 13.5154 4.60049 13.1645C4.65576 12.9217 4.67304 12.6674 4.70759 12.159L4.90254 9.29016C4.98797 8.03302 5.03069 7.40445 5.25288 6.8964C5.57438 6.16126 6.16126 5.57438 6.8964 5.25288C7.40445 5.03069 8.03302 4.98797 9.29016 4.90254L12.159 4.70759C12.6674 4.67304 12.9217 4.65577 13.1645 4.6005C13.5154 4.52063 13.8503 4.38193 14.1549 4.19028C14.3657 4.05764 14.5576 3.89009 14.9416 3.555L17.108 1.66428C18.0574 0.83576 18.532 0.421499 19.0484 0.219363C19.7955 -0.073121 20.6255 -0.073121 21.3727 0.219363C21.889 0.421499 22.3637 0.83576 23.313 1.66428L25.4795 3.555C25.8634 3.89009 26.0554 4.05764 26.2662 4.19028C26.5708 4.38193 26.9056 4.52063 27.2566 4.6005C27.4994 4.65577 27.7536 4.67304 28.2621 4.70759L31.1309 4.90254Z"
|
|
5597
|
+
fill="#006E0F"
|
|
5598
|
+
/>
|
|
5599
|
+
</svg>
|
|
5600
|
+
<svg width="16" height="12" viewBox="0 0 16 12" fill="none" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
|
5601
|
+
<path
|
|
5602
|
+
d="M5.472 11.544L0 6.072L1.368 4.704L5.472 8.808L14.28 0L15.648 1.368L5.472 11.544Z"
|
|
5603
|
+
fill="white"
|
|
5604
|
+
/>
|
|
5605
|
+
</svg>
|
|
5606
|
+
</div>
|
|
5448
5607
|
`;
|
|
5449
5608
|
}
|
|
5450
5609
|
attachEventListeners() {
|
|
@@ -5521,10 +5680,6 @@
|
|
|
5521
5680
|
if (cancelBtn) {
|
|
5522
5681
|
cancelBtn.addEventListener("click", () => this.resetForm());
|
|
5523
5682
|
}
|
|
5524
|
-
const submitAnotherBtn = this.container.querySelector("#medos-enquiry-btn-submit-another");
|
|
5525
|
-
if (submitAnotherBtn) {
|
|
5526
|
-
submitAnotherBtn.addEventListener("click", () => this.resetForm());
|
|
5527
|
-
}
|
|
5528
5683
|
}
|
|
5529
5684
|
escapeHtml(text) {
|
|
5530
5685
|
const div = document.createElement("div");
|
package/package.json
CHANGED