medos-sdk 1.1.10 → 1.1.12
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/client/MedosClient.d.ts +1 -0
- package/dist/client/MedosClient.js +8 -1
- package/dist/components/AppointmentCalender.js +19 -22
- package/dist/components/AppointmentConfirmationStep.d.ts +1 -0
- package/dist/components/AppointmentConfirmationStep.js +34 -42
- package/dist/components/AppointmentDateTimeModal.d.ts +1 -0
- package/dist/components/AppointmentDateTimeModal.js +201 -168
- package/dist/components/AppointmentSummaryStep.d.ts +12 -0
- package/dist/components/AppointmentSummaryStep.js +168 -0
- package/dist/components/BookingOptionStep.d.ts +14 -0
- package/dist/components/BookingOptionStep.js +346 -0
- package/dist/components/ContactInformationStep.js +10 -4
- package/dist/components/ContactPreferenceStep.js +10 -1
- package/dist/components/DoctorSelectModal.js +105 -59
- package/dist/components/EnquiryForm.js +81 -69
- package/dist/components/Icons/CloseIcon.d.ts +9 -0
- package/dist/components/Icons/CloseIcon.js +5 -0
- package/dist/components/InquiryDetailsStep.js +5 -1
- package/dist/components/PatientDetailsStep.js +17 -12
- package/dist/components/PatientSelectionStep.d.ts +12 -0
- package/dist/components/PatientSelectionStep.js +254 -0
- package/dist/components/PhoneVerificationStep.js +1 -1
- package/dist/components/SuccessStep.js +1 -1
- package/dist/components/appointment-booking/AppointmentCalender.js +145 -67
- package/dist/components/appointment-booking/appointment-modal-styles.d.ts +272 -0
- package/dist/components/appointment-booking/appointment-modal-styles.js +419 -0
- package/dist/components/appointment-booking/components/AppointmentConfirmationStep.d.ts +28 -0
- package/dist/components/appointment-booking/components/AppointmentConfirmationStep.js +107 -0
- package/dist/components/appointment-booking/components/AppointmentDateTimeModal.d.ts +18 -0
- package/dist/components/appointment-booking/components/AppointmentDateTimeModal.js +306 -0
- package/dist/components/appointment-booking/components/AppointmentSummaryStep.d.ts +12 -0
- package/dist/components/appointment-booking/components/AppointmentSummaryStep.js +194 -0
- package/dist/components/appointment-booking/components/BookingOptionStep.d.ts +14 -0
- package/dist/components/appointment-booking/components/BookingOptionStep.js +350 -0
- package/dist/components/appointment-booking/components/DoctorSelectModal.d.ts +14 -0
- package/dist/components/appointment-booking/components/DoctorSelectModal.js +213 -0
- package/dist/components/appointment-booking/components/PatientDetailsStep.d.ts +3 -0
- package/dist/components/appointment-booking/components/PatientDetailsStep.js +96 -0
- package/dist/components/appointment-booking/components/PatientSelectionStep.d.ts +12 -0
- package/dist/components/appointment-booking/components/PatientSelectionStep.js +254 -0
- package/dist/components/appointment-booking/components/PhoneVerificationStep.d.ts +3 -0
- package/dist/components/appointment-booking/components/PhoneVerificationStep.js +49 -0
- package/dist/components/appointment-booking/components/SuccessStep.d.ts +5 -0
- package/dist/components/appointment-booking/components/SuccessStep.js +9 -0
- package/dist/components/appointment-booking/components/index.d.ts +9 -0
- package/dist/components/appointment-booking/components/index.js +9 -0
- package/dist/components/appointment-booking/hooks/useAppointmentFlow.d.ts +0 -1
- package/dist/components/appointment-booking/hooks/useAppointmentFlow.js +111 -25
- package/dist/components/appointment-booking/hooks/useAppointmentState.js +32 -0
- package/dist/components/appointment-booking/hooks/useInitializeAddresses.js +0 -1
- package/dist/components/appointment-booking/index.d.ts +2 -4
- package/dist/components/appointment-booking/index.js +2 -2
- package/dist/components/appointment-booking/types.d.ts +167 -0
- package/dist/components/appointment-booking/types.js +16 -0
- package/dist/components/appointment-modal-styles.d.ts +259 -0
- package/dist/components/appointment-modal-styles.js +395 -0
- package/dist/components/constant.d.ts +2 -0
- package/dist/components/constant.js +15 -0
- package/dist/components/constants/constant.d.ts +2 -0
- package/dist/components/constants/constant.js +15 -0
- package/dist/components/constants/index.d.ts +3 -0
- package/dist/components/constants/index.js +24 -0
- package/dist/components/constants/options.d.ts +13 -0
- package/dist/components/constants/options.js +35 -0
- package/dist/components/constants/validation.d.ts +6 -0
- package/dist/components/constants/validation.js +16 -0
- package/dist/components/custom-calendar.js +20 -11
- package/dist/components/enquiry-form/EnquiryForm.d.ts +7 -0
- package/dist/components/enquiry-form/EnquiryForm.js +238 -0
- package/dist/components/enquiry-form/components/ContactInformationStep.d.ts +13 -0
- package/dist/components/enquiry-form/components/ContactInformationStep.js +21 -0
- package/dist/components/enquiry-form/components/ContactPreferenceStep.d.ts +9 -0
- package/dist/components/enquiry-form/components/ContactPreferenceStep.js +20 -0
- package/dist/components/enquiry-form/components/InquiryDetailsStep.d.ts +10 -0
- package/dist/components/enquiry-form/components/InquiryDetailsStep.js +20 -0
- package/dist/components/enquiry-form/components/index.d.ts +3 -0
- package/dist/components/enquiry-form/components/index.js +3 -0
- package/dist/components/enquiry-form/index.d.ts +2 -0
- package/dist/components/enquiry-form/index.js +2 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.js +7 -0
- package/dist/components/shared/icons/Check.d.ts +6 -0
- package/dist/components/shared/icons/Check.js +2 -0
- package/dist/components/shared/icons/ChevronDownIcon.d.ts +4 -0
- package/dist/components/shared/icons/ChevronDownIcon.js +2 -0
- package/dist/components/shared/icons/ChevronLeft.d.ts +3 -0
- package/dist/components/shared/icons/ChevronLeft.js +3 -0
- package/dist/components/shared/icons/ChevronRight.d.ts +3 -0
- package/dist/components/shared/icons/ChevronRight.js +3 -0
- package/dist/components/shared/icons/CloseIcon.d.ts +9 -0
- package/dist/components/shared/icons/CloseIcon.js +5 -0
- package/dist/components/shared/icons/ConfirmationCheck.d.ts +1 -0
- package/dist/components/shared/icons/ConfirmationCheck.js +9 -0
- package/dist/components/shared/icons/ConsultationType.d.ts +1 -0
- package/dist/components/shared/icons/ConsultationType.js +2 -0
- package/dist/components/shared/icons/Date&TimeIcon.d.ts +1 -0
- package/dist/components/shared/icons/Date&TimeIcon.js +2 -0
- package/dist/components/shared/icons/MapIcon.d.ts +1 -0
- package/dist/components/shared/icons/MapIcon.js +2 -0
- package/dist/components/shared/icons/MedosLogo.d.ts +3 -0
- package/dist/components/shared/icons/MedosLogo.js +3 -0
- package/dist/components/shared/icons/PaymentMethodIcon.d.ts +1 -0
- package/dist/components/shared/icons/PaymentMethodIcon.js +2 -0
- package/dist/components/shared/icons/SuccessIcon.d.ts +8 -0
- package/dist/components/shared/icons/SuccessIcon.js +14 -0
- package/dist/components/shared/icons/UserIcon.d.ts +1 -0
- package/dist/components/shared/icons/UserIcon.js +2 -0
- package/dist/components/shared/icons/index.d.ts +13 -0
- package/dist/components/shared/icons/index.js +13 -0
- package/dist/components/shared/index.d.ts +2 -0
- package/dist/components/shared/index.js +2 -0
- package/dist/components/shared/ui/Calendar.d.ts +5 -0
- package/dist/components/shared/ui/Calendar.js +167 -0
- package/dist/components/shared/ui/SelectDropdown.d.ts +41 -0
- package/dist/components/shared/ui/SelectDropdown.js +301 -0
- package/dist/components/shared/ui/index.d.ts +2 -0
- package/dist/components/shared/ui/index.js +2 -0
- package/dist/components/styles/appointment.d.ts +4 -0
- package/dist/components/styles/appointment.js +220 -0
- package/dist/components/styles/enquiry.d.ts +2 -0
- package/dist/components/styles/enquiry.js +3 -0
- package/dist/components/styles/index.d.ts +2 -0
- package/dist/components/styles/index.js +2 -0
- package/dist/components/styles/shared.d.ts +3 -0
- package/dist/components/styles/shared.js +78 -0
- package/dist/components/styles.d.ts +1 -6
- package/dist/components/styles.js +1 -257
- package/dist/components/theme-styles.d.ts +5 -4
- package/dist/components/theme-styles.js +239 -125
- package/dist/components/types/appointment.d.ts +42 -0
- package/dist/components/types/appointment.js +1 -0
- package/dist/components/types/common.d.ts +24 -0
- package/dist/components/types/common.js +1 -0
- package/dist/components/types/enquiry.d.ts +59 -0
- package/dist/components/types/enquiry.js +1 -0
- package/dist/components/types/index.d.ts +4 -0
- package/dist/components/types/index.js +4 -0
- package/dist/components/types.d.ts +1 -52
- package/dist/components/types.js +1 -23
- package/dist/components/utils/date.d.ts +4 -0
- package/dist/components/utils/date.js +65 -0
- package/dist/components/utils/formatting.d.ts +4 -0
- package/dist/components/utils/formatting.js +9 -0
- package/dist/components/utils/index.d.ts +3 -0
- package/dist/components/utils/index.js +3 -0
- package/dist/components/utils/validation.d.ts +4 -0
- package/dist/components/utils/validation.js +37 -0
- package/dist/components/utils.d.ts +1 -5
- package/dist/components/utils.js +1 -15
- package/dist/components/validation.d.ts +1 -2
- package/dist/components/validation.js +1 -7
- package/dist/constants/index.d.ts +1 -1
- package/dist/constants/index.js +1 -1
- package/dist/core/theme/index.d.ts +1 -0
- package/dist/core/theme/index.js +1 -0
- package/dist/core/theme/responsive.d.ts +15 -0
- package/dist/core/theme/responsive.js +113 -0
- package/dist/core/theme/themes.js +16 -4
- package/dist/core/theme/types.d.ts +8 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/react/ThemeProvider.d.ts +2 -1
- package/dist/react/ThemeProvider.js +49 -10
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js +1 -1
- package/dist/services/AppointmentService.d.ts +80 -2
- package/dist/services/AppointmentService.js +131 -5
- package/dist/services/AuthService.js +1 -1
- package/dist/services/WorkspaceService.d.ts +58 -3
- package/dist/services/WorkspaceService.js +10 -1
- package/dist/vanilla/AppointmentCalendarWidget.d.ts +17 -7
- package/dist/vanilla/AppointmentCalendarWidget.js +1401 -380
- package/dist/vanilla/EnquiryFormWidget.d.ts +1 -0
- package/dist/vanilla/EnquiryFormWidget.js +25 -43
- package/dist/vanilla/client/MedosClient.d.ts +1 -0
- package/dist/vanilla/components/AppointmentConfirmationStep.d.ts +1 -0
- package/dist/vanilla/components/AppointmentDateTimeModal.d.ts +1 -0
- package/dist/vanilla/components/AppointmentSummaryStep.d.ts +12 -0
- package/dist/vanilla/components/BookingOptionStep.d.ts +14 -0
- package/dist/vanilla/components/Icons/CloseIcon.d.ts +9 -0
- package/dist/vanilla/components/PatientSelectionStep.d.ts +12 -0
- package/dist/vanilla/components/VanillaCalendar.js +33 -18
- package/dist/vanilla/components/VanillaIcons.d.ts +5 -0
- package/dist/vanilla/components/VanillaIcons.js +92 -0
- package/dist/vanilla/components/VanillaSelect.d.ts +3 -0
- package/dist/vanilla/components/VanillaSelect.js +93 -5
- package/dist/vanilla/components/appointment-booking/appointment-modal-styles.d.ts +272 -0
- package/dist/vanilla/components/appointment-booking/components/AppointmentConfirmationStep.d.ts +28 -0
- package/dist/vanilla/components/appointment-booking/components/AppointmentDateTimeModal.d.ts +18 -0
- package/dist/vanilla/components/appointment-booking/components/AppointmentSummaryStep.d.ts +12 -0
- package/dist/vanilla/components/appointment-booking/components/BookingOptionStep.d.ts +14 -0
- package/dist/vanilla/components/appointment-booking/components/DoctorSelectModal.d.ts +14 -0
- package/dist/vanilla/components/appointment-booking/components/PatientDetailsStep.d.ts +3 -0
- package/dist/vanilla/components/appointment-booking/components/PatientSelectionStep.d.ts +12 -0
- package/dist/vanilla/components/appointment-booking/components/PhoneVerificationStep.d.ts +3 -0
- package/dist/vanilla/components/appointment-booking/components/SuccessStep.d.ts +5 -0
- package/dist/vanilla/components/appointment-booking/components/index.d.ts +9 -0
- package/dist/vanilla/components/appointment-booking/hooks/useAppointmentFlow.d.ts +0 -1
- package/dist/vanilla/components/appointment-booking/index.d.ts +2 -4
- package/dist/vanilla/components/appointment-booking/types.d.ts +167 -0
- package/dist/vanilla/components/appointment-modal-styles.d.ts +259 -0
- package/dist/vanilla/components/constant.d.ts +2 -0
- package/dist/vanilla/components/constants/constant.d.ts +2 -0
- package/dist/vanilla/components/constants/index.d.ts +3 -0
- package/dist/vanilla/components/constants/options.d.ts +13 -0
- package/dist/vanilla/components/constants/validation.d.ts +6 -0
- package/dist/vanilla/components/enquiry-form/EnquiryForm.d.ts +7 -0
- package/dist/vanilla/components/enquiry-form/components/ContactInformationStep.d.ts +13 -0
- package/dist/vanilla/components/enquiry-form/components/ContactPreferenceStep.d.ts +9 -0
- package/dist/vanilla/components/enquiry-form/components/InquiryDetailsStep.d.ts +10 -0
- package/dist/vanilla/components/enquiry-form/components/index.d.ts +3 -0
- package/dist/vanilla/components/enquiry-form/index.d.ts +2 -0
- package/dist/vanilla/components/index.d.ts +7 -3
- package/dist/vanilla/components/shared/icons/Check.d.ts +6 -0
- package/dist/vanilla/components/shared/icons/ChevronDownIcon.d.ts +4 -0
- package/dist/vanilla/components/shared/icons/ChevronLeft.d.ts +3 -0
- package/dist/vanilla/components/shared/icons/ChevronRight.d.ts +3 -0
- package/dist/vanilla/components/shared/icons/CloseIcon.d.ts +9 -0
- package/dist/vanilla/components/shared/icons/ConfirmationCheck.d.ts +1 -0
- package/dist/vanilla/components/shared/icons/ConsultationType.d.ts +1 -0
- package/dist/vanilla/components/shared/icons/Date&TimeIcon.d.ts +1 -0
- package/dist/vanilla/components/shared/icons/MapIcon.d.ts +1 -0
- package/dist/vanilla/components/shared/icons/MedosLogo.d.ts +3 -0
- package/dist/vanilla/components/shared/icons/PaymentMethodIcon.d.ts +1 -0
- package/dist/vanilla/components/shared/icons/SuccessIcon.d.ts +8 -0
- package/dist/vanilla/components/shared/icons/UserIcon.d.ts +1 -0
- package/dist/vanilla/components/shared/icons/index.d.ts +13 -0
- package/dist/vanilla/components/shared/index.d.ts +2 -0
- package/dist/vanilla/components/shared/ui/Calendar.d.ts +5 -0
- package/dist/vanilla/components/shared/ui/SelectDropdown.d.ts +41 -0
- package/dist/vanilla/components/shared/ui/index.d.ts +2 -0
- package/dist/vanilla/components/styles/appointment.d.ts +4 -0
- package/dist/vanilla/components/styles/enquiry.d.ts +2 -0
- package/dist/vanilla/components/styles/index.d.ts +2 -0
- package/dist/vanilla/components/styles/shared.d.ts +3 -0
- package/dist/vanilla/components/styles.d.ts +1 -6
- package/dist/vanilla/components/theme-styles.d.ts +5 -4
- package/dist/vanilla/components/types/appointment.d.ts +42 -0
- package/dist/vanilla/components/types/common.d.ts +24 -0
- package/dist/vanilla/components/types/enquiry.d.ts +59 -0
- package/dist/vanilla/components/types/index.d.ts +4 -0
- package/dist/vanilla/components/types.d.ts +1 -52
- package/dist/vanilla/components/utils/date.d.ts +4 -0
- package/dist/vanilla/components/utils/formatting.d.ts +4 -0
- package/dist/vanilla/components/utils/index.d.ts +3 -0
- package/dist/vanilla/components/utils/validation.d.ts +4 -0
- package/dist/vanilla/components/utils.d.ts +1 -5
- package/dist/vanilla/components/validation.d.ts +1 -2
- package/dist/vanilla/constants/index.d.ts +1 -1
- package/dist/vanilla/core/theme/index.d.ts +1 -0
- package/dist/vanilla/core/theme/responsive.d.ts +15 -0
- package/dist/vanilla/core/theme/types.d.ts +8 -0
- package/dist/vanilla/enquiry-widget.js +3632 -90
- package/dist/vanilla/index.d.ts +4 -2
- package/dist/vanilla/react/ThemeProvider.d.ts +2 -1
- package/dist/vanilla/react/index.d.ts +3 -3
- package/dist/vanilla/services/AppointmentService.d.ts +80 -2
- package/dist/vanilla/services/WorkspaceService.d.ts +58 -3
- package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +17 -7
- package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +1 -0
- package/dist/vanilla/vanilla/components/VanillaIcons.d.ts +5 -0
- package/dist/vanilla/vanilla/components/VanillaSelect.d.ts +3 -0
- package/dist/vanilla/widget.css +1045 -205
- package/dist/vanilla/widget.js +10365 -5737
- package/package.json +2 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { AppointmentService, } from "../services/AppointmentService";
|
|
2
2
|
import { PatientService } from "../services/PatientService";
|
|
3
3
|
import { MedosClient } from "../client/MedosClient";
|
|
4
|
-
import { INITIAL_STATE,
|
|
5
|
-
import {
|
|
4
|
+
import { INITIAL_STATE, } from "../components/appointment-booking/types";
|
|
5
|
+
import { COUNTRY_CODES, GENDER_OPTIONS, BLOOD_GROUP_OPTIONS, mapBloodGroupToApi, } from "../components/constants/options";
|
|
6
|
+
import { validatePhoneNumber, validateCountryCode, validateDateOfBirth, validateBloodGroup, } from "../components/validation";
|
|
6
7
|
import { formatDateToISO, parsePatientName } from "../components/utils";
|
|
7
8
|
import { VanillaIcons } from "./components/VanillaIcons";
|
|
8
9
|
import { VanillaSelect } from "./components/VanillaSelect";
|
|
@@ -207,18 +208,58 @@ class AppointmentCalendarWidget {
|
|
|
207
208
|
return true;
|
|
208
209
|
}
|
|
209
210
|
updateSubmitButtonState() {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
this.state.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
211
|
+
try {
|
|
212
|
+
const submitBtn = this.container.querySelector("#medos-btn-submit");
|
|
213
|
+
if (submitBtn) {
|
|
214
|
+
const canSubmit = this.state.patientName &&
|
|
215
|
+
this.state.patientAddress &&
|
|
216
|
+
this.state.patientCity &&
|
|
217
|
+
this.state.patientState &&
|
|
218
|
+
this.state.patientCountry &&
|
|
219
|
+
this.state.patientZipcode &&
|
|
220
|
+
this.state.patientAge &&
|
|
221
|
+
this.state.patientGender &&
|
|
222
|
+
this.state.otpVerified &&
|
|
223
|
+
(!(this.state.patientDob && this.state.patientDob.trim() !== "") ||
|
|
224
|
+
this.isValidDateOfBirth(this.state.patientDob)) &&
|
|
225
|
+
(!(this.state.bloodGroup && this.state.bloodGroup.trim() !== "") ||
|
|
226
|
+
this.isValidBloodGroup(this.state.bloodGroup));
|
|
227
|
+
submitBtn.disabled = !(canSubmit && !this.state.loading);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
console.error("Error updating submit button state:", error);
|
|
232
|
+
const submitBtn = this.container.querySelector("#medos-btn-submit");
|
|
233
|
+
if (submitBtn) {
|
|
234
|
+
submitBtn.disabled = true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
updatePatientDetailsButtonState() {
|
|
239
|
+
try {
|
|
240
|
+
const continueBtn = this.container.querySelector("#medos-btn-continue");
|
|
241
|
+
if (continueBtn) {
|
|
242
|
+
const isFormValid = this.state.patientName &&
|
|
243
|
+
this.state.patientAge &&
|
|
244
|
+
this.state.patientGender &&
|
|
245
|
+
this.state.patientAddress &&
|
|
246
|
+
this.state.patientCity &&
|
|
247
|
+
this.state.patientState &&
|
|
248
|
+
this.state.patientCountry &&
|
|
249
|
+
this.state.patientZipcode &&
|
|
250
|
+
(!(this.state.patientDob && this.state.patientDob.trim() !== "") ||
|
|
251
|
+
this.isValidDateOfBirth(this.state.patientDob)) &&
|
|
252
|
+
(!(this.state.bloodGroup && this.state.bloodGroup.trim() !== "") ||
|
|
253
|
+
this.isValidBloodGroup(this.state.bloodGroup));
|
|
254
|
+
continueBtn.disabled = !isFormValid;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
console.error("Error updating patient details button state:", error);
|
|
259
|
+
const continueBtn = this.container.querySelector("#medos-btn-continue");
|
|
260
|
+
if (continueBtn) {
|
|
261
|
+
continueBtn.disabled = true;
|
|
262
|
+
}
|
|
222
263
|
}
|
|
223
264
|
}
|
|
224
265
|
async sendOtp() {
|
|
@@ -319,6 +360,9 @@ class AppointmentCalendarWidget {
|
|
|
319
360
|
!this.state.selectedSlot ||
|
|
320
361
|
!this.state.workspaceId ||
|
|
321
362
|
!this.state.selectedAddress ||
|
|
363
|
+
!this.state.patientName ||
|
|
364
|
+
!this.state.patientAge ||
|
|
365
|
+
!this.state.patientGender ||
|
|
322
366
|
!this.state.patientAddress ||
|
|
323
367
|
!this.state.patientCity ||
|
|
324
368
|
!this.state.patientState ||
|
|
@@ -333,6 +377,40 @@ class AppointmentCalendarWidget {
|
|
|
333
377
|
this.setState({ error: "Please verify your phone number first." });
|
|
334
378
|
return;
|
|
335
379
|
}
|
|
380
|
+
if (this.state.patientDob && this.state.patientDob.trim() !== "") {
|
|
381
|
+
if (!this.isValidDateOfBirth(this.state.patientDob)) {
|
|
382
|
+
const dobValue = this.state.patientDob;
|
|
383
|
+
const today = new Date();
|
|
384
|
+
const inputDate = new Date(dobValue);
|
|
385
|
+
if (inputDate > today) {
|
|
386
|
+
this.displayFieldValidationError("dateOfBirth", "future");
|
|
387
|
+
}
|
|
388
|
+
else if (!/^\d{4}-\d{2}-\d{2}$/.test(dobValue)) {
|
|
389
|
+
this.displayFieldValidationError("dateOfBirth", "format");
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
this.displayFieldValidationError("dateOfBirth", "invalid");
|
|
393
|
+
}
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (this.state.bloodGroup && this.state.bloodGroup.trim() !== "") {
|
|
398
|
+
if (!this.isValidBloodGroup(this.state.bloodGroup)) {
|
|
399
|
+
this.displayFieldValidationError("bloodGroup", "invalid");
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
try {
|
|
403
|
+
const mappedValue = this.safeMapBloodGroupToApi(this.state.bloodGroup);
|
|
404
|
+
if (mappedValue === "UNKNOWN" && this.state.bloodGroup !== "UNKNOWN") {
|
|
405
|
+
this.displayFieldValidationError("bloodGroup", "mapping");
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
catch (error) {
|
|
410
|
+
this.displayFieldValidationError("bloodGroup", "mapping");
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
336
414
|
this.setState({ loading: true });
|
|
337
415
|
this.render();
|
|
338
416
|
try {
|
|
@@ -359,11 +437,11 @@ class AppointmentCalendarWidget {
|
|
|
359
437
|
workspaceId: this.state.workspaceId,
|
|
360
438
|
workspaceAddressId: this.state.selectedAddress,
|
|
361
439
|
doctorId: this.state.selectedDoctor,
|
|
362
|
-
mode: "OFFLINE",
|
|
440
|
+
mode: this.state.consultationMode || "OFFLINE",
|
|
363
441
|
appointmentDate,
|
|
364
442
|
fromDateTimeTs,
|
|
365
443
|
toDateTimeTs,
|
|
366
|
-
consultationCharge: this.state.
|
|
444
|
+
consultationCharge: this.state.consultationMode === "ONLINE" ? "500" : "300",
|
|
367
445
|
type: "CONSULTATION",
|
|
368
446
|
source: "SDK_POWERED_WEBSITE",
|
|
369
447
|
patientPayload: {
|
|
@@ -378,10 +456,12 @@ class AppointmentCalendarWidget {
|
|
|
378
456
|
gender: this.state.patientGender
|
|
379
457
|
? this.state.patientGender.toUpperCase()
|
|
380
458
|
: undefined,
|
|
459
|
+
dob: this.safeFormatDateOfBirth(this.state.patientDob),
|
|
460
|
+
bloodGroup: this.safeMapBloodGroupToApi(this.state.bloodGroup),
|
|
381
461
|
},
|
|
382
462
|
patientAddress: patientAddressPayload,
|
|
383
463
|
});
|
|
384
|
-
this.state.step =
|
|
464
|
+
this.state.step = 7;
|
|
385
465
|
this.options.onSuccess?.();
|
|
386
466
|
}
|
|
387
467
|
catch (e) {
|
|
@@ -396,34 +476,112 @@ class AppointmentCalendarWidget {
|
|
|
396
476
|
}
|
|
397
477
|
goToNext() {
|
|
398
478
|
if (this.state.step === 0) {
|
|
479
|
+
if (!this.state.otpVerified)
|
|
480
|
+
return;
|
|
481
|
+
this.state.step = 1;
|
|
482
|
+
this.render();
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
if (this.state.step === 1) {
|
|
486
|
+
if (!this.state.bookingOptionType)
|
|
487
|
+
return;
|
|
488
|
+
if (this.state.showPackageExplorer) {
|
|
489
|
+
if (this.state.selectedNewPackage) {
|
|
490
|
+
this.state.showPackageExplorer = false;
|
|
491
|
+
this.state.step = 2;
|
|
492
|
+
this.render();
|
|
493
|
+
}
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
this.state.step = 2;
|
|
497
|
+
this.render();
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
if (this.state.step === 2) {
|
|
399
501
|
if (this.state.addresses.length > 1 && !this.state.selectedAddress)
|
|
400
502
|
return;
|
|
401
503
|
if (this.doctors.length > 1 && !this.state.selectedDoctor)
|
|
402
504
|
return;
|
|
505
|
+
this.state.step = 3;
|
|
506
|
+
const dateStr = formatDateToISO(this.state.selectedDate);
|
|
507
|
+
if (dateStr) {
|
|
508
|
+
this.loadSlots();
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
this.render();
|
|
512
|
+
}
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
if (this.state.step === 3) {
|
|
516
|
+
const dateStr = formatDateToISO(this.state.selectedDate);
|
|
517
|
+
if (!dateStr || !this.state.selectedSlot)
|
|
518
|
+
return;
|
|
519
|
+
this.state.step = 4;
|
|
520
|
+
this.render();
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
if (this.state.step === 4) {
|
|
524
|
+
if (!this.state.selectedPatient)
|
|
525
|
+
return;
|
|
526
|
+
this.state.step = 5;
|
|
527
|
+
this.render();
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
if (this.state.step === 5) {
|
|
531
|
+
const isFormValid = this.state.patientName &&
|
|
532
|
+
this.state.patientAge &&
|
|
533
|
+
this.state.patientGender &&
|
|
534
|
+
this.state.patientAddress &&
|
|
535
|
+
this.state.patientCity &&
|
|
536
|
+
this.state.patientState &&
|
|
537
|
+
this.state.patientCountry &&
|
|
538
|
+
this.state.patientZipcode;
|
|
539
|
+
if (!isFormValid)
|
|
540
|
+
return;
|
|
541
|
+
this.state.step = 6;
|
|
542
|
+
this.render();
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
this.state.step = Math.min(7, this.state.step + 1);
|
|
546
|
+
this.render();
|
|
547
|
+
}
|
|
548
|
+
goBack() {
|
|
549
|
+
if (this.state.step === 1) {
|
|
550
|
+
if (this.state.showPackageExplorer) {
|
|
551
|
+
this.state.showPackageExplorer = false;
|
|
552
|
+
this.state.selectedNewPackage = null;
|
|
553
|
+
this.render();
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
this.state.step = 0;
|
|
557
|
+
this.render();
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
if (this.state.step === 2) {
|
|
403
561
|
this.state.step = 1;
|
|
404
562
|
this.render();
|
|
405
563
|
return;
|
|
406
564
|
}
|
|
407
|
-
|
|
408
|
-
if (this.state.step === 1 && dateStr) {
|
|
565
|
+
if (this.state.step === 3) {
|
|
409
566
|
this.state.step = 2;
|
|
410
|
-
this.
|
|
567
|
+
this.render();
|
|
411
568
|
return;
|
|
412
569
|
}
|
|
413
|
-
if (this.state.step ===
|
|
570
|
+
if (this.state.step === 4) {
|
|
414
571
|
this.state.step = 3;
|
|
415
572
|
this.render();
|
|
416
573
|
return;
|
|
417
574
|
}
|
|
418
|
-
if (this.state.step ===
|
|
575
|
+
if (this.state.step === 5) {
|
|
419
576
|
this.state.step = 4;
|
|
420
577
|
this.render();
|
|
421
578
|
return;
|
|
422
579
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
580
|
+
if (this.state.step === 6) {
|
|
581
|
+
this.state.step = 5;
|
|
582
|
+
this.render();
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
427
585
|
this.state.step = Math.max(0, this.state.step - 1);
|
|
428
586
|
this.render();
|
|
429
587
|
}
|
|
@@ -434,7 +592,25 @@ class AppointmentCalendarWidget {
|
|
|
434
592
|
this.render();
|
|
435
593
|
}
|
|
436
594
|
setState(updates) {
|
|
437
|
-
|
|
595
|
+
try {
|
|
596
|
+
const safeUpdates = { ...updates };
|
|
597
|
+
if ("bloodGroup" in safeUpdates && safeUpdates.bloodGroup === undefined) {
|
|
598
|
+
safeUpdates.bloodGroup = "";
|
|
599
|
+
}
|
|
600
|
+
if ("patientDob" in safeUpdates && safeUpdates.patientDob === undefined) {
|
|
601
|
+
safeUpdates.patientDob = "";
|
|
602
|
+
}
|
|
603
|
+
this.state = { ...this.state, ...safeUpdates };
|
|
604
|
+
if (safeUpdates.bloodGroup !== undefined ||
|
|
605
|
+
safeUpdates.patientDob !== undefined) {
|
|
606
|
+
this.updatePatientDetailsButtonState();
|
|
607
|
+
this.updateSubmitButtonState();
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
catch (error) {
|
|
611
|
+
console.error("Error updating state:", error);
|
|
612
|
+
this.state = { ...this.state, ...updates };
|
|
613
|
+
}
|
|
438
614
|
}
|
|
439
615
|
render() {
|
|
440
616
|
if (!this.mounted)
|
|
@@ -444,13 +620,6 @@ class AppointmentCalendarWidget {
|
|
|
444
620
|
<div class="medos-appointment-card">
|
|
445
621
|
<div class="medos-appointment-header">
|
|
446
622
|
<h2 class="medos-appointment-title">Book Appointment</h2>
|
|
447
|
-
<div class="medos-appointment-stepper">
|
|
448
|
-
<div class="medos-appointment-step-pill ${this.state.step === 0 ? "active" : ""}">1 Address</div>
|
|
449
|
-
<div class="medos-appointment-step-pill ${this.state.step === 1 ? "active" : ""}">2 Date</div>
|
|
450
|
-
<div class="medos-appointment-step-pill ${this.state.step === 2 ? "active" : ""}">3 Slot</div>
|
|
451
|
-
<div class="medos-appointment-step-pill ${this.state.step === 3 ? "active" : ""}">4 Phone</div>
|
|
452
|
-
<div class="medos-appointment-step-pill ${this.state.step === 4 ? "active" : ""}">5 Details</div>
|
|
453
|
-
</div>
|
|
454
623
|
</div>
|
|
455
624
|
|
|
456
625
|
${this.state.loading
|
|
@@ -469,6 +638,30 @@ class AppointmentCalendarWidget {
|
|
|
469
638
|
}
|
|
470
639
|
initializeCustomComponents() {
|
|
471
640
|
if (this.state.step === 0) {
|
|
641
|
+
const countryCodeContainer = this.container.querySelector("#medos-country-code-container");
|
|
642
|
+
if (countryCodeContainer) {
|
|
643
|
+
const countryOptions = COUNTRY_CODES.map((c) => ({
|
|
644
|
+
value: c.code,
|
|
645
|
+
label: c.label,
|
|
646
|
+
}));
|
|
647
|
+
this.countryCodeSelect = new VanillaSelect(countryCodeContainer, countryOptions, {
|
|
648
|
+
placeholder: "Country",
|
|
649
|
+
onValueChange: (value) => {
|
|
650
|
+
this.state.countryCode = value;
|
|
651
|
+
const sendOtpBtn = this.container.querySelector("#medos-btn-send-otp");
|
|
652
|
+
if (sendOtpBtn) {
|
|
653
|
+
const canSendOtp = this.state.countryCode &&
|
|
654
|
+
this.state.patientPhone.length >= 10;
|
|
655
|
+
sendOtpBtn.disabled = !canSendOtp;
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
});
|
|
659
|
+
if (this.state.countryCode) {
|
|
660
|
+
this.countryCodeSelect.setValue(this.state.countryCode);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (this.state.step === 2 && !this.state.showPackageExplorer) {
|
|
472
665
|
const addressContainer = this.container.querySelector("#medos-address-select-container");
|
|
473
666
|
if (addressContainer && this.state.addresses.length > 0) {
|
|
474
667
|
const addressOptions = this.state.addresses.map((a) => ({
|
|
@@ -496,7 +689,7 @@ class AppointmentCalendarWidget {
|
|
|
496
689
|
onValueChange: (value) => {
|
|
497
690
|
this.state.selectedDoctor = Number(value) || null;
|
|
498
691
|
const selectedDoc = this.doctors.find((d) => d.id === this.state.selectedDoctor);
|
|
499
|
-
if (selectedDoc
|
|
692
|
+
if (selectedDoc?.consultationCharge) {
|
|
500
693
|
this.state.consultationCharge = selectedDoc.consultationCharge;
|
|
501
694
|
}
|
|
502
695
|
this.render();
|
|
@@ -507,7 +700,7 @@ class AppointmentCalendarWidget {
|
|
|
507
700
|
}
|
|
508
701
|
}
|
|
509
702
|
}
|
|
510
|
-
if (this.state.step ===
|
|
703
|
+
if (this.state.step === 3) {
|
|
511
704
|
const calendarContainer = this.container.querySelector("#medos-calendar-container");
|
|
512
705
|
if (calendarContainer) {
|
|
513
706
|
this.calendar = new VanillaCalendar(calendarContainer, {
|
|
@@ -515,55 +708,59 @@ class AppointmentCalendarWidget {
|
|
|
515
708
|
pastDisabled: true,
|
|
516
709
|
onSelect: (date) => {
|
|
517
710
|
this.state.selectedDate = date;
|
|
518
|
-
this.
|
|
519
|
-
},
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
if (this.state.step === 3) {
|
|
524
|
-
const countryCodeContainer = this.container.querySelector("#medos-country-code-container");
|
|
525
|
-
if (countryCodeContainer) {
|
|
526
|
-
const countryOptions = COUNTRY_CODES.map((c) => ({
|
|
527
|
-
value: c.code,
|
|
528
|
-
label: c.label,
|
|
529
|
-
}));
|
|
530
|
-
this.countryCodeSelect = new VanillaSelect(countryCodeContainer, countryOptions, {
|
|
531
|
-
placeholder: "Country",
|
|
532
|
-
onValueChange: (value) => {
|
|
533
|
-
this.state.countryCode = value;
|
|
534
|
-
const sendOtpBtn = this.container.querySelector("#medos-btn-send-otp");
|
|
535
|
-
if (sendOtpBtn) {
|
|
536
|
-
const canSendOtp = this.state.countryCode &&
|
|
537
|
-
this.state.patientPhone.length >= 10;
|
|
538
|
-
sendOtpBtn.disabled = !canSendOtp;
|
|
539
|
-
}
|
|
711
|
+
this.loadSlots();
|
|
540
712
|
},
|
|
541
713
|
});
|
|
542
|
-
if (this.state.countryCode) {
|
|
543
|
-
this.countryCodeSelect.setValue(this.state.countryCode);
|
|
544
|
-
}
|
|
545
714
|
}
|
|
546
715
|
}
|
|
547
|
-
if (this.state.step ===
|
|
548
|
-
const genderContainer = this.container.querySelector("#medos-gender-container");
|
|
716
|
+
if (this.state.step === 5) {
|
|
717
|
+
const genderContainer = this.container.querySelector("#medos-gender-select-container");
|
|
549
718
|
if (genderContainer) {
|
|
550
|
-
|
|
719
|
+
const genderOptions = GENDER_OPTIONS.map((g) => ({
|
|
720
|
+
value: g.value,
|
|
721
|
+
label: g.label,
|
|
722
|
+
}));
|
|
723
|
+
this.genderSelect = new VanillaSelect(genderContainer, genderOptions, {
|
|
551
724
|
placeholder: "Select gender",
|
|
552
725
|
onValueChange: (value) => {
|
|
553
726
|
this.state.patientGender = value;
|
|
554
|
-
this.
|
|
727
|
+
this.updatePatientDetailsButtonState();
|
|
555
728
|
},
|
|
556
729
|
});
|
|
557
730
|
if (this.state.patientGender) {
|
|
558
731
|
this.genderSelect.setValue(this.state.patientGender);
|
|
559
732
|
}
|
|
560
733
|
}
|
|
561
|
-
const bloodGroupContainer = this.container.querySelector("#medos-blood-group-container");
|
|
734
|
+
const bloodGroupContainer = this.container.querySelector("#medos-blood-group-select-container");
|
|
562
735
|
if (bloodGroupContainer) {
|
|
563
|
-
|
|
736
|
+
const bloodGroupOptions = BLOOD_GROUP_OPTIONS.map((bg) => ({
|
|
737
|
+
value: bg.value,
|
|
738
|
+
label: bg.label,
|
|
739
|
+
}));
|
|
740
|
+
this.bloodGroupSelect = new VanillaSelect(bloodGroupContainer, bloodGroupOptions, {
|
|
564
741
|
placeholder: "Select blood group (optional)",
|
|
565
742
|
onValueChange: (value) => {
|
|
566
|
-
this.
|
|
743
|
+
this.setState({ error: null });
|
|
744
|
+
try {
|
|
745
|
+
if (value && value.trim() !== "") {
|
|
746
|
+
if (!this.isValidBloodGroup(value)) {
|
|
747
|
+
this.displayFieldValidationError("bloodGroup", "invalid");
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
const mappedValue = this.safeMapBloodGroupToApi(value);
|
|
751
|
+
if (mappedValue === "UNKNOWN" && value !== "UNKNOWN") {
|
|
752
|
+
this.displayFieldValidationError("bloodGroup", "mapping");
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
this.setState({ bloodGroup: value });
|
|
757
|
+
this.updatePatientDetailsButtonState();
|
|
758
|
+
this.updateSubmitButtonState();
|
|
759
|
+
}
|
|
760
|
+
catch (error) {
|
|
761
|
+
console.error("Blood group selection error:", error);
|
|
762
|
+
this.displayFieldValidationError("bloodGroup", "mapping");
|
|
763
|
+
}
|
|
567
764
|
},
|
|
568
765
|
});
|
|
569
766
|
if (this.state.bloodGroup) {
|
|
@@ -575,147 +772,357 @@ class AppointmentCalendarWidget {
|
|
|
575
772
|
renderStep() {
|
|
576
773
|
switch (this.state.step) {
|
|
577
774
|
case 0:
|
|
578
|
-
return this.
|
|
775
|
+
return this.renderPhoneVerificationStep();
|
|
579
776
|
case 1:
|
|
580
|
-
return this.
|
|
777
|
+
return this.renderBookingOptionStep();
|
|
581
778
|
case 2:
|
|
582
|
-
return this.
|
|
779
|
+
return this.state.showPackageExplorer
|
|
780
|
+
? this.renderPackageExplorerStep()
|
|
781
|
+
: this.renderLocationDoctorStep();
|
|
583
782
|
case 3:
|
|
584
|
-
return this.
|
|
783
|
+
return this.renderNewAppointmentStep();
|
|
585
784
|
case 4:
|
|
586
|
-
return this.
|
|
785
|
+
return this.renderPatientSelectionStep();
|
|
587
786
|
case 5:
|
|
588
|
-
return this.
|
|
787
|
+
return this.renderPatientDetailsStep();
|
|
788
|
+
case 6:
|
|
789
|
+
return this.renderAppointmentSummaryStep();
|
|
790
|
+
case 7:
|
|
791
|
+
return this.renderSuccessStep();
|
|
589
792
|
default:
|
|
590
793
|
return "";
|
|
591
794
|
}
|
|
592
795
|
}
|
|
593
|
-
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
<label style="display:block;font-size:13px;margin-bottom:6px;color:#374151;">
|
|
604
|
-
Preferred Location <span style="color:#EF4444">*</span>
|
|
605
|
-
</label>
|
|
606
|
-
<div id="medos-address-select-container"></div>
|
|
796
|
+
renderPhoneVerificationStep() {
|
|
797
|
+
const countryCodeValid = this.state.countryCode && validateCountryCode(this.state.countryCode);
|
|
798
|
+
const phoneValid = this.state.patientPhone && validatePhoneNumber(this.state.patientPhone);
|
|
799
|
+
const canSendOtp = countryCodeValid && phoneValid && !this.state.otpSending;
|
|
800
|
+
if (!this.state.otpSent) {
|
|
801
|
+
return `
|
|
802
|
+
<div class="medos-section-card">
|
|
803
|
+
<div class="medos-section-header">
|
|
804
|
+
${VanillaIcons.phone(14)}
|
|
805
|
+
<span class="medos-section-title">Search Patient</span>
|
|
607
806
|
</div>
|
|
608
|
-
<div
|
|
609
|
-
<
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
807
|
+
<div class="medos-section-body">
|
|
808
|
+
<p class="medos-section-description">Enter Phone Number</p>
|
|
809
|
+
<div class="medos-phone-input-row">
|
|
810
|
+
<div class="medos-country-code-wrapper">
|
|
811
|
+
<div id="medos-country-code-container"></div>
|
|
812
|
+
</div>
|
|
813
|
+
<div class="medos-phone-wrapper">
|
|
814
|
+
<input
|
|
815
|
+
type="tel"
|
|
816
|
+
class="medos-input"
|
|
817
|
+
id="medos-phone"
|
|
818
|
+
placeholder="XXXXXXXXXX"
|
|
819
|
+
value="${this.escapeHtml(this.state.patientPhone)}"
|
|
820
|
+
maxlength="15"
|
|
821
|
+
/>
|
|
822
|
+
</div>
|
|
823
|
+
</div>
|
|
824
|
+
${this.state.patientPhone && !phoneValid
|
|
825
|
+
? '<div class="medos-validation-error">Phone number should be 7-15 digits</div>'
|
|
826
|
+
: ""}
|
|
613
827
|
</div>
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
828
|
+
</div>
|
|
829
|
+
<div class="medos-actions">
|
|
830
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
831
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-send-otp" ${canSendOtp ? "" : "disabled"}>${this.state.otpSending ? "Sending..." : "Continue"}</button>
|
|
832
|
+
</div>
|
|
833
|
+
`;
|
|
834
|
+
}
|
|
835
|
+
if (this.state.otpVerified) {
|
|
836
|
+
return `
|
|
837
|
+
<div class="medos-section-card">
|
|
838
|
+
<div class="medos-section-header">
|
|
839
|
+
${VanillaIcons.phone(14)}
|
|
840
|
+
<span class="medos-section-title">Search Patient</span>
|
|
841
|
+
</div>
|
|
842
|
+
<div class="medos-section-body">
|
|
843
|
+
<div class="medos-verified-badge">
|
|
844
|
+
${VanillaIcons.successBadge(20)}
|
|
845
|
+
<span>Phone verified successfully</span>
|
|
846
|
+
</div>
|
|
847
|
+
<div class="medos-verified-number">${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</div>
|
|
624
848
|
</div>
|
|
625
849
|
</div>
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
renderStep1() {
|
|
633
|
-
const dateStr = formatDateToISO(this.state.selectedDate);
|
|
634
|
-
const selectedDoctor = this.doctors.find((d) => d.id === this.state.selectedDoctor);
|
|
635
|
-
const selectedDoctorData = this.doctors.find((d) => d.id === this.state.selectedDoctor);
|
|
636
|
-
const consultationCharge = selectedDoctorData?.consultationCharge ||
|
|
637
|
-
selectedDoctor?.consultationCharge ||
|
|
638
|
-
this.state.consultationCharge ||
|
|
639
|
-
"N/A";
|
|
850
|
+
<div class="medos-actions">
|
|
851
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
852
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-next">Continue</button>
|
|
853
|
+
</div>
|
|
854
|
+
`;
|
|
855
|
+
}
|
|
640
856
|
return `
|
|
641
857
|
<div class="medos-section-card">
|
|
642
858
|
<div class="medos-section-header">
|
|
643
|
-
${VanillaIcons.
|
|
644
|
-
<span class="medos-section-title">
|
|
859
|
+
${VanillaIcons.phone(14)}
|
|
860
|
+
<span class="medos-section-title">Enter OTP</span>
|
|
645
861
|
</div>
|
|
646
862
|
<div class="medos-section-body">
|
|
647
|
-
<
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
</label>
|
|
658
|
-
<label class="medos-radio-option ${this.state.consultationMode === "ONLINE" ? "selected" : ""}">
|
|
659
|
-
<input
|
|
660
|
-
type="radio"
|
|
661
|
-
name="consultationMode"
|
|
662
|
-
value="ONLINE"
|
|
663
|
-
${this.state.consultationMode === "ONLINE" ? "checked" : ""}
|
|
664
|
-
class="medos-radio-input"
|
|
665
|
-
/>
|
|
666
|
-
<span class="medos-radio-label">Online Consultation</span>
|
|
667
|
-
</label>
|
|
863
|
+
<p class="medos-section-description">Enter the 6-digit code sent to ${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</p>
|
|
864
|
+
<div class="medos-otp-input-wrapper">
|
|
865
|
+
<input
|
|
866
|
+
type="text"
|
|
867
|
+
class="medos-input medos-otp-input"
|
|
868
|
+
id="medos-otp"
|
|
869
|
+
placeholder="Enter 6-digit OTP"
|
|
870
|
+
value="${this.escapeHtml(this.state.otpCode)}"
|
|
871
|
+
maxlength="6"
|
|
872
|
+
/>
|
|
668
873
|
</div>
|
|
669
|
-
<
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
874
|
+
<button class="medos-link-btn" id="medos-btn-change-number">Change phone number</button>
|
|
875
|
+
</div>
|
|
876
|
+
</div>
|
|
877
|
+
<div class="medos-actions">
|
|
878
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-resend-otp">Resend OTP</button>
|
|
879
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-verify-otp" ${this.state.otpCode.length === 6 && !this.state.otpVerifying
|
|
880
|
+
? ""
|
|
881
|
+
: "disabled"}>${this.state.otpVerifying ? "Verifying..." : "Verify OTP"}</button>
|
|
882
|
+
</div>
|
|
883
|
+
`;
|
|
884
|
+
}
|
|
885
|
+
renderBookingOptionStep() {
|
|
886
|
+
const hasActivePacks = this.state.userSessionPacks.length > 0;
|
|
887
|
+
const activePack = this.state.userSessionPacks.find((p) => p.remainingSessions > 0);
|
|
888
|
+
return `
|
|
889
|
+
<div class="medos-section-card">
|
|
890
|
+
<div class="medos-section-header">
|
|
891
|
+
${VanillaIcons.calendar(14)}
|
|
892
|
+
<span class="medos-section-title">Choose Booking Option</span>
|
|
893
|
+
</div>
|
|
894
|
+
<div class="medos-section-body">
|
|
895
|
+
<p class="medos-section-description">Select a package to explore on offer</p>
|
|
896
|
+
|
|
897
|
+
${hasActivePacks && activePack
|
|
898
|
+
? `
|
|
899
|
+
<div class="medos-active-session-packs">
|
|
900
|
+
<label class="medos-form-label">YOUR ACTIVE SESSION PACKS</label>
|
|
901
|
+
<div class="medos-session-pack-card ${this.state.bookingOptionType === "session-pack"
|
|
902
|
+
? "selected"
|
|
903
|
+
: ""}" data-pack-id="${activePack.id}">
|
|
904
|
+
<div class="medos-pack-header">
|
|
905
|
+
<span class="medos-pack-name">${this.escapeHtml(activePack.name)}</span>
|
|
906
|
+
<span class="medos-pack-badge">${activePack.remainingSessions} sessions</span>
|
|
907
|
+
</div>
|
|
908
|
+
<div class="medos-pack-details">
|
|
909
|
+
${activePack.remainingSessions} of ${activePack.totalSessions} sessions • <a href="#" class="medos-link">view details</a>
|
|
910
|
+
</div>
|
|
911
|
+
</div>
|
|
912
|
+
</div>
|
|
913
|
+
`
|
|
914
|
+
: ""}
|
|
915
|
+
|
|
916
|
+
<div class="medos-other-options">
|
|
917
|
+
<label class="medos-form-label">OTHER OPTIONS</label>
|
|
918
|
+
|
|
919
|
+
<div class="medos-option-cards">
|
|
920
|
+
<div class="medos-option-card ${this.state.bookingOptionType === "new-appointment"
|
|
921
|
+
? "selected"
|
|
922
|
+
: ""}" data-option="new-appointment">
|
|
923
|
+
<div class="medos-option-icon">${VanillaIcons.calendar(24)}</div>
|
|
924
|
+
<div class="medos-option-content">
|
|
925
|
+
<span class="medos-option-title">Standard Consultation</span>
|
|
926
|
+
<span class="medos-option-subtitle">Pay per appointment</span>
|
|
927
|
+
</div>
|
|
928
|
+
</div>
|
|
929
|
+
|
|
930
|
+
<div class="medos-option-card ${this.state.bookingOptionType === "explore-packages"
|
|
931
|
+
? "selected"
|
|
932
|
+
: ""}" data-option="explore-packages">
|
|
933
|
+
<div class="medos-option-icon">${VanillaIcons.giftBox(24)}</div>
|
|
934
|
+
<div class="medos-option-content">
|
|
935
|
+
<span class="medos-option-title">Session Packs</span>
|
|
936
|
+
<span class="medos-option-subtitle">Explore packs with discounts and offers</span>
|
|
937
|
+
</div>
|
|
938
|
+
</div>
|
|
939
|
+
</div>
|
|
674
940
|
</div>
|
|
675
941
|
</div>
|
|
676
942
|
</div>
|
|
677
|
-
|
|
943
|
+
<div class="medos-actions">
|
|
944
|
+
<button class="medos-btn medos-btn-back" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
945
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
946
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-continue">Continue</button>
|
|
947
|
+
</div>
|
|
948
|
+
`;
|
|
949
|
+
}
|
|
950
|
+
renderPackageExplorerStep() {
|
|
951
|
+
const packages = this.state.availablePackages.length > 0
|
|
952
|
+
? this.state.availablePackages
|
|
953
|
+
: [
|
|
954
|
+
{
|
|
955
|
+
id: 1,
|
|
956
|
+
name: "Silver Package",
|
|
957
|
+
description: "• 3 consultations (In clinic & Online appointments)\n• Can redeem for 6 months after\n purchase",
|
|
958
|
+
totalSessions: 3,
|
|
959
|
+
price: 5000,
|
|
960
|
+
validityDays: 180,
|
|
961
|
+
applicableOnline: true,
|
|
962
|
+
applicableOffline: true,
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
id: 2,
|
|
966
|
+
name: "Gold Package",
|
|
967
|
+
description: "• 5 consultations (In clinic & Online appointments)\n• Can redeem for 12 months after\n purchase",
|
|
968
|
+
totalSessions: 5,
|
|
969
|
+
price: 8000,
|
|
970
|
+
validityDays: 365,
|
|
971
|
+
applicableOnline: true,
|
|
972
|
+
applicableOffline: true,
|
|
973
|
+
},
|
|
974
|
+
];
|
|
975
|
+
return `
|
|
678
976
|
<div class="medos-section-card">
|
|
679
977
|
<div class="medos-section-header">
|
|
680
|
-
${VanillaIcons.
|
|
681
|
-
<span class="medos-section-title">
|
|
978
|
+
${VanillaIcons.giftBox(14)}
|
|
979
|
+
<span class="medos-section-title">Explore Session Packs</span>
|
|
682
980
|
</div>
|
|
683
981
|
<div class="medos-section-body">
|
|
684
|
-
<
|
|
982
|
+
<p class="medos-section-description">Select a package to explore on offer</p>
|
|
983
|
+
|
|
984
|
+
<div class="medos-available-packages">
|
|
985
|
+
<label class="medos-form-label">AVAILABLE PACKAGES</label>
|
|
986
|
+
|
|
987
|
+
${packages
|
|
988
|
+
.map((pkg, index) => `
|
|
989
|
+
<div class="medos-package-card ${this.state.selectedNewPackage?.id === pkg.id ? "selected" : ""}" data-package-id="${pkg.id}">
|
|
990
|
+
<div class="medos-package-radio">
|
|
991
|
+
<input type="radio" name="package" value="${pkg.id}" ${this.state.selectedNewPackage?.id === pkg.id ? "checked" : ""} />
|
|
992
|
+
</div>
|
|
993
|
+
<div class="medos-package-content">
|
|
994
|
+
<div class="medos-package-name">${this.escapeHtml(pkg.name)}</div>
|
|
995
|
+
<div class="medos-package-description">${this.escapeHtml(pkg.description || "").replace(/\n/g, "<br>")}</div>
|
|
996
|
+
</div>
|
|
997
|
+
<div class="medos-package-price">₹ ${pkg.price.toLocaleString()}</div>
|
|
998
|
+
</div>
|
|
999
|
+
`)
|
|
1000
|
+
.join("")}
|
|
1001
|
+
</div>
|
|
1002
|
+
|
|
1003
|
+
<div class="medos-package-note">
|
|
1004
|
+
<a href="#" class="medos-link">View full terms and conditions</a>
|
|
1005
|
+
</div>
|
|
685
1006
|
</div>
|
|
686
1007
|
</div>
|
|
687
|
-
|
|
688
1008
|
<div class="medos-actions">
|
|
689
|
-
<button class="medos-btn medos-btn-
|
|
690
|
-
<button class="medos-btn medos-btn-
|
|
1009
|
+
<button class="medos-btn medos-btn-back" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1010
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
1011
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${this.state.selectedNewPackage ? "" : "disabled"}>Continue</button>
|
|
691
1012
|
</div>
|
|
692
1013
|
`;
|
|
693
1014
|
}
|
|
694
|
-
|
|
1015
|
+
renderLocationDoctorStep() {
|
|
1016
|
+
const canProceed = this.canProceedFromMergedStep();
|
|
1017
|
+
return `
|
|
1018
|
+
<div style="border:1px solid #e5e7eb;border-radius:12px;margin-bottom:24px;background:#fff;">
|
|
1019
|
+
<div style="background:#F9FAFB;padding:16px 20px;display:flex;align-items:center;gap:12px;border-bottom:1px solid #E5E7EB;">
|
|
1020
|
+
${VanillaIcons.mapPin(18)}
|
|
1021
|
+
<h3 style="font-size:18px;font-weight:600;margin:0;">Location & Doctor</h3>
|
|
1022
|
+
</div>
|
|
1023
|
+
<div style="padding:24px;">
|
|
1024
|
+
<div style="margin-bottom:20px;">
|
|
1025
|
+
<label style="display:block;font-size:13px;margin-bottom:6px;color:#374151;">
|
|
1026
|
+
Preferred Location <span style="color:#EF4444">*</span>
|
|
1027
|
+
</label>
|
|
1028
|
+
<div id="medos-address-select-container"></div>
|
|
1029
|
+
</div>
|
|
1030
|
+
<div style="margin-bottom:20px;">
|
|
1031
|
+
<label style="display:block;font-size:13px;margin-bottom:6px;color:#374151;">
|
|
1032
|
+
Preferred Doctor <span style="color:#EF4444">*</span>
|
|
1033
|
+
</label>
|
|
1034
|
+
<div id="medos-doctor-select-container"></div>
|
|
1035
|
+
</div>
|
|
1036
|
+
<div style="margin-bottom:20px;">
|
|
1037
|
+
<label style="display:block;font-size:13px;margin-bottom:6px;color:#374151;">
|
|
1038
|
+
Chief Complaint <span style="color:#6B7280">(optional)</span>
|
|
1039
|
+
</label>
|
|
1040
|
+
<textarea
|
|
1041
|
+
style="width:100%;padding:10px 12px;border-radius:8px;border:1px solid #e6e9ef;font-size:14px;box-sizing:border-box;"
|
|
1042
|
+
class="medos-textarea"
|
|
1043
|
+
id="medos-chief-complaint"
|
|
1044
|
+
placeholder="Enter Chief Complaint or Appointment Notes"
|
|
1045
|
+
></textarea>
|
|
1046
|
+
</div>
|
|
1047
|
+
</div>
|
|
1048
|
+
</div>
|
|
1049
|
+
<div style="display:flex;gap:8px;margin-top:16px;justify-content:flex-end;">
|
|
1050
|
+
<button class="medos-btn medos-btn-back" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1051
|
+
<button style="background:#218838;color:#fff;border:none;padding:10px 14px;border-radius:8px;cursor:pointer;font-weight:600;${canProceed ? "" : "opacity:0.6;"}" id="medos-btn-next" ${canProceed ? "" : "disabled"}>Continue</button>
|
|
1052
|
+
</div>
|
|
1053
|
+
`;
|
|
1054
|
+
}
|
|
1055
|
+
renderNewAppointmentStep() {
|
|
1056
|
+
const dateStr = formatDateToISO(this.state.selectedDate);
|
|
1057
|
+
const consultationCharge = this.state.consultationMode === "ONLINE" ? "500" : "300";
|
|
695
1058
|
const dateDisplay = this.state.selectedDate
|
|
696
1059
|
? this.state.selectedDate.toLocaleDateString("en-US", {
|
|
697
|
-
weekday: "long",
|
|
698
1060
|
year: "numeric",
|
|
699
1061
|
month: "long",
|
|
700
1062
|
day: "numeric",
|
|
701
1063
|
})
|
|
702
1064
|
: "";
|
|
1065
|
+
const usingSessionPack = this.state.bookingOptionType === "session-pack" &&
|
|
1066
|
+
this.state.selectedSessionPack;
|
|
1067
|
+
const sessionInfo = usingSessionPack
|
|
1068
|
+
? `
|
|
1069
|
+
<div class="medos-session-info">
|
|
1070
|
+
<span class="medos-session-label">Sessions:</span>
|
|
1071
|
+
<span class="medos-session-value">${this.state.selectedSessionPack?.remainingSessions} appointments now remaining</span>
|
|
1072
|
+
</div>
|
|
1073
|
+
`
|
|
1074
|
+
: "";
|
|
703
1075
|
return `
|
|
704
1076
|
<div class="medos-section-card">
|
|
705
1077
|
<div class="medos-section-header">
|
|
706
|
-
${VanillaIcons.
|
|
707
|
-
<span class="medos-section-title">
|
|
1078
|
+
${VanillaIcons.consultationType(14)}
|
|
1079
|
+
<span class="medos-section-title">Consultation Type</span>
|
|
708
1080
|
</div>
|
|
709
1081
|
<div class="medos-section-body">
|
|
710
|
-
<
|
|
711
|
-
|
|
712
|
-
<
|
|
1082
|
+
<label class="medos-form-label">Consultation Mode</label>
|
|
1083
|
+
<div class="medos-consultation-options">
|
|
1084
|
+
<label class="medos-radio-option ${this.state.consultationMode === "OFFLINE" ? "selected" : ""}">
|
|
1085
|
+
<input
|
|
1086
|
+
type="radio"
|
|
1087
|
+
name="consultationMode"
|
|
1088
|
+
value="OFFLINE"
|
|
1089
|
+
${this.state.consultationMode === "OFFLINE" ? "checked" : ""}
|
|
1090
|
+
class="medos-radio-input"
|
|
1091
|
+
/>
|
|
1092
|
+
<span class="medos-radio-label">Online</span>
|
|
1093
|
+
</label>
|
|
1094
|
+
<label class="medos-radio-option ${this.state.consultationMode === "ONLINE" ? "selected" : ""}">
|
|
1095
|
+
<input
|
|
1096
|
+
type="radio"
|
|
1097
|
+
name="consultationMode"
|
|
1098
|
+
value="ONLINE"
|
|
1099
|
+
${this.state.consultationMode === "ONLINE" ? "checked" : ""}
|
|
1100
|
+
class="medos-radio-input"
|
|
1101
|
+
/>
|
|
1102
|
+
<span class="medos-radio-label">Offline</span>
|
|
1103
|
+
</label>
|
|
1104
|
+
</div>
|
|
1105
|
+
</div>
|
|
1106
|
+
</div>
|
|
1107
|
+
|
|
1108
|
+
<div class="medos-section-card">
|
|
1109
|
+
<div class="medos-section-header">
|
|
1110
|
+
${VanillaIcons.dateTime(14)}
|
|
1111
|
+
<span class="medos-section-title">Date & Time</span>
|
|
1112
|
+
</div>
|
|
1113
|
+
<div class="medos-section-body medos-datetime-layout">
|
|
1114
|
+
<div class="medos-calendar-section">
|
|
1115
|
+
<label class="medos-form-label">Available Dates</label>
|
|
1116
|
+
<div class="medos-date-display">${dateDisplay}</div>
|
|
1117
|
+
<div id="medos-calendar-container"></div>
|
|
713
1118
|
</div>
|
|
714
|
-
|
|
715
|
-
|
|
1119
|
+
<div class="medos-slots-section">
|
|
1120
|
+
<label class="medos-form-label">Available Slots</label>
|
|
1121
|
+
${this.state.slots.length === 0
|
|
1122
|
+
? '<div class="medos-empty-slots">Select a date to see available slots</div>'
|
|
716
1123
|
: `
|
|
717
|
-
|
|
718
|
-
|
|
1124
|
+
<div class="medos-slots-grid-compact">
|
|
1125
|
+
${this.state.slots
|
|
719
1126
|
.map((s) => {
|
|
720
1127
|
const start = new Date(s.start).toLocaleTimeString([], {
|
|
721
1128
|
hour: "2-digit",
|
|
@@ -728,128 +1135,164 @@ class AppointmentCalendarWidget {
|
|
|
728
1135
|
const selected = this.state.selectedSlot?.start === s.start &&
|
|
729
1136
|
this.state.selectedSlot?.end === s.end;
|
|
730
1137
|
return `
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
${selected
|
|
739
|
-
? `<span class="medos-slot-check">${VanillaIcons.check(14)}</span>`
|
|
740
|
-
: ""}
|
|
741
|
-
</div>
|
|
742
|
-
`;
|
|
1138
|
+
<div class="medos-slot-btn ${selected ? "selected" : ""}"
|
|
1139
|
+
data-slot-id="${this.escapeHtml(s.id || `${s.start}-${s.end}`)}"
|
|
1140
|
+
data-slot-start="${this.escapeHtml(s.start)}"
|
|
1141
|
+
data-slot-end="${this.escapeHtml(s.end)}">
|
|
1142
|
+
${start}
|
|
1143
|
+
</div>
|
|
1144
|
+
`;
|
|
743
1145
|
})
|
|
744
1146
|
.join("")}
|
|
745
|
-
|
|
746
|
-
|
|
1147
|
+
</div>
|
|
1148
|
+
`}
|
|
1149
|
+
</div>
|
|
747
1150
|
</div>
|
|
748
1151
|
</div>
|
|
1152
|
+
|
|
749
1153
|
<div class="medos-actions">
|
|
750
|
-
<button class="medos-btn medos-btn-
|
|
751
|
-
<button class="medos-btn medos-btn-
|
|
1154
|
+
<button class="medos-btn medos-btn-back" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1155
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
1156
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${this.state.selectedSlot ? "" : "disabled"}>Continue</button>
|
|
752
1157
|
</div>
|
|
753
1158
|
`;
|
|
754
1159
|
}
|
|
755
|
-
|
|
756
|
-
const
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1160
|
+
renderPatientSelectionStep() {
|
|
1161
|
+
const patients = this.state.verifiedPatients.length > 0
|
|
1162
|
+
? this.state.verifiedPatients
|
|
1163
|
+
: [
|
|
1164
|
+
{
|
|
1165
|
+
id: 1,
|
|
1166
|
+
firstName: "Mumma",
|
|
1167
|
+
lastName: "Bear",
|
|
1168
|
+
email: "mumma@example.com",
|
|
1169
|
+
countryCode: "+91",
|
|
1170
|
+
phoneNumber: this.state.patientPhone,
|
|
1171
|
+
dob: "1970-01-01",
|
|
1172
|
+
age: 55,
|
|
1173
|
+
gender: "FEMALE",
|
|
1174
|
+
bloodGroup: "O+",
|
|
1175
|
+
mrn: "MRN001",
|
|
1176
|
+
address: {
|
|
1177
|
+
id: 1,
|
|
1178
|
+
completeAddress: "123 Main St",
|
|
1179
|
+
addressLine1: "123 Main St",
|
|
1180
|
+
addressLine2: "",
|
|
1181
|
+
city: "Mumbai",
|
|
1182
|
+
state: "Maharashtra",
|
|
1183
|
+
country: "India",
|
|
1184
|
+
zipcode: "400001",
|
|
1185
|
+
landmark: "",
|
|
1186
|
+
phoneNumber: this.state.patientPhone,
|
|
1187
|
+
latitude: 0,
|
|
1188
|
+
longitude: 0,
|
|
1189
|
+
},
|
|
1190
|
+
},
|
|
1191
|
+
{
|
|
1192
|
+
id: 2,
|
|
1193
|
+
firstName: "Papa",
|
|
1194
|
+
lastName: "Bear",
|
|
1195
|
+
email: "papa@example.com",
|
|
1196
|
+
countryCode: "+91",
|
|
1197
|
+
phoneNumber: this.state.patientPhone,
|
|
1198
|
+
dob: "1968-01-01",
|
|
1199
|
+
age: 57,
|
|
1200
|
+
gender: "MALE",
|
|
1201
|
+
bloodGroup: "B+",
|
|
1202
|
+
mrn: "MRN002",
|
|
1203
|
+
address: {
|
|
1204
|
+
id: 2,
|
|
1205
|
+
completeAddress: "123 Main St",
|
|
1206
|
+
addressLine1: "123 Main St",
|
|
1207
|
+
addressLine2: "",
|
|
1208
|
+
city: "Mumbai",
|
|
1209
|
+
state: "Maharashtra",
|
|
1210
|
+
country: "India",
|
|
1211
|
+
zipcode: "400001",
|
|
1212
|
+
landmark: "",
|
|
1213
|
+
phoneNumber: this.state.patientPhone,
|
|
1214
|
+
latitude: 0,
|
|
1215
|
+
longitude: 0,
|
|
1216
|
+
},
|
|
1217
|
+
},
|
|
1218
|
+
{
|
|
1219
|
+
id: 3,
|
|
1220
|
+
firstName: "Monty",
|
|
1221
|
+
lastName: "Bear",
|
|
1222
|
+
email: "monty@example.com",
|
|
1223
|
+
countryCode: "+91",
|
|
1224
|
+
phoneNumber: this.state.patientPhone,
|
|
1225
|
+
dob: "1990-01-01",
|
|
1226
|
+
age: 35,
|
|
1227
|
+
gender: "MALE",
|
|
1228
|
+
bloodGroup: "A+",
|
|
1229
|
+
mrn: "MRN003",
|
|
1230
|
+
address: {
|
|
1231
|
+
id: 3,
|
|
1232
|
+
completeAddress: "123 Main St",
|
|
1233
|
+
addressLine1: "123 Main St",
|
|
1234
|
+
addressLine2: "",
|
|
1235
|
+
city: "Mumbai",
|
|
1236
|
+
state: "Maharashtra",
|
|
1237
|
+
country: "India",
|
|
1238
|
+
zipcode: "400001",
|
|
1239
|
+
landmark: "",
|
|
1240
|
+
phoneNumber: this.state.patientPhone,
|
|
1241
|
+
latitude: 0,
|
|
1242
|
+
longitude: 0,
|
|
1243
|
+
},
|
|
1244
|
+
},
|
|
1245
|
+
];
|
|
815
1246
|
return `
|
|
816
1247
|
<div class="medos-section-card">
|
|
817
1248
|
<div class="medos-section-header">
|
|
818
|
-
${VanillaIcons.
|
|
819
|
-
<span class="medos-section-title">
|
|
1249
|
+
${VanillaIcons.users(14)}
|
|
1250
|
+
<span class="medos-section-title">Select Patient</span>
|
|
820
1251
|
</div>
|
|
821
1252
|
<div class="medos-section-body">
|
|
822
|
-
<
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1253
|
+
<div class="medos-patient-list">
|
|
1254
|
+
${patients
|
|
1255
|
+
.map((patient) => `
|
|
1256
|
+
<div class="medos-patient-card ${this.state.selectedPatient?.id === patient.id ? "selected" : ""}" data-patient-id="${patient.id}">
|
|
1257
|
+
<div class="medos-patient-radio">
|
|
1258
|
+
<input type="radio" name="patient" value="${patient.id}" ${this.state.selectedPatient?.id === patient.id ? "checked" : ""} />
|
|
1259
|
+
</div>
|
|
1260
|
+
<div class="medos-patient-avatar">
|
|
1261
|
+
${patient.firstName.charAt(0)}${patient.lastName.charAt(0)}
|
|
1262
|
+
</div>
|
|
1263
|
+
<div class="medos-patient-info">
|
|
1264
|
+
<div class="medos-patient-name">${this.escapeHtml(patient.firstName)} ${this.escapeHtml(patient.lastName)}</div>
|
|
1265
|
+
<div class="medos-patient-details">${this.escapeHtml(patient.countryCode)} ${this.escapeHtml(patient.phoneNumber)}</div>
|
|
1266
|
+
</div>
|
|
1267
|
+
<div class="medos-patient-select">select</div>
|
|
1268
|
+
</div>
|
|
1269
|
+
`)
|
|
1270
|
+
.join("")}
|
|
832
1271
|
</div>
|
|
833
|
-
|
|
1272
|
+
|
|
1273
|
+
<button class="medos-add-patient-btn" id="medos-btn-add-patient">
|
|
1274
|
+
${VanillaIcons.plus(16)} New Patient
|
|
1275
|
+
</button>
|
|
834
1276
|
</div>
|
|
835
1277
|
</div>
|
|
836
1278
|
<div class="medos-actions">
|
|
837
|
-
<button class="medos-btn medos-btn-
|
|
838
|
-
<button class="medos-btn medos-btn-
|
|
839
|
-
|
|
840
|
-
: "disabled"}>${this.state.otpVerifying ? "Verifying..." : "Verify OTP"}</button>
|
|
1279
|
+
<button class="medos-btn medos-btn-back" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1280
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
1281
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${this.state.selectedPatient ? "" : "disabled"}>Continue</button>
|
|
841
1282
|
</div>
|
|
842
1283
|
`;
|
|
843
1284
|
}
|
|
844
|
-
|
|
845
|
-
const
|
|
1285
|
+
renderPatientDetailsStep() {
|
|
1286
|
+
const isFormValid = this.state.patientName &&
|
|
1287
|
+
this.state.patientAge &&
|
|
1288
|
+
this.state.patientGender &&
|
|
846
1289
|
this.state.patientAddress &&
|
|
847
1290
|
this.state.patientCity &&
|
|
848
1291
|
this.state.patientState &&
|
|
849
1292
|
this.state.patientCountry &&
|
|
850
|
-
this.state.patientZipcode
|
|
851
|
-
this.state.otpVerified;
|
|
1293
|
+
this.state.patientZipcode;
|
|
852
1294
|
return `
|
|
1295
|
+
<!-- Patient Information Section -->
|
|
853
1296
|
<div class="medos-section-card">
|
|
854
1297
|
<div class="medos-section-header">
|
|
855
1298
|
${VanillaIcons.user(14)}
|
|
@@ -857,92 +1300,384 @@ class AppointmentCalendarWidget {
|
|
|
857
1300
|
</div>
|
|
858
1301
|
<div class="medos-section-body">
|
|
859
1302
|
<div class="medos-form-row">
|
|
860
|
-
<div class="medos-form-
|
|
861
|
-
<label class="medos-label">
|
|
862
|
-
|
|
1303
|
+
<div class="medos-form-field">
|
|
1304
|
+
<label class="medos-form-label">
|
|
1305
|
+
First Name <span style="color: #EF4444;">*</span>
|
|
1306
|
+
</label>
|
|
1307
|
+
<input
|
|
1308
|
+
type="text"
|
|
1309
|
+
class="medos-appointment-input"
|
|
1310
|
+
id="medos-patient-first-name"
|
|
1311
|
+
placeholder="Jane"
|
|
1312
|
+
value="${this.escapeHtml(this.state.patientName.split(" ")[0] || "")}"
|
|
1313
|
+
/>
|
|
1314
|
+
</div>
|
|
1315
|
+
<div class="medos-form-field">
|
|
1316
|
+
<label class="medos-form-label">
|
|
1317
|
+
Last Name <span style="color: #EF4444;">*</span>
|
|
1318
|
+
</label>
|
|
1319
|
+
<input
|
|
1320
|
+
type="text"
|
|
1321
|
+
class="medos-appointment-input"
|
|
1322
|
+
id="medos-patient-last-name"
|
|
1323
|
+
placeholder="Doe"
|
|
1324
|
+
value="${this.escapeHtml(this.state.patientName.split(" ").slice(1).join(" ") || "")}"
|
|
1325
|
+
/>
|
|
1326
|
+
</div>
|
|
1327
|
+
</div>
|
|
1328
|
+
|
|
1329
|
+
<div class="medos-form-row">
|
|
1330
|
+
<div class="medos-form-field">
|
|
1331
|
+
<label class="medos-form-label">
|
|
1332
|
+
Age <span style="color: #EF4444;">*</span>
|
|
1333
|
+
</label>
|
|
1334
|
+
<input
|
|
1335
|
+
type="number"
|
|
1336
|
+
class="medos-appointment-input"
|
|
1337
|
+
id="medos-patient-age"
|
|
1338
|
+
placeholder="25"
|
|
1339
|
+
min="0"
|
|
1340
|
+
max="120"
|
|
1341
|
+
value="${this.escapeHtml(this.state.patientAge)}"
|
|
1342
|
+
/>
|
|
863
1343
|
</div>
|
|
864
|
-
<div class="medos-form-
|
|
865
|
-
<label class="medos-label">
|
|
866
|
-
<input
|
|
1344
|
+
<div class="medos-form-field">
|
|
1345
|
+
<label class="medos-form-label">Email</label>
|
|
1346
|
+
<input
|
|
1347
|
+
type="email"
|
|
1348
|
+
class="medos-appointment-input"
|
|
1349
|
+
id="medos-patient-email"
|
|
1350
|
+
placeholder="jane@example.com (optional)"
|
|
1351
|
+
value="${this.escapeHtml(this.state.patientEmail)}"
|
|
1352
|
+
/>
|
|
867
1353
|
</div>
|
|
868
1354
|
</div>
|
|
1355
|
+
|
|
869
1356
|
<div class="medos-form-row">
|
|
870
|
-
<div class="medos-form-
|
|
871
|
-
<label class="medos-label">
|
|
872
|
-
|
|
1357
|
+
<div class="medos-form-field">
|
|
1358
|
+
<label class="medos-form-label">
|
|
1359
|
+
Gender <span style="color: #EF4444;">*</span>
|
|
1360
|
+
</label>
|
|
1361
|
+
<div id="medos-gender-select-container"></div>
|
|
873
1362
|
</div>
|
|
874
|
-
<div class="medos-form-
|
|
875
|
-
<label class="medos-label">
|
|
876
|
-
<div id="medos-
|
|
1363
|
+
<div class="medos-form-field">
|
|
1364
|
+
<label class="medos-form-label">Blood Group</label>
|
|
1365
|
+
<div id="medos-blood-group-select-container"></div>
|
|
877
1366
|
</div>
|
|
878
1367
|
</div>
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
<div
|
|
1368
|
+
|
|
1369
|
+
<div class="medos-form-row">
|
|
1370
|
+
<div class="medos-form-field">
|
|
1371
|
+
<label class="medos-form-label">Date of Birth</label>
|
|
1372
|
+
<input
|
|
1373
|
+
type="date"
|
|
1374
|
+
class="medos-appointment-input"
|
|
1375
|
+
id="medos-patient-dob"
|
|
1376
|
+
value="${this.escapeHtml(this.state.patientDob)}"
|
|
1377
|
+
/>
|
|
1378
|
+
${this.state.patientDob &&
|
|
1379
|
+
this.state.patientDob.trim() !== "" &&
|
|
1380
|
+
!this.isValidDateOfBirth(this.state.patientDob)
|
|
1381
|
+
? this.getDateOfBirthErrorMessage(this.state.patientDob)
|
|
1382
|
+
: ""}
|
|
1383
|
+
</div>
|
|
882
1384
|
</div>
|
|
883
1385
|
</div>
|
|
884
1386
|
</div>
|
|
885
1387
|
|
|
1388
|
+
<!-- Address Information Section -->
|
|
886
1389
|
<div class="medos-section-card">
|
|
887
1390
|
<div class="medos-section-header">
|
|
888
1391
|
${VanillaIcons.mapPin(14)}
|
|
889
|
-
<span class="medos-section-title">Address
|
|
1392
|
+
<span class="medos-section-title">Address Information</span>
|
|
890
1393
|
</div>
|
|
891
1394
|
<div class="medos-section-body">
|
|
892
|
-
<div class="medos-form-
|
|
893
|
-
<label class="medos-label">
|
|
894
|
-
|
|
1395
|
+
<div class="medos-form-field">
|
|
1396
|
+
<label class="medos-form-label">
|
|
1397
|
+
Address <span style="color: #EF4444;">*</span>
|
|
1398
|
+
</label>
|
|
1399
|
+
<input
|
|
1400
|
+
type="text"
|
|
1401
|
+
class="medos-appointment-input"
|
|
1402
|
+
id="medos-patient-address"
|
|
1403
|
+
placeholder="123 Main Street"
|
|
1404
|
+
value="${this.escapeHtml(this.state.patientAddress)}"
|
|
1405
|
+
/>
|
|
895
1406
|
</div>
|
|
1407
|
+
|
|
896
1408
|
<div class="medos-form-row">
|
|
897
|
-
<div class="medos-form-
|
|
898
|
-
<label class="medos-label">
|
|
899
|
-
|
|
1409
|
+
<div class="medos-form-field">
|
|
1410
|
+
<label class="medos-form-label">
|
|
1411
|
+
City <span style="color: #EF4444;">*</span>
|
|
1412
|
+
</label>
|
|
1413
|
+
<input
|
|
1414
|
+
type="text"
|
|
1415
|
+
class="medos-appointment-input"
|
|
1416
|
+
id="medos-patient-city"
|
|
1417
|
+
placeholder="New York"
|
|
1418
|
+
value="${this.escapeHtml(this.state.patientCity)}"
|
|
1419
|
+
/>
|
|
900
1420
|
</div>
|
|
901
|
-
<div class="medos-form-
|
|
902
|
-
<label class="medos-label">
|
|
903
|
-
|
|
1421
|
+
<div class="medos-form-field">
|
|
1422
|
+
<label class="medos-form-label">
|
|
1423
|
+
State <span style="color: #EF4444;">*</span>
|
|
1424
|
+
</label>
|
|
1425
|
+
<input
|
|
1426
|
+
type="text"
|
|
1427
|
+
class="medos-appointment-input"
|
|
1428
|
+
id="medos-patient-state"
|
|
1429
|
+
placeholder="NY"
|
|
1430
|
+
value="${this.escapeHtml(this.state.patientState)}"
|
|
1431
|
+
/>
|
|
904
1432
|
</div>
|
|
905
1433
|
</div>
|
|
1434
|
+
|
|
906
1435
|
<div class="medos-form-row">
|
|
907
|
-
<div class="medos-form-
|
|
908
|
-
<label class="medos-label">
|
|
909
|
-
|
|
1436
|
+
<div class="medos-form-field">
|
|
1437
|
+
<label class="medos-form-label">
|
|
1438
|
+
Country <span style="color: #EF4444;">*</span>
|
|
1439
|
+
</label>
|
|
1440
|
+
<input
|
|
1441
|
+
type="text"
|
|
1442
|
+
class="medos-appointment-input"
|
|
1443
|
+
id="medos-patient-country"
|
|
1444
|
+
placeholder="United States"
|
|
1445
|
+
value="${this.escapeHtml(this.state.patientCountry)}"
|
|
1446
|
+
/>
|
|
910
1447
|
</div>
|
|
911
|
-
<div class="medos-form-
|
|
912
|
-
<label class="medos-label">
|
|
913
|
-
|
|
1448
|
+
<div class="medos-form-field">
|
|
1449
|
+
<label class="medos-form-label">
|
|
1450
|
+
Zipcode <span style="color: #EF4444;">*</span>
|
|
1451
|
+
</label>
|
|
1452
|
+
<input
|
|
1453
|
+
type="text"
|
|
1454
|
+
class="medos-appointment-input"
|
|
1455
|
+
id="medos-patient-zipcode"
|
|
1456
|
+
placeholder="10001"
|
|
1457
|
+
value="${this.escapeHtml(this.state.patientZipcode)}"
|
|
1458
|
+
/>
|
|
914
1459
|
</div>
|
|
915
1460
|
</div>
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
<
|
|
1461
|
+
|
|
1462
|
+
<div class="medos-form-field" style="margin-top: 20px;">
|
|
1463
|
+
<label class="medos-form-label">Landmark</label>
|
|
1464
|
+
<input
|
|
1465
|
+
type="text"
|
|
1466
|
+
class="medos-appointment-input"
|
|
1467
|
+
id="medos-patient-landmark"
|
|
1468
|
+
placeholder="Near Central Park"
|
|
1469
|
+
value="${this.escapeHtml(this.state.patientLandmark)}"
|
|
1470
|
+
/>
|
|
919
1471
|
</div>
|
|
920
1472
|
</div>
|
|
921
1473
|
</div>
|
|
922
1474
|
|
|
923
1475
|
<div class="medos-actions">
|
|
924
|
-
<button class="medos-btn medos-btn-
|
|
925
|
-
<button class="medos-btn medos-btn-
|
|
1476
|
+
<button class="medos-btn medos-btn-back" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1477
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
1478
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${isFormValid ? "" : "disabled"}>Continue</button>
|
|
1479
|
+
</div>
|
|
1480
|
+
`;
|
|
1481
|
+
}
|
|
1482
|
+
renderAppointmentSummaryStep() {
|
|
1483
|
+
const selectedDoctor = this.doctors.find((d) => d.id === this.state.selectedDoctor);
|
|
1484
|
+
const selectedAddress = this.state.addresses.find((addr) => addr.id === this.state.selectedAddress);
|
|
1485
|
+
const appointmentDate = this.state.selectedDate
|
|
1486
|
+
? this.state.selectedDate.toLocaleDateString("en-US", {
|
|
1487
|
+
weekday: "short",
|
|
1488
|
+
year: "numeric",
|
|
1489
|
+
month: "short",
|
|
1490
|
+
day: "numeric",
|
|
1491
|
+
})
|
|
1492
|
+
: "";
|
|
1493
|
+
const startTime = this.state.selectedSlot?.start
|
|
1494
|
+
? new Date(this.state.selectedSlot.start).toLocaleTimeString([], {
|
|
1495
|
+
hour: "2-digit",
|
|
1496
|
+
minute: "2-digit",
|
|
1497
|
+
})
|
|
1498
|
+
: "";
|
|
1499
|
+
const usingSessionPack = this.state.bookingOptionType === "session-pack" &&
|
|
1500
|
+
this.state.selectedSessionPack;
|
|
1501
|
+
const usingNewPackage = this.state.bookingOptionType === "explore-packages" &&
|
|
1502
|
+
this.state.selectedNewPackage;
|
|
1503
|
+
const consultationCharge = this.state.consultationMode === "ONLINE" ? 500 : 300;
|
|
1504
|
+
let totalAmount = consultationCharge;
|
|
1505
|
+
let sessionInfo = "";
|
|
1506
|
+
let dateOfExpiry = "";
|
|
1507
|
+
if (usingSessionPack) {
|
|
1508
|
+
totalAmount = 0;
|
|
1509
|
+
sessionInfo = `${this.state.selectedSessionPack?.remainingSessions} appointments now remaining`;
|
|
1510
|
+
dateOfExpiry = this.state.selectedSessionPack?.expiryDate || "";
|
|
1511
|
+
}
|
|
1512
|
+
else if (usingNewPackage) {
|
|
1513
|
+
totalAmount = this.state.selectedNewPackage?.price || 0;
|
|
1514
|
+
sessionInfo = `${this.state.selectedNewPackage?.totalSessions} appointments after purchase`;
|
|
1515
|
+
const validityDays = this.state.selectedNewPackage?.validityDays || 365;
|
|
1516
|
+
const expiryDate = new Date();
|
|
1517
|
+
expiryDate.setDate(expiryDate.getDate() + validityDays);
|
|
1518
|
+
dateOfExpiry = expiryDate.toLocaleDateString("en-US", {
|
|
1519
|
+
day: "numeric",
|
|
1520
|
+
month: "long",
|
|
1521
|
+
year: "numeric",
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
const patientName = this.state.selectedPatient
|
|
1525
|
+
? `${this.state.selectedPatient.firstName} ${this.state.selectedPatient.lastName}`
|
|
1526
|
+
: this.state.patientName || "Patient";
|
|
1527
|
+
return `
|
|
1528
|
+
<div class="medos-appointment-summary">
|
|
1529
|
+
<div class="medos-summary-header">
|
|
1530
|
+
<h3>Appointment Summary</h3>
|
|
1531
|
+
<button class="medos-close-btn" id="medos-btn-close">×</button>
|
|
1532
|
+
</div>
|
|
1533
|
+
|
|
1534
|
+
<div class="medos-summary-section">
|
|
1535
|
+
<label class="medos-form-label">REVIEW APPOINTMENT DETAILS</label>
|
|
1536
|
+
|
|
1537
|
+
<div class="medos-summary-grid">
|
|
1538
|
+
<div class="medos-summary-row">
|
|
1539
|
+
<span class="medos-summary-label">Patient:</span>
|
|
1540
|
+
<span class="medos-summary-value">${this.escapeHtml(patientName)}</span>
|
|
1541
|
+
</div>
|
|
1542
|
+
${this.state.patientAge
|
|
1543
|
+
? `<div class="medos-summary-row">
|
|
1544
|
+
<span class="medos-summary-label">Age:</span>
|
|
1545
|
+
<span class="medos-summary-value">${this.escapeHtml(this.state.patientAge)} years</span>
|
|
1546
|
+
</div>`
|
|
1547
|
+
: ""}
|
|
1548
|
+
${this.state.bloodGroup
|
|
1549
|
+
? `<div class="medos-summary-row">
|
|
1550
|
+
<span class="medos-summary-label">Blood Group:</span>
|
|
1551
|
+
<span class="medos-summary-value">${this.escapeHtml(this.state.bloodGroup)}</span>
|
|
1552
|
+
</div>`
|
|
1553
|
+
: ""}
|
|
1554
|
+
<div class="medos-summary-row">
|
|
1555
|
+
<span class="medos-summary-label">Doctor:</span>
|
|
1556
|
+
<span class="medos-summary-value">${selectedDoctor
|
|
1557
|
+
? this.escapeHtml(selectedDoctor.name)
|
|
1558
|
+
: "Not selected"}</span>
|
|
1559
|
+
</div>
|
|
1560
|
+
${selectedAddress
|
|
1561
|
+
? `<div class="medos-summary-row">
|
|
1562
|
+
<span class="medos-summary-label">Location:</span>
|
|
1563
|
+
<span class="medos-summary-value">${this.escapeHtml(selectedAddress.label || "Unknown Location")}</span>
|
|
1564
|
+
</div>`
|
|
1565
|
+
: ""}
|
|
1566
|
+
<div class="medos-summary-row">
|
|
1567
|
+
<span class="medos-summary-label">Date & Time:</span>
|
|
1568
|
+
<span class="medos-summary-value">${appointmentDate}${startTime ? `, ${startTime}` : ""}</span>
|
|
1569
|
+
</div>
|
|
1570
|
+
<div class="medos-summary-row">
|
|
1571
|
+
<span class="medos-summary-label">Appointment Type:</span>
|
|
1572
|
+
<span class="medos-summary-value">${this.state.consultationMode === "ONLINE"
|
|
1573
|
+
? "In Clinic Consultation"
|
|
1574
|
+
: "Online Consultation"}</span>
|
|
1575
|
+
</div>
|
|
1576
|
+
<div class="medos-summary-row">
|
|
1577
|
+
<span class="medos-summary-label">Service:</span>
|
|
1578
|
+
<span class="medos-summary-value">${usingSessionPack
|
|
1579
|
+
? this.escapeHtml(this.state.selectedSessionPack?.name || "Session Pack")
|
|
1580
|
+
: usingNewPackage
|
|
1581
|
+
? this.escapeHtml(this.state.selectedNewPackage?.name || "Package")
|
|
1582
|
+
: "Standard Consultation"}</span>
|
|
1583
|
+
</div>
|
|
1584
|
+
<div class="medos-summary-row">
|
|
1585
|
+
<span class="medos-summary-label">Sessions:</span>
|
|
1586
|
+
<span class="medos-summary-value">${sessionInfo || "1 consultation"}</span>
|
|
1587
|
+
</div>
|
|
1588
|
+
${usingSessionPack || usingNewPackage
|
|
1589
|
+
? `
|
|
1590
|
+
<div class="medos-summary-row">
|
|
1591
|
+
<span class="medos-summary-label">Date of Purchase:</span>
|
|
1592
|
+
<span class="medos-summary-value">${usingSessionPack
|
|
1593
|
+
? this.state.selectedSessionPack?.purchaseDate ||
|
|
1594
|
+
"Previously"
|
|
1595
|
+
: "Today"}</span>
|
|
1596
|
+
</div>
|
|
1597
|
+
<div class="medos-summary-row">
|
|
1598
|
+
<span class="medos-summary-label">Date of Expiry:</span>
|
|
1599
|
+
<span class="medos-summary-value medos-expiry">${dateOfExpiry}</span>
|
|
1600
|
+
</div>
|
|
1601
|
+
`
|
|
1602
|
+
: ""}
|
|
1603
|
+
</div>
|
|
1604
|
+
</div>
|
|
1605
|
+
|
|
1606
|
+
<div class="medos-summary-total">
|
|
1607
|
+
<div class="medos-total-row">
|
|
1608
|
+
<span class="medos-total-label">Total Amount</span>
|
|
1609
|
+
<span class="medos-total-note">${usingSessionPack ? "Using credits from bundle sessions." : ""}</span>
|
|
1610
|
+
</div>
|
|
1611
|
+
<div class="medos-total-amount">₹${totalAmount.toLocaleString()}</div>
|
|
1612
|
+
</div>
|
|
1613
|
+
|
|
1614
|
+
<div class="medos-actions">
|
|
1615
|
+
<button class="medos-btn medos-btn-back" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1616
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
1617
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-confirm">Confirm Book</button>
|
|
1618
|
+
</div>
|
|
926
1619
|
</div>
|
|
927
1620
|
`;
|
|
928
1621
|
}
|
|
929
|
-
|
|
1622
|
+
renderSuccessStep() {
|
|
1623
|
+
const duration = this.calculateDuration();
|
|
1624
|
+
const selectedDoctor = this.doctors.find((d) => d.id === this.state.selectedDoctor);
|
|
1625
|
+
const selectedAddress = this.state.addresses.find((addr) => addr.id === this.state.selectedAddress);
|
|
1626
|
+
const appointmentDate = this.state.selectedDate
|
|
1627
|
+
? this.formatDate(formatDateToISO(this.state.selectedDate))
|
|
1628
|
+
: "";
|
|
1629
|
+
const startTime = this.state.selectedSlot?.start
|
|
1630
|
+
? this.formatTime(new Date(this.state.selectedSlot.start).toTimeString().slice(0, 5))
|
|
1631
|
+
: "";
|
|
1632
|
+
const patientName = this.state.selectedPatient
|
|
1633
|
+
? `${this.state.selectedPatient.firstName} ${this.state.selectedPatient.lastName}`
|
|
1634
|
+
: this.state.patientName || "Patient";
|
|
1635
|
+
const usingSessionPack = this.state.bookingOptionType === "session-pack" &&
|
|
1636
|
+
this.state.selectedSessionPack;
|
|
930
1637
|
return `
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1638
|
+
<div class="medos-success-container">
|
|
1639
|
+
<div class="medos-success-header">
|
|
1640
|
+
<h2>Appointment Confirmed</h2>
|
|
1641
|
+
</div>
|
|
1642
|
+
|
|
1643
|
+
<div class="medos-success-content">
|
|
1644
|
+
<div class="medos-success-badge">
|
|
1645
|
+
${VanillaIcons.successBadge(64)}
|
|
1646
|
+
</div>
|
|
1647
|
+
|
|
1648
|
+
<h3 class="medos-success-title">Appointment Confirmed</h3>
|
|
1649
|
+
|
|
1650
|
+
<div class="medos-success-details">
|
|
1651
|
+
<h4>Appointment Details</h4>
|
|
1652
|
+
<div class="medos-details-text">
|
|
1653
|
+
<p><strong>Patient:</strong> ${this.escapeHtml(patientName)}</p>
|
|
1654
|
+
<p><strong>Type:</strong> ${this.state.consultationMode === "ONLINE"
|
|
1655
|
+
? "In Clinic Consultation"
|
|
1656
|
+
: "Online"}</p>
|
|
1657
|
+
<p><strong>Date:</strong> ${appointmentDate}</p>
|
|
1658
|
+
<p><strong>Time:</strong> ${startTime}</p>
|
|
1659
|
+
<p><strong>Duration:</strong> ~${duration} minutes</p>
|
|
1660
|
+
${selectedAddress?.label
|
|
1661
|
+
? `<p><strong>Location:</strong> ${this.escapeHtml(selectedAddress.label)}</p>`
|
|
1662
|
+
: ""}
|
|
1663
|
+
</div>
|
|
1664
|
+
</div>
|
|
1665
|
+
|
|
1666
|
+
<p class="medos-confirmation-message">
|
|
1667
|
+
A confirmation message has been sent to the registered Phone Number.
|
|
1668
|
+
</p>
|
|
1669
|
+
|
|
1670
|
+
${usingSessionPack
|
|
1671
|
+
? `
|
|
1672
|
+
<div class="medos-session-remaining">
|
|
1673
|
+
<span class="medos-remaining-label">Sessions:</span>
|
|
1674
|
+
<span class="medos-remaining-value">${(this.state.selectedSessionPack?.remainingSessions || 1) - 1} appointments now remaining</span>
|
|
1675
|
+
</div>
|
|
1676
|
+
`
|
|
1677
|
+
: ""}
|
|
1678
|
+
</div>
|
|
1679
|
+
</div>
|
|
1680
|
+
`;
|
|
946
1681
|
}
|
|
947
1682
|
formatDate(dateStr) {
|
|
948
1683
|
try {
|
|
@@ -980,66 +1715,6 @@ class AppointmentCalendarWidget {
|
|
|
980
1715
|
}
|
|
981
1716
|
return 60;
|
|
982
1717
|
}
|
|
983
|
-
renderStep5() {
|
|
984
|
-
const duration = this.calculateDuration();
|
|
985
|
-
const selectedAddress = this.state.addresses.find((addr) => addr.id === this.state.selectedAddress);
|
|
986
|
-
const appointmentDate = this.state.selectedDate
|
|
987
|
-
? this.formatDate(formatDateToISO(this.state.selectedDate))
|
|
988
|
-
: "";
|
|
989
|
-
const startTime = this.state.selectedSlot?.start
|
|
990
|
-
? this.formatTime(new Date(this.state.selectedSlot.start).toTimeString().slice(0, 5))
|
|
991
|
-
: "";
|
|
992
|
-
return `
|
|
993
|
-
<div style="display: flex; flex-direction: column; padding: 0; font-family: Arial, sans-serif; background: #f8f9fa; min-height: 500px;">
|
|
994
|
-
<!-- Header with border -->
|
|
995
|
-
<div style="padding: 20px 24px; font-size: 24px; font-weight: bold; color: #1a365d; border-bottom: 2px solid #e2e8f0; background: white;">
|
|
996
|
-
Appointment Confirmed
|
|
997
|
-
</div>
|
|
998
|
-
|
|
999
|
-
<!-- Main content with border -->
|
|
1000
|
-
<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;">
|
|
1001
|
-
<!-- Success Title -->
|
|
1002
|
-
<h2 style="font-size: 20px; font-weight: 600; color: #006E0F; margin: 0 0 24px 0;">
|
|
1003
|
-
Appointment Confirmed
|
|
1004
|
-
</h2>
|
|
1005
|
-
|
|
1006
|
-
<!-- Success Icon -->
|
|
1007
|
-
<div style="margin-bottom: 32px;">
|
|
1008
|
-
${this.renderSuccessIcon()}
|
|
1009
|
-
</div>
|
|
1010
|
-
|
|
1011
|
-
<!-- Appointment Details -->
|
|
1012
|
-
<div style="width: 100%; max-width: 500px; margin-bottom: 32px;">
|
|
1013
|
-
<h3 style="font-size: 18px; font-weight: 600; color: #006E0F; margin-bottom: 24px;">
|
|
1014
|
-
Appointment Details
|
|
1015
|
-
</h3>
|
|
1016
|
-
|
|
1017
|
-
<div style="display: flex; flex-direction: column; gap: 12px; font-size: 16px; line-height: 1.6; color: #4a5568;">
|
|
1018
|
-
<div><strong style="color: #006E0F;">Patient:</strong> ${this.escapeHtml(this.state.patientName || "Patient")}</div>
|
|
1019
|
-
<div><strong style="color: #006E0F;">Visitation Type:</strong> ${this.state.consultationMode === "ONLINE"
|
|
1020
|
-
? "Online Consultation"
|
|
1021
|
-
: "General"}</div>
|
|
1022
|
-
${appointmentDate
|
|
1023
|
-
? `<div><strong style="color: #006E0F;">Date:</strong> ${appointmentDate}</div>`
|
|
1024
|
-
: ""}
|
|
1025
|
-
${startTime
|
|
1026
|
-
? `<div><strong style="color: #006E0F;">Time:</strong> ${startTime}</div>`
|
|
1027
|
-
: ""}
|
|
1028
|
-
<div><strong style="color: #006E0F;">Duration:</strong> ~${duration} minutes</div>
|
|
1029
|
-
${selectedAddress?.label
|
|
1030
|
-
? `<div><strong style="color: #006E0F;">Location:</strong> ${this.escapeHtml(selectedAddress.label)}</div>`
|
|
1031
|
-
: ""}
|
|
1032
|
-
</div>
|
|
1033
|
-
</div>
|
|
1034
|
-
|
|
1035
|
-
<!-- Confirmation Message -->
|
|
1036
|
-
<div style="font-size: 16px; font-style: italic; color: #718096; text-align: center; max-width: 600px; line-height: 1.5;">
|
|
1037
|
-
A confirmation email has been sent to the Patient's Email address.
|
|
1038
|
-
</div>
|
|
1039
|
-
</div>
|
|
1040
|
-
</div>
|
|
1041
|
-
`;
|
|
1042
|
-
}
|
|
1043
1718
|
attachEventListeners() {
|
|
1044
1719
|
const consultationRadios = this.container.querySelectorAll('input[name="consultationMode"]');
|
|
1045
1720
|
consultationRadios.forEach((radio) => {
|
|
@@ -1049,7 +1724,7 @@ class AppointmentCalendarWidget {
|
|
|
1049
1724
|
this.render();
|
|
1050
1725
|
});
|
|
1051
1726
|
});
|
|
1052
|
-
const slotCards = this.container.querySelectorAll(".medos-slot-card");
|
|
1727
|
+
const slotCards = this.container.querySelectorAll(".medos-slot-card, .medos-slot-btn");
|
|
1053
1728
|
slotCards.forEach((card) => {
|
|
1054
1729
|
card.addEventListener("click", () => {
|
|
1055
1730
|
const slotId = card.dataset.slotId;
|
|
@@ -1121,6 +1796,7 @@ class AppointmentCalendarWidget {
|
|
|
1121
1796
|
const target = e.target;
|
|
1122
1797
|
this.state.patientAge = target.value;
|
|
1123
1798
|
this.updateSubmitButtonState();
|
|
1799
|
+
this.updatePatientDetailsButtonState();
|
|
1124
1800
|
});
|
|
1125
1801
|
}
|
|
1126
1802
|
const patientEmailInput = this.container.querySelector("#medos-patient-email");
|
|
@@ -1131,19 +1807,13 @@ class AppointmentCalendarWidget {
|
|
|
1131
1807
|
this.updateSubmitButtonState();
|
|
1132
1808
|
});
|
|
1133
1809
|
}
|
|
1134
|
-
const patientGenderSelect = this.container.querySelector("#medos-patient-gender");
|
|
1135
|
-
if (patientGenderSelect) {
|
|
1136
|
-
patientGenderSelect.addEventListener("change", (e) => {
|
|
1137
|
-
const target = e.target;
|
|
1138
|
-
this.state.patientGender = target.value;
|
|
1139
|
-
});
|
|
1140
|
-
}
|
|
1141
1810
|
const patientAddressInput = this.container.querySelector("#medos-patient-address");
|
|
1142
1811
|
if (patientAddressInput) {
|
|
1143
1812
|
patientAddressInput.addEventListener("input", (e) => {
|
|
1144
1813
|
const target = e.target;
|
|
1145
1814
|
this.state.patientAddress = target.value;
|
|
1146
1815
|
this.updateSubmitButtonState();
|
|
1816
|
+
this.updatePatientDetailsButtonState();
|
|
1147
1817
|
});
|
|
1148
1818
|
}
|
|
1149
1819
|
const patientCityInput = this.container.querySelector("#medos-patient-city");
|
|
@@ -1152,6 +1822,7 @@ class AppointmentCalendarWidget {
|
|
|
1152
1822
|
const target = e.target;
|
|
1153
1823
|
this.state.patientCity = target.value;
|
|
1154
1824
|
this.updateSubmitButtonState();
|
|
1825
|
+
this.updatePatientDetailsButtonState();
|
|
1155
1826
|
});
|
|
1156
1827
|
}
|
|
1157
1828
|
const patientStateInput = this.container.querySelector("#medos-patient-state");
|
|
@@ -1160,6 +1831,7 @@ class AppointmentCalendarWidget {
|
|
|
1160
1831
|
const target = e.target;
|
|
1161
1832
|
this.state.patientState = target.value;
|
|
1162
1833
|
this.updateSubmitButtonState();
|
|
1834
|
+
this.updatePatientDetailsButtonState();
|
|
1163
1835
|
});
|
|
1164
1836
|
}
|
|
1165
1837
|
const patientCountryInput = this.container.querySelector("#medos-patient-country");
|
|
@@ -1168,6 +1840,7 @@ class AppointmentCalendarWidget {
|
|
|
1168
1840
|
const target = e.target;
|
|
1169
1841
|
this.state.patientCountry = target.value;
|
|
1170
1842
|
this.updateSubmitButtonState();
|
|
1843
|
+
this.updatePatientDetailsButtonState();
|
|
1171
1844
|
});
|
|
1172
1845
|
}
|
|
1173
1846
|
const patientZipcodeInput = this.container.querySelector("#medos-patient-zipcode");
|
|
@@ -1176,6 +1849,7 @@ class AppointmentCalendarWidget {
|
|
|
1176
1849
|
const target = e.target;
|
|
1177
1850
|
this.state.patientZipcode = target.value;
|
|
1178
1851
|
this.updateSubmitButtonState();
|
|
1852
|
+
this.updatePatientDetailsButtonState();
|
|
1179
1853
|
});
|
|
1180
1854
|
}
|
|
1181
1855
|
const patientLandmarkInput = this.container.querySelector("#medos-patient-landmark");
|
|
@@ -1185,6 +1859,151 @@ class AppointmentCalendarWidget {
|
|
|
1185
1859
|
this.state.patientLandmark = target.value;
|
|
1186
1860
|
});
|
|
1187
1861
|
}
|
|
1862
|
+
const patientFirstNameInput = this.container.querySelector("#medos-patient-first-name");
|
|
1863
|
+
if (patientFirstNameInput) {
|
|
1864
|
+
patientFirstNameInput.addEventListener("input", (e) => {
|
|
1865
|
+
const target = e.target;
|
|
1866
|
+
const lastName = this.state.patientName.split(" ").slice(1).join(" ") || "";
|
|
1867
|
+
this.state.patientName = `${target.value} ${lastName}`.trim();
|
|
1868
|
+
this.updatePatientDetailsButtonState();
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
const patientLastNameInput = this.container.querySelector("#medos-patient-last-name");
|
|
1872
|
+
if (patientLastNameInput) {
|
|
1873
|
+
patientLastNameInput.addEventListener("input", (e) => {
|
|
1874
|
+
const target = e.target;
|
|
1875
|
+
const firstName = this.state.patientName.split(" ")[0] || "";
|
|
1876
|
+
this.state.patientName = `${firstName} ${target.value}`.trim();
|
|
1877
|
+
this.updatePatientDetailsButtonState();
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
const patientDobInput = this.container.querySelector("#medos-patient-dob");
|
|
1881
|
+
if (patientDobInput) {
|
|
1882
|
+
patientDobInput.addEventListener("input", (e) => {
|
|
1883
|
+
const target = e.target;
|
|
1884
|
+
const dobValue = target.value;
|
|
1885
|
+
this.setState({ patientDob: dobValue });
|
|
1886
|
+
this.setState({ error: null });
|
|
1887
|
+
if (dobValue && dobValue.trim() !== "") {
|
|
1888
|
+
try {
|
|
1889
|
+
if (!this.isValidDateOfBirth(dobValue)) {
|
|
1890
|
+
target.classList.add("medos-input-error");
|
|
1891
|
+
const today = new Date();
|
|
1892
|
+
const inputDate = new Date(dobValue);
|
|
1893
|
+
if (inputDate > today) {
|
|
1894
|
+
target.title = "Date of birth cannot be in the future";
|
|
1895
|
+
}
|
|
1896
|
+
else if (!/^\d{4}-\d{2}-\d{2}$/.test(dobValue)) {
|
|
1897
|
+
target.title = "Please use YYYY-MM-DD format";
|
|
1898
|
+
}
|
|
1899
|
+
else {
|
|
1900
|
+
target.title = "Please enter a valid date";
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
else {
|
|
1904
|
+
target.classList.remove("medos-input-error");
|
|
1905
|
+
target.title = "";
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
catch (error) {
|
|
1909
|
+
console.warn("Date validation error:", error);
|
|
1910
|
+
target.classList.add("medos-input-error");
|
|
1911
|
+
target.title = "Date validation failed";
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
else {
|
|
1915
|
+
target.classList.remove("medos-input-error");
|
|
1916
|
+
target.title = "";
|
|
1917
|
+
}
|
|
1918
|
+
this.updatePatientDetailsButtonState();
|
|
1919
|
+
this.updateSubmitButtonState();
|
|
1920
|
+
});
|
|
1921
|
+
patientDobInput.addEventListener("blur", (e) => {
|
|
1922
|
+
const target = e.target;
|
|
1923
|
+
const dobValue = target.value;
|
|
1924
|
+
if (dobValue && dobValue.trim() !== "") {
|
|
1925
|
+
try {
|
|
1926
|
+
if (!this.isValidDateOfBirth(dobValue)) {
|
|
1927
|
+
target.classList.add("medos-input-error");
|
|
1928
|
+
const today = new Date();
|
|
1929
|
+
const inputDate = new Date(dobValue);
|
|
1930
|
+
if (inputDate > today) {
|
|
1931
|
+
this.displayFieldValidationError("dateOfBirth", "future");
|
|
1932
|
+
}
|
|
1933
|
+
else if (!/^\d{4}-\d{2}-\d{2}$/.test(dobValue)) {
|
|
1934
|
+
this.displayFieldValidationError("dateOfBirth", "format");
|
|
1935
|
+
}
|
|
1936
|
+
else {
|
|
1937
|
+
this.displayFieldValidationError("dateOfBirth", "invalid");
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
catch (error) {
|
|
1942
|
+
console.warn("Date validation error on blur:", error);
|
|
1943
|
+
this.displayFieldValidationError("dateOfBirth", "invalid");
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
const optionCards = this.container.querySelectorAll(".medos-option-card");
|
|
1949
|
+
optionCards.forEach((card) => {
|
|
1950
|
+
card.addEventListener("click", () => {
|
|
1951
|
+
const option = card.dataset.option;
|
|
1952
|
+
if (option === "new-appointment" ||
|
|
1953
|
+
option === "session-pack" ||
|
|
1954
|
+
option === "explore-packages") {
|
|
1955
|
+
this.state.bookingOptionType = option;
|
|
1956
|
+
this.render();
|
|
1957
|
+
}
|
|
1958
|
+
});
|
|
1959
|
+
});
|
|
1960
|
+
const packCards = this.container.querySelectorAll(".medos-session-pack-card");
|
|
1961
|
+
packCards.forEach((card) => {
|
|
1962
|
+
card.addEventListener("click", () => {
|
|
1963
|
+
const packId = Number.parseInt(card.dataset.packId || "0", 10);
|
|
1964
|
+
const pack = this.state.userSessionPacks.find((p) => p.id === packId);
|
|
1965
|
+
if (pack) {
|
|
1966
|
+
this.state.selectedSessionPack = pack;
|
|
1967
|
+
this.state.bookingOptionType = "session-pack";
|
|
1968
|
+
this.render();
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1971
|
+
});
|
|
1972
|
+
const packageCards = this.container.querySelectorAll(".medos-package-card");
|
|
1973
|
+
packageCards.forEach((card) => {
|
|
1974
|
+
card.addEventListener("click", () => {
|
|
1975
|
+
const packageId = parseInt(card.dataset.packageId || "0", 10);
|
|
1976
|
+
const pkg = this.state.availablePackages.length > 0
|
|
1977
|
+
? this.state.availablePackages.find((p) => p.id === packageId)
|
|
1978
|
+
: {
|
|
1979
|
+
id: packageId,
|
|
1980
|
+
name: packageId === 1 ? "Silver Package" : "Gold Package",
|
|
1981
|
+
totalSessions: packageId === 1 ? 3 : 5,
|
|
1982
|
+
price: packageId === 1 ? 5000 : 8000,
|
|
1983
|
+
validityDays: packageId === 1 ? 180 : 365,
|
|
1984
|
+
applicableOnline: true,
|
|
1985
|
+
applicableOffline: true,
|
|
1986
|
+
};
|
|
1987
|
+
if (pkg) {
|
|
1988
|
+
this.state.selectedNewPackage = pkg;
|
|
1989
|
+
this.render();
|
|
1990
|
+
}
|
|
1991
|
+
});
|
|
1992
|
+
});
|
|
1993
|
+
const patientCards = this.container.querySelectorAll(".medos-patient-card");
|
|
1994
|
+
patientCards.forEach((card) => {
|
|
1995
|
+
card.addEventListener("click", () => {
|
|
1996
|
+
const patientId = parseInt(card.dataset.patientId || "0", 10);
|
|
1997
|
+
const patients = this.state.verifiedPatients.length > 0
|
|
1998
|
+
? this.state.verifiedPatients
|
|
1999
|
+
: this.getPlaceholderPatients();
|
|
2000
|
+
const patient = patients.find((p) => p.id === patientId);
|
|
2001
|
+
if (patient) {
|
|
2002
|
+
this.state.selectedPatient = patient;
|
|
2003
|
+
this.render();
|
|
2004
|
+
}
|
|
2005
|
+
});
|
|
2006
|
+
});
|
|
1188
2007
|
const nextBtn = this.container.querySelector("#medos-btn-next");
|
|
1189
2008
|
if (nextBtn) {
|
|
1190
2009
|
nextBtn.addEventListener("click", () => {
|
|
@@ -1193,10 +2012,22 @@ class AppointmentCalendarWidget {
|
|
|
1193
2012
|
}
|
|
1194
2013
|
});
|
|
1195
2014
|
}
|
|
2015
|
+
const continueBtn = this.container.querySelector("#medos-btn-continue");
|
|
2016
|
+
if (continueBtn) {
|
|
2017
|
+
continueBtn.addEventListener("click", () => {
|
|
2018
|
+
if (!continueBtn.disabled) {
|
|
2019
|
+
this.goToNext();
|
|
2020
|
+
}
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
1196
2023
|
const backBtn = this.container.querySelector("#medos-btn-back");
|
|
1197
2024
|
if (backBtn) {
|
|
1198
2025
|
backBtn.addEventListener("click", () => this.goBack());
|
|
1199
2026
|
}
|
|
2027
|
+
const cancelBtn = this.container.querySelector("#medos-btn-cancel");
|
|
2028
|
+
if (cancelBtn) {
|
|
2029
|
+
cancelBtn.addEventListener("click", () => this.reset());
|
|
2030
|
+
}
|
|
1200
2031
|
const sendOtpBtn = this.container.querySelector("#medos-btn-send-otp");
|
|
1201
2032
|
if (sendOtpBtn) {
|
|
1202
2033
|
sendOtpBtn.addEventListener("click", () => {
|
|
@@ -1226,6 +2057,14 @@ class AppointmentCalendarWidget {
|
|
|
1226
2057
|
this.sendOtp();
|
|
1227
2058
|
});
|
|
1228
2059
|
}
|
|
2060
|
+
const confirmBtn = this.container.querySelector("#medos-btn-confirm");
|
|
2061
|
+
if (confirmBtn) {
|
|
2062
|
+
confirmBtn.addEventListener("click", () => {
|
|
2063
|
+
if (!confirmBtn.disabled) {
|
|
2064
|
+
this.submitAppointment();
|
|
2065
|
+
}
|
|
2066
|
+
});
|
|
2067
|
+
}
|
|
1229
2068
|
const submitBtn = this.container.querySelector("#medos-btn-submit");
|
|
1230
2069
|
if (submitBtn) {
|
|
1231
2070
|
submitBtn.addEventListener("click", () => {
|
|
@@ -1238,12 +2077,194 @@ class AppointmentCalendarWidget {
|
|
|
1238
2077
|
if (bookAnotherBtn) {
|
|
1239
2078
|
bookAnotherBtn.addEventListener("click", () => this.reset());
|
|
1240
2079
|
}
|
|
2080
|
+
const addPatientBtn = this.container.querySelector("#medos-btn-add-patient");
|
|
2081
|
+
if (addPatientBtn) {
|
|
2082
|
+
addPatientBtn.addEventListener("click", () => {
|
|
2083
|
+
this.state.selectedPatient = null;
|
|
2084
|
+
this.state.useExistingPatient = false;
|
|
2085
|
+
this.goToNext();
|
|
2086
|
+
});
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
getPlaceholderPatients() {
|
|
2090
|
+
return [
|
|
2091
|
+
{
|
|
2092
|
+
id: 1,
|
|
2093
|
+
firstName: "Mumma",
|
|
2094
|
+
lastName: "Bear",
|
|
2095
|
+
email: "mumma@example.com",
|
|
2096
|
+
countryCode: "+91",
|
|
2097
|
+
phoneNumber: this.state.patientPhone,
|
|
2098
|
+
dob: "1970-01-01",
|
|
2099
|
+
age: 55,
|
|
2100
|
+
gender: "FEMALE",
|
|
2101
|
+
bloodGroup: "O+",
|
|
2102
|
+
mrn: "MRN001",
|
|
2103
|
+
address: {
|
|
2104
|
+
id: 1,
|
|
2105
|
+
completeAddress: "123 Main St",
|
|
2106
|
+
addressLine1: "123 Main St",
|
|
2107
|
+
addressLine2: "",
|
|
2108
|
+
city: "Mumbai",
|
|
2109
|
+
state: "Maharashtra",
|
|
2110
|
+
country: "India",
|
|
2111
|
+
zipcode: "400001",
|
|
2112
|
+
landmark: "",
|
|
2113
|
+
phoneNumber: this.state.patientPhone,
|
|
2114
|
+
latitude: 0,
|
|
2115
|
+
longitude: 0,
|
|
2116
|
+
},
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
2119
|
+
id: 2,
|
|
2120
|
+
firstName: "Papa",
|
|
2121
|
+
lastName: "Bear",
|
|
2122
|
+
email: "papa@example.com",
|
|
2123
|
+
countryCode: "+91",
|
|
2124
|
+
phoneNumber: this.state.patientPhone,
|
|
2125
|
+
dob: "1968-01-01",
|
|
2126
|
+
age: 57,
|
|
2127
|
+
gender: "MALE",
|
|
2128
|
+
bloodGroup: "B+",
|
|
2129
|
+
mrn: "MRN002",
|
|
2130
|
+
address: {
|
|
2131
|
+
id: 2,
|
|
2132
|
+
completeAddress: "123 Main St",
|
|
2133
|
+
addressLine1: "123 Main St",
|
|
2134
|
+
addressLine2: "",
|
|
2135
|
+
city: "Mumbai",
|
|
2136
|
+
state: "Maharashtra",
|
|
2137
|
+
country: "India",
|
|
2138
|
+
zipcode: "400001",
|
|
2139
|
+
landmark: "",
|
|
2140
|
+
phoneNumber: this.state.patientPhone,
|
|
2141
|
+
latitude: 0,
|
|
2142
|
+
longitude: 0,
|
|
2143
|
+
},
|
|
2144
|
+
},
|
|
2145
|
+
];
|
|
1241
2146
|
}
|
|
1242
2147
|
escapeHtml(text) {
|
|
1243
2148
|
const div = document.createElement("div");
|
|
1244
2149
|
div.textContent = text;
|
|
1245
2150
|
return div.innerHTML;
|
|
1246
2151
|
}
|
|
2152
|
+
isValidDateOfBirth(dob) {
|
|
2153
|
+
try {
|
|
2154
|
+
return validateDateOfBirth(dob);
|
|
2155
|
+
}
|
|
2156
|
+
catch (error) {
|
|
2157
|
+
console.warn("Date of birth validation error:", error);
|
|
2158
|
+
return false;
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
isValidBloodGroup(bloodGroup) {
|
|
2162
|
+
try {
|
|
2163
|
+
return validateBloodGroup(bloodGroup);
|
|
2164
|
+
}
|
|
2165
|
+
catch (error) {
|
|
2166
|
+
console.warn("Blood group validation error:", error);
|
|
2167
|
+
return false;
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
safeMapBloodGroupToApi(bloodGroup) {
|
|
2171
|
+
try {
|
|
2172
|
+
if (!bloodGroup) {
|
|
2173
|
+
return "UNKNOWN";
|
|
2174
|
+
}
|
|
2175
|
+
if (!this.isValidBloodGroup(bloodGroup)) {
|
|
2176
|
+
console.warn(`Invalid blood group provided: ${bloodGroup}, using UNKNOWN`);
|
|
2177
|
+
return "UNKNOWN";
|
|
2178
|
+
}
|
|
2179
|
+
const mapped = mapBloodGroupToApi(bloodGroup);
|
|
2180
|
+
if (!mapped || mapped === "") {
|
|
2181
|
+
console.warn(`Blood group mapping failed for: ${bloodGroup}, using UNKNOWN`);
|
|
2182
|
+
return "UNKNOWN";
|
|
2183
|
+
}
|
|
2184
|
+
return mapped;
|
|
2185
|
+
}
|
|
2186
|
+
catch (error) {
|
|
2187
|
+
console.error("Blood group mapping error:", error);
|
|
2188
|
+
return "UNKNOWN";
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
safeFormatDateOfBirth(dob) {
|
|
2192
|
+
try {
|
|
2193
|
+
if (!dob) {
|
|
2194
|
+
return undefined;
|
|
2195
|
+
}
|
|
2196
|
+
if (!this.isValidDateOfBirth(dob)) {
|
|
2197
|
+
console.warn(`Invalid date of birth provided: ${dob}, excluding from payload`);
|
|
2198
|
+
return undefined;
|
|
2199
|
+
}
|
|
2200
|
+
return dob;
|
|
2201
|
+
}
|
|
2202
|
+
catch (error) {
|
|
2203
|
+
console.error("Date of birth formatting error:", error);
|
|
2204
|
+
return undefined;
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
getDateOfBirthErrorMessage(dobValue) {
|
|
2208
|
+
try {
|
|
2209
|
+
const today = new Date();
|
|
2210
|
+
const inputDate = new Date(dobValue);
|
|
2211
|
+
if (inputDate > today) {
|
|
2212
|
+
return '<div class="medos-validation-error">Date of birth cannot be in the future</div>';
|
|
2213
|
+
}
|
|
2214
|
+
else if (!/^\d{4}-\d{2}-\d{2}$/.test(dobValue)) {
|
|
2215
|
+
return '<div class="medos-validation-error">Please use YYYY-MM-DD format</div>';
|
|
2216
|
+
}
|
|
2217
|
+
else {
|
|
2218
|
+
return '<div class="medos-validation-error">Please enter a valid date of birth</div>';
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
catch (error) {
|
|
2222
|
+
console.warn("Error generating date of birth error message:", error);
|
|
2223
|
+
return '<div class="medos-validation-error">Please enter a valid date of birth</div>';
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
displayFieldValidationError(fieldName, errorType) {
|
|
2227
|
+
let errorMessage = "";
|
|
2228
|
+
switch (fieldName) {
|
|
2229
|
+
case "bloodGroup":
|
|
2230
|
+
switch (errorType) {
|
|
2231
|
+
case "invalid":
|
|
2232
|
+
errorMessage =
|
|
2233
|
+
"Please select a valid blood group from the dropdown or leave it empty.";
|
|
2234
|
+
break;
|
|
2235
|
+
case "mapping":
|
|
2236
|
+
errorMessage =
|
|
2237
|
+
"Blood group selection failed. Please try selecting again or leave it empty.";
|
|
2238
|
+
break;
|
|
2239
|
+
default:
|
|
2240
|
+
errorMessage =
|
|
2241
|
+
"Blood group validation failed. Please check your selection.";
|
|
2242
|
+
}
|
|
2243
|
+
break;
|
|
2244
|
+
case "dateOfBirth":
|
|
2245
|
+
switch (errorType) {
|
|
2246
|
+
case "invalid":
|
|
2247
|
+
errorMessage =
|
|
2248
|
+
"Please enter a valid date of birth in YYYY-MM-DD format or leave it empty.";
|
|
2249
|
+
break;
|
|
2250
|
+
case "future":
|
|
2251
|
+
errorMessage =
|
|
2252
|
+
"Date of birth cannot be in the future. Please enter a valid past date.";
|
|
2253
|
+
break;
|
|
2254
|
+
case "format":
|
|
2255
|
+
errorMessage =
|
|
2256
|
+
"Please enter date of birth in the correct format (YYYY-MM-DD).";
|
|
2257
|
+
break;
|
|
2258
|
+
default:
|
|
2259
|
+
errorMessage =
|
|
2260
|
+
"Date of birth validation failed. Please check the date format.";
|
|
2261
|
+
}
|
|
2262
|
+
break;
|
|
2263
|
+
default:
|
|
2264
|
+
errorMessage = `Validation failed for ${fieldName}. Please check your input.`;
|
|
2265
|
+
}
|
|
2266
|
+
this.setState({ error: errorMessage });
|
|
2267
|
+
}
|
|
1247
2268
|
destroy() {
|
|
1248
2269
|
this.mounted = false;
|
|
1249
2270
|
this.container.innerHTML = "";
|