medos-sdk 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/client/MedosClient.d.ts +3 -5
- package/dist/client/MedosClient.js +4 -4
- package/dist/components/AppointmentCalender.d.ts +1 -4
- package/dist/components/AppointmentCalender.js +323 -530
- package/dist/components/AppointmentDateTimeModal.d.ts +14 -0
- package/dist/components/AppointmentDateTimeModal.js +220 -0
- package/dist/components/ConfigurableCard.d.ts +12 -0
- package/dist/components/ConfigurableCard.js +29 -0
- package/dist/components/ContactInformationStep.d.ts +13 -0
- package/dist/components/ContactInformationStep.js +14 -0
- package/dist/components/ContactPreferenceStep.d.ts +9 -0
- package/dist/components/ContactPreferenceStep.js +16 -0
- package/dist/components/DoctorSelectModal.d.ts +7 -0
- package/dist/components/DoctorSelectModal.js +93 -0
- package/dist/components/EnquiryForm.d.ts +7 -0
- package/dist/components/EnquiryForm.js +212 -0
- package/dist/components/Icons/Check.d.ts +6 -0
- package/dist/components/Icons/Check.js +2 -0
- package/dist/components/Icons/ChevronDownIcon.d.ts +4 -0
- package/dist/components/Icons/ChevronDownIcon.js +2 -0
- package/dist/components/Icons/ChevronLeft.d.ts +3 -0
- package/dist/components/Icons/ChevronLeft.js +3 -0
- package/dist/components/Icons/ChevronRight.d.ts +3 -0
- package/dist/components/Icons/ChevronRight.js +3 -0
- package/dist/components/Icons/ConfirmationCheck.d.ts +1 -0
- package/dist/components/Icons/ConfirmationCheck.js +9 -0
- package/dist/components/Icons/ConsultationType.d.ts +1 -0
- package/dist/components/Icons/ConsultationType.js +2 -0
- package/dist/components/Icons/Date&TimeIcon.d.ts +1 -0
- package/dist/components/Icons/Date&TimeIcon.js +2 -0
- package/dist/components/Icons/MapIcon.d.ts +1 -0
- package/dist/components/Icons/MapIcon.js +2 -0
- package/dist/components/Icons/PaymentMethodIcon.d.ts +1 -0
- package/dist/components/Icons/PaymentMethodIcon.js +2 -0
- package/dist/components/Icons/UserIcon.d.ts +1 -0
- package/dist/components/Icons/UserIcon.js +2 -0
- package/dist/components/InquiryDetailsStep.d.ts +10 -0
- package/dist/components/InquiryDetailsStep.js +15 -0
- package/dist/components/PatientDetailsStep.d.ts +3 -0
- package/dist/components/PatientDetailsStep.js +84 -0
- package/dist/components/PhoneVerificationStep.d.ts +3 -0
- package/dist/components/PhoneVerificationStep.js +49 -0
- package/dist/components/SuccessStep.d.ts +5 -0
- package/dist/components/SuccessStep.js +9 -0
- package/dist/components/custom-calendar.d.ts +5 -0
- package/dist/components/custom-calendar.js +171 -0
- package/dist/components/styles.d.ts +6 -0
- package/dist/components/styles.js +257 -0
- package/dist/components/theme-styles.d.ts +12 -0
- package/dist/components/theme-styles.js +319 -0
- package/dist/components/types.d.ts +181 -0
- package/dist/components/types.js +55 -0
- package/dist/components/ui/select.d.ts +10 -0
- package/dist/components/ui/select.js +21 -0
- package/dist/components/uiComponents/SelectDropdown.d.ts +41 -0
- package/dist/components/uiComponents/SelectDropdown.js +302 -0
- package/dist/components/utils.d.ts +5 -0
- package/dist/components/utils.js +15 -0
- package/dist/components/validation.d.ts +2 -0
- package/dist/components/validation.js +7 -0
- package/dist/context/TemplateContext.d.ts +12 -0
- package/dist/context/TemplateContext.js +19 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +4 -0
- package/dist/core/theme/index.d.ts +3 -0
- package/dist/core/theme/index.js +3 -0
- package/dist/core/theme/themes.d.ts +8 -0
- package/dist/core/theme/themes.js +178 -0
- package/dist/core/theme/types.d.ts +106 -0
- package/dist/core/theme/types.js +1 -0
- package/dist/core/theme/utils.d.ts +8 -0
- package/dist/core/theme/utils.js +135 -0
- package/dist/enquiry-form/index.d.ts +4 -0
- package/dist/enquiry-form/index.js +4 -0
- package/dist/enquiry-form/provider.d.ts +3 -0
- package/dist/enquiry-form/provider.js +9 -0
- package/dist/enquiry-form/serialization.d.ts +4 -0
- package/dist/enquiry-form/serialization.js +57 -0
- package/dist/enquiry-form/types.d.ts +38 -0
- package/dist/enquiry-form/types.js +1 -0
- package/dist/enquiry-form/validation.d.ts +6 -0
- package/dist/enquiry-form/validation.js +21 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/lib/templateUtils.d.ts +3 -0
- package/dist/lib/templateUtils.js +28 -0
- package/dist/react/ThemeProvider.d.ts +18 -0
- package/dist/react/ThemeProvider.js +45 -0
- package/dist/react/hooks/useTheme.d.ts +1 -0
- package/dist/react/hooks/useTheme.js +1 -0
- package/dist/react/index.d.ts +5 -0
- package/dist/react/index.js +3 -0
- package/dist/services/AppointmentService.d.ts +4 -5
- package/dist/services/AppointmentService.js +12 -10
- package/dist/services/EnquiryService.d.ts +5 -0
- package/dist/services/EnquiryService.js +30 -0
- package/dist/templates/registry.d.ts +12 -0
- package/dist/templates/registry.js +58 -0
- package/dist/vanilla/AppointmentCalendarWidget.d.ts +2 -34
- package/dist/vanilla/AppointmentCalendarWidget.js +264 -275
- package/dist/vanilla/EnquiryFormWidget.d.ts +35 -0
- package/dist/vanilla/EnquiryFormWidget.js +425 -0
- package/dist/vanilla/client/MedosClient.d.ts +3 -5
- package/dist/vanilla/components/AppointmentCalender.d.ts +1 -4
- package/dist/vanilla/components/AppointmentDateTimeModal.d.ts +14 -0
- package/dist/vanilla/components/ConfigurableCard.d.ts +12 -0
- package/dist/vanilla/components/ContactInformationStep.d.ts +13 -0
- package/dist/vanilla/components/ContactPreferenceStep.d.ts +9 -0
- package/dist/vanilla/components/DoctorSelectModal.d.ts +7 -0
- package/dist/vanilla/components/EnquiryForm.d.ts +7 -0
- package/dist/vanilla/components/Icons/Check.d.ts +6 -0
- package/dist/vanilla/components/Icons/ChevronDownIcon.d.ts +4 -0
- package/dist/vanilla/components/Icons/ChevronLeft.d.ts +3 -0
- package/dist/vanilla/components/Icons/ChevronRight.d.ts +3 -0
- package/dist/vanilla/components/Icons/ConfirmationCheck.d.ts +1 -0
- package/dist/vanilla/components/Icons/ConsultationType.d.ts +1 -0
- package/dist/vanilla/components/Icons/Date&TimeIcon.d.ts +1 -0
- package/dist/vanilla/components/Icons/MapIcon.d.ts +1 -0
- package/dist/vanilla/components/Icons/PaymentMethodIcon.d.ts +1 -0
- package/dist/vanilla/components/Icons/UserIcon.d.ts +1 -0
- package/dist/vanilla/components/InquiryDetailsStep.d.ts +10 -0
- package/dist/vanilla/components/PatientDetailsStep.d.ts +3 -0
- package/dist/vanilla/components/PhoneVerificationStep.d.ts +3 -0
- package/dist/vanilla/components/SuccessStep.d.ts +5 -0
- package/dist/vanilla/components/custom-calendar.d.ts +5 -0
- package/dist/vanilla/components/styles.d.ts +6 -0
- package/dist/vanilla/components/theme-styles.d.ts +12 -0
- package/dist/vanilla/components/types.d.ts +181 -0
- package/dist/vanilla/components/ui/select.d.ts +10 -0
- package/dist/vanilla/components/uiComponents/SelectDropdown.d.ts +41 -0
- package/dist/vanilla/components/utils.d.ts +5 -0
- package/dist/vanilla/components/validation.d.ts +2 -0
- package/dist/vanilla/context/TemplateContext.d.ts +12 -0
- package/dist/vanilla/core/index.d.ts +4 -0
- package/dist/vanilla/core/theme/index.d.ts +3 -0
- package/dist/vanilla/core/theme/themes.d.ts +8 -0
- package/dist/vanilla/core/theme/types.d.ts +106 -0
- package/dist/vanilla/core/theme/utils.d.ts +8 -0
- package/dist/vanilla/enquiry-form/index.d.ts +4 -0
- package/dist/vanilla/enquiry-form/provider.d.ts +3 -0
- package/dist/vanilla/enquiry-form/serialization.d.ts +4 -0
- package/dist/vanilla/enquiry-form/types.d.ts +38 -0
- package/dist/vanilla/enquiry-form/validation.d.ts +6 -0
- package/dist/vanilla/enquiry-widget.js +4650 -0
- package/dist/vanilla/index.d.ts +9 -0
- package/dist/vanilla/index.js +3 -1
- package/dist/vanilla/lib/templateUtils.d.ts +3 -0
- package/dist/vanilla/react/ThemeProvider.d.ts +18 -0
- package/dist/vanilla/react/hooks/useTheme.d.ts +1 -0
- package/dist/vanilla/react/index.d.ts +5 -0
- package/dist/vanilla/services/AppointmentService.d.ts +4 -5
- package/dist/vanilla/services/EnquiryService.d.ts +5 -0
- package/dist/vanilla/templates/alternative.css +13 -0
- package/dist/vanilla/templates/default.css +13 -0
- package/dist/vanilla/templates/registry.d.ts +12 -0
- package/dist/vanilla/theme-injector.d.ts +6 -0
- package/dist/vanilla/theme-injector.js +44 -0
- package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +2 -34
- package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +35 -0
- package/dist/vanilla/vanilla/index.d.ts +3 -1
- package/dist/vanilla/vanilla/theme-injector.d.ts +6 -0
- package/dist/vanilla/vanilla/widget.d.ts +6 -1
- package/dist/vanilla/widget.css +173 -0
- package/dist/vanilla/widget.d.ts +6 -1
- package/dist/vanilla/widget.js +813 -288
- package/package.json +9 -4
package/dist/vanilla/widget.js
CHANGED
|
@@ -3885,7 +3885,7 @@
|
|
|
3885
3885
|
};
|
|
3886
3886
|
|
|
3887
3887
|
class MedosClient {
|
|
3888
|
-
static async init({ apiKey
|
|
3888
|
+
static async init({ apiKey }) {
|
|
3889
3889
|
if (!apiKey) {
|
|
3890
3890
|
throw new Error("MedosClient.init() requires 'apiKey'");
|
|
3891
3891
|
}
|
|
@@ -3895,7 +3895,7 @@
|
|
|
3895
3895
|
this.initPromise = (async () => {
|
|
3896
3896
|
try {
|
|
3897
3897
|
const sessionToken = await AuthService.init(apiKey);
|
|
3898
|
-
this.initializeAxiosInstance(sessionToken,
|
|
3898
|
+
this.initializeAxiosInstance(sessionToken, "https://api.medos.one");
|
|
3899
3899
|
}
|
|
3900
3900
|
catch (e) {
|
|
3901
3901
|
this.initPromise = null;
|
|
@@ -3904,7 +3904,7 @@
|
|
|
3904
3904
|
})();
|
|
3905
3905
|
return this.initPromise;
|
|
3906
3906
|
}
|
|
3907
|
-
static async initWithSession({ sessionToken
|
|
3907
|
+
static async initWithSession({ sessionToken }) {
|
|
3908
3908
|
if (!sessionToken) {
|
|
3909
3909
|
throw new Error("MedosClient.initWithSession() requires 'sessionToken'");
|
|
3910
3910
|
}
|
|
@@ -3913,7 +3913,7 @@
|
|
|
3913
3913
|
}
|
|
3914
3914
|
this.initPromise = (async () => {
|
|
3915
3915
|
try {
|
|
3916
|
-
this.initializeAxiosInstance(sessionToken,
|
|
3916
|
+
this.initializeAxiosInstance(sessionToken, "https://api.medos.one");
|
|
3917
3917
|
}
|
|
3918
3918
|
catch (e) {
|
|
3919
3919
|
this.initPromise = null;
|
|
@@ -4072,18 +4072,19 @@
|
|
|
4072
4072
|
.map((ad) => {
|
|
4073
4073
|
const addr = ad.address;
|
|
4074
4074
|
const doctors = (ad.doctors || []).map((d) => ({
|
|
4075
|
-
id:
|
|
4076
|
-
name: `${d.firstName || ""} ${d.lastName || ""}`.trim() ||
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4075
|
+
id: Number(d.user.id),
|
|
4076
|
+
name: `${d.user.firstName || ""} ${d.user.lastName || ""}`.trim() ||
|
|
4077
|
+
"Doctor",
|
|
4078
|
+
email: d.user.email,
|
|
4079
|
+
gender: d.user.gender,
|
|
4080
|
+
countryCode: d.user.countryCode,
|
|
4081
|
+
phoneNumber: d.user.phoneNumber,
|
|
4082
|
+
dob: d.user.dob,
|
|
4083
|
+
platform: d.user.platform,
|
|
4084
|
+
isKycCompleted: d.user.isKycCompleted,
|
|
4084
4085
|
}));
|
|
4085
4086
|
return {
|
|
4086
|
-
id:
|
|
4087
|
+
id: Number(addr.id),
|
|
4087
4088
|
completeAddress: addr.completeAddress,
|
|
4088
4089
|
addressLine1: addr.addressLine1,
|
|
4089
4090
|
addressLine2: addr.addressLine2,
|
|
@@ -4109,6 +4110,7 @@
|
|
|
4109
4110
|
},
|
|
4110
4111
|
async fetchSlots(workspaceId, addressId, doctorId, appointmentDate) {
|
|
4111
4112
|
const client = await MedosClient.ensureInitialized();
|
|
4113
|
+
console.log("fetching slots", workspaceId, addressId, doctorId, appointmentDate);
|
|
4112
4114
|
const res = await client.get(`/appointments/available-slots`, {
|
|
4113
4115
|
params: {
|
|
4114
4116
|
workspaceId,
|
|
@@ -4169,40 +4171,68 @@
|
|
|
4169
4171
|
},
|
|
4170
4172
|
};
|
|
4171
4173
|
|
|
4174
|
+
const INITIAL_STATE = {
|
|
4175
|
+
step: 0,
|
|
4176
|
+
loading: false,
|
|
4177
|
+
error: null,
|
|
4178
|
+
workspaceId: null,
|
|
4179
|
+
addresses: [],
|
|
4180
|
+
addressDoctorsMap: {},
|
|
4181
|
+
selectedAddress: null,
|
|
4182
|
+
selectedDoctor: null,
|
|
4183
|
+
selectedDate: new Date(),
|
|
4184
|
+
slots: [],
|
|
4185
|
+
selectedSlot: null,
|
|
4186
|
+
consultationMode: "OFFLINE",
|
|
4187
|
+
consultationCharge: "",
|
|
4188
|
+
patientName: "",
|
|
4189
|
+
patientAge: "",
|
|
4190
|
+
patientEmail: "",
|
|
4191
|
+
patientGender: "",
|
|
4192
|
+
bloodGroup: "",
|
|
4193
|
+
patientAddress: "",
|
|
4194
|
+
patientCity: "",
|
|
4195
|
+
patientState: "",
|
|
4196
|
+
patientCountry: "",
|
|
4197
|
+
patientZipcode: "",
|
|
4198
|
+
patientLandmark: "",
|
|
4199
|
+
countryCode: "+91",
|
|
4200
|
+
patientPhone: "",
|
|
4201
|
+
otpCode: "",
|
|
4202
|
+
otpSent: false,
|
|
4203
|
+
otpVerified: false,
|
|
4204
|
+
otpSending: false,
|
|
4205
|
+
otpVerifying: false,
|
|
4206
|
+
};
|
|
4207
|
+
|
|
4208
|
+
const validatePhoneNumber$1 = (phone) => {
|
|
4209
|
+
const cleaned = phone.replace(/\D/g, "");
|
|
4210
|
+
return cleaned.length >= 7 && cleaned.length <= 15;
|
|
4211
|
+
};
|
|
4212
|
+
const validateCountryCode$1 = (code) => {
|
|
4213
|
+
return /^\+[1-9]\d{0,3}$/.test(code);
|
|
4214
|
+
};
|
|
4215
|
+
|
|
4216
|
+
const formatDateToISO = (date) => {
|
|
4217
|
+
const year = String(date.getFullYear()).padStart(4, "0");
|
|
4218
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
4219
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
4220
|
+
return `${year}-${month}-${day}`;
|
|
4221
|
+
};
|
|
4222
|
+
const parsePatientName = (fullName) => {
|
|
4223
|
+
const nameParts = fullName.trim().split(/\s+/);
|
|
4224
|
+
const firstName = nameParts[0] || "Patient";
|
|
4225
|
+
const lastName = nameParts.slice(1).join(" ") || "";
|
|
4226
|
+
return {
|
|
4227
|
+
firstName,
|
|
4228
|
+
lastName,
|
|
4229
|
+
};
|
|
4230
|
+
};
|
|
4231
|
+
|
|
4172
4232
|
class AppointmentCalendarWidget {
|
|
4173
4233
|
constructor(container, options) {
|
|
4174
4234
|
this.mounted = true;
|
|
4175
|
-
this.step = 0;
|
|
4176
|
-
this.addresses = [];
|
|
4177
|
-
this.addressDoctorsMap = {};
|
|
4178
|
-
this.selectedAddress = null;
|
|
4179
|
-
this.workspaceId = null;
|
|
4180
4235
|
this.doctors = [];
|
|
4181
|
-
this.selectedDoctor = null;
|
|
4182
|
-
this.date = "";
|
|
4183
|
-
this.slots = [];
|
|
4184
|
-
this.selectedSlot = null;
|
|
4185
|
-
this.loading = false;
|
|
4186
|
-
this.error = null;
|
|
4187
|
-
this.patientName = "";
|
|
4188
|
-
this.patientAge = "";
|
|
4189
|
-
this.patientAddress = "";
|
|
4190
|
-
this.patientCity = "";
|
|
4191
|
-
this.patientState = "";
|
|
4192
|
-
this.patientCountry = "";
|
|
4193
|
-
this.patientZipcode = "";
|
|
4194
|
-
this.patientLandmark = "";
|
|
4195
|
-
this.patientEmail = "";
|
|
4196
|
-
this.patientGender = "";
|
|
4197
|
-
this.problemFacing = "";
|
|
4198
|
-
this.consultationCharge = "";
|
|
4199
|
-
this.countryCode = "+91";
|
|
4200
|
-
this.patientPhone = "";
|
|
4201
|
-
this.otpCode = "";
|
|
4202
|
-
this.otpSent = false;
|
|
4203
|
-
this.otpVerified = false;
|
|
4204
|
-
this.otpSending = false;
|
|
4205
|
-
this.otpVerifying = false;
|
|
4206
4236
|
if (typeof container === "string") {
|
|
4207
4237
|
const el = document.getElementById(container);
|
|
4208
4238
|
if (!el) {
|
|
@@ -4214,19 +4244,18 @@
|
|
|
4214
4244
|
this.container = container;
|
|
4215
4245
|
}
|
|
4216
4246
|
this.options = options;
|
|
4247
|
+
this.state = { ...INITIAL_STATE };
|
|
4217
4248
|
this.init();
|
|
4218
4249
|
}
|
|
4219
4250
|
async init() {
|
|
4220
4251
|
if (this.options.apiKey) {
|
|
4221
4252
|
await MedosClient.init({
|
|
4222
4253
|
apiKey: this.options.apiKey,
|
|
4223
|
-
baseURL: this.options.baseURL,
|
|
4224
4254
|
});
|
|
4225
4255
|
}
|
|
4226
4256
|
else if (this.options.sessionToken) {
|
|
4227
4257
|
await MedosClient.initWithSession({
|
|
4228
4258
|
sessionToken: this.options.sessionToken,
|
|
4229
|
-
baseURL: this.options.baseURL,
|
|
4230
4259
|
});
|
|
4231
4260
|
}
|
|
4232
4261
|
else {
|
|
@@ -4236,19 +4265,18 @@
|
|
|
4236
4265
|
this.render();
|
|
4237
4266
|
}
|
|
4238
4267
|
async loadAddresses() {
|
|
4239
|
-
this.
|
|
4240
|
-
this.setError(null);
|
|
4268
|
+
this.setState({ loading: true, error: null });
|
|
4241
4269
|
try {
|
|
4242
4270
|
const addrResp = await AppointmentService.getAddresses();
|
|
4243
4271
|
if (addrResp && Array.isArray(addrResp.addresses)) {
|
|
4244
4272
|
const fetchedAddresses = addrResp.addresses;
|
|
4245
4273
|
if (addrResp.workspaceId) {
|
|
4246
|
-
this.workspaceId = addrResp.workspaceId;
|
|
4274
|
+
this.state.workspaceId = addrResp.workspaceId;
|
|
4247
4275
|
}
|
|
4248
4276
|
if (fetchedAddresses.length > 0) {
|
|
4249
4277
|
const addrMap = {};
|
|
4250
4278
|
const mappedAddrs = fetchedAddresses.map((a, idx) => {
|
|
4251
|
-
const id =
|
|
4279
|
+
const id = Number(a.id ?? idx);
|
|
4252
4280
|
const label = a.completeAddress ?? a.label ?? a.address ?? `Address ${idx + 1}`;
|
|
4253
4281
|
const docs = Array.isArray(a.doctors)
|
|
4254
4282
|
? a.doctors
|
|
@@ -4256,233 +4284,242 @@
|
|
|
4256
4284
|
addrMap[id] = docs || [];
|
|
4257
4285
|
return { id, label };
|
|
4258
4286
|
});
|
|
4259
|
-
this.addresses = mappedAddrs;
|
|
4260
|
-
this.addressDoctorsMap = addrMap;
|
|
4287
|
+
this.state.addresses = mappedAddrs;
|
|
4288
|
+
this.state.addressDoctorsMap = addrMap;
|
|
4261
4289
|
const anyDoctorsExist = Object.values(addrMap).some((arr) => Array.isArray(arr) && arr.length > 0);
|
|
4262
4290
|
if (mappedAddrs.length === 1) {
|
|
4263
4291
|
const only = mappedAddrs[0];
|
|
4264
|
-
this.selectedAddress = only.id;
|
|
4292
|
+
this.state.selectedAddress = only.id;
|
|
4265
4293
|
const docsForAddr = addrMap[only.id] || [];
|
|
4266
4294
|
if (docsForAddr.length > 0) {
|
|
4267
4295
|
this.doctors = docsForAddr;
|
|
4268
4296
|
if (docsForAddr.length === 1) {
|
|
4269
|
-
this.selectedDoctor = docsForAddr[0].id;
|
|
4270
|
-
this.step = 1;
|
|
4297
|
+
this.state.selectedDoctor = docsForAddr[0].id;
|
|
4298
|
+
this.state.step = 1;
|
|
4271
4299
|
}
|
|
4272
4300
|
else {
|
|
4273
|
-
this.step = 0;
|
|
4301
|
+
this.state.step = 0;
|
|
4274
4302
|
}
|
|
4275
4303
|
}
|
|
4276
4304
|
else {
|
|
4277
4305
|
if (anyDoctorsExist) {
|
|
4278
|
-
this.
|
|
4306
|
+
this.setState({
|
|
4307
|
+
error: "No doctors at this address. Please choose a different address.",
|
|
4308
|
+
});
|
|
4279
4309
|
this.doctors = [];
|
|
4280
|
-
this.step = 0;
|
|
4310
|
+
this.state.step = 0;
|
|
4281
4311
|
}
|
|
4282
4312
|
else {
|
|
4283
|
-
this.
|
|
4313
|
+
this.setState({
|
|
4314
|
+
error: "No doctors available for the selected location(s).",
|
|
4315
|
+
});
|
|
4284
4316
|
this.doctors = [];
|
|
4285
|
-
this.step = 0;
|
|
4317
|
+
this.state.step = 0;
|
|
4286
4318
|
}
|
|
4287
4319
|
}
|
|
4288
4320
|
}
|
|
4289
4321
|
else {
|
|
4290
|
-
this.step = 0;
|
|
4322
|
+
this.state.step = 0;
|
|
4291
4323
|
}
|
|
4292
4324
|
}
|
|
4293
4325
|
else {
|
|
4294
|
-
this.
|
|
4295
|
-
this.addresses = [];
|
|
4296
|
-
this.addressDoctorsMap = {};
|
|
4326
|
+
this.setState({ error: "No addresses or doctors available." });
|
|
4327
|
+
this.state.addresses = [];
|
|
4328
|
+
this.state.addressDoctorsMap = {};
|
|
4297
4329
|
this.doctors = [];
|
|
4298
|
-
this.step = 0;
|
|
4330
|
+
this.state.step = 0;
|
|
4299
4331
|
}
|
|
4300
4332
|
}
|
|
4301
4333
|
}
|
|
4302
4334
|
catch (e) {
|
|
4303
4335
|
const msg = e.message || "Failed to load addresses";
|
|
4304
|
-
this.
|
|
4336
|
+
this.setState({ error: msg });
|
|
4305
4337
|
this.options.onError?.(e);
|
|
4306
4338
|
}
|
|
4307
4339
|
finally {
|
|
4308
|
-
this.
|
|
4340
|
+
this.setState({ loading: false });
|
|
4309
4341
|
}
|
|
4310
4342
|
}
|
|
4311
4343
|
async handleAddressChange(addressId) {
|
|
4312
|
-
this.selectedAddress = addressId;
|
|
4344
|
+
this.state.selectedAddress = addressId;
|
|
4313
4345
|
if (!addressId) {
|
|
4314
4346
|
this.doctors = [];
|
|
4315
|
-
this.selectedDoctor = null;
|
|
4347
|
+
this.state.selectedDoctor = null;
|
|
4316
4348
|
this.render();
|
|
4317
4349
|
return;
|
|
4318
4350
|
}
|
|
4319
|
-
this.
|
|
4320
|
-
this.setError(null);
|
|
4351
|
+
this.setState({ loading: true, error: null });
|
|
4321
4352
|
try {
|
|
4322
|
-
const docsForAddr = this.addressDoctorsMap[addressId] ?? [];
|
|
4353
|
+
const docsForAddr = this.state.addressDoctorsMap[addressId] ?? [];
|
|
4323
4354
|
if (docsForAddr.length > 0) {
|
|
4324
4355
|
this.doctors = docsForAddr;
|
|
4325
4356
|
if (docsForAddr.length === 1) {
|
|
4326
|
-
this.selectedDoctor = docsForAddr[0].id;
|
|
4327
|
-
this.step = 1;
|
|
4357
|
+
this.state.selectedDoctor = docsForAddr[0].id;
|
|
4358
|
+
this.state.step = 1;
|
|
4328
4359
|
}
|
|
4329
4360
|
else {
|
|
4330
|
-
this.selectedDoctor = null;
|
|
4361
|
+
this.state.selectedDoctor = null;
|
|
4331
4362
|
}
|
|
4332
4363
|
}
|
|
4333
4364
|
else {
|
|
4334
|
-
const otherHasDoctors = Object.entries(this.addressDoctorsMap).some(([key, docs]) => key !== addressId && Array.isArray(docs) && docs.length > 0);
|
|
4365
|
+
const otherHasDoctors = Object.entries(this.state.addressDoctorsMap).some(([key, docs]) => Number(key) !== addressId && Array.isArray(docs) && docs.length > 0);
|
|
4335
4366
|
this.doctors = [];
|
|
4336
|
-
this.selectedDoctor = null;
|
|
4367
|
+
this.state.selectedDoctor = null;
|
|
4337
4368
|
if (otherHasDoctors) {
|
|
4338
|
-
this.
|
|
4369
|
+
this.setState({
|
|
4370
|
+
error: "No doctors at this address. Please select a different address.",
|
|
4371
|
+
});
|
|
4339
4372
|
}
|
|
4340
4373
|
else {
|
|
4341
|
-
this.
|
|
4374
|
+
this.setState({
|
|
4375
|
+
error: "No doctors available for the selected location(s).",
|
|
4376
|
+
});
|
|
4342
4377
|
}
|
|
4343
4378
|
}
|
|
4344
4379
|
}
|
|
4345
4380
|
catch (e) {
|
|
4346
|
-
this.
|
|
4381
|
+
this.setState({
|
|
4382
|
+
error: e.message || "Failed to load doctors for address",
|
|
4383
|
+
});
|
|
4347
4384
|
}
|
|
4348
4385
|
finally {
|
|
4349
|
-
this.
|
|
4386
|
+
this.setState({ loading: false });
|
|
4350
4387
|
this.render();
|
|
4351
4388
|
}
|
|
4352
4389
|
}
|
|
4353
4390
|
async loadSlots() {
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
this.
|
|
4391
|
+
const dateStr = formatDateToISO(this.state.selectedDate);
|
|
4392
|
+
if (!this.state.workspaceId ||
|
|
4393
|
+
!this.state.selectedAddress ||
|
|
4394
|
+
!this.state.selectedDoctor ||
|
|
4395
|
+
!dateStr) {
|
|
4396
|
+
this.state.slots = [];
|
|
4397
|
+
this.state.selectedSlot = null;
|
|
4357
4398
|
this.render();
|
|
4358
4399
|
return;
|
|
4359
4400
|
}
|
|
4360
|
-
this.
|
|
4361
|
-
this.setError(null);
|
|
4401
|
+
this.setState({ loading: true, error: null });
|
|
4362
4402
|
try {
|
|
4363
|
-
const s = await AppointmentService.fetchSlots(this.workspaceId, this.selectedAddress, this.selectedDoctor,
|
|
4364
|
-
this.slots = s || [];
|
|
4403
|
+
const s = await AppointmentService.fetchSlots(this.state.workspaceId, this.state.selectedAddress, this.state.selectedDoctor, dateStr);
|
|
4404
|
+
this.state.slots = s || [];
|
|
4365
4405
|
}
|
|
4366
4406
|
catch (e) {
|
|
4367
|
-
this.
|
|
4407
|
+
this.setState({ error: e.message || "Failed to load slots" });
|
|
4368
4408
|
}
|
|
4369
4409
|
finally {
|
|
4370
|
-
this.
|
|
4410
|
+
this.setState({ loading: false });
|
|
4371
4411
|
this.render();
|
|
4372
4412
|
}
|
|
4373
4413
|
}
|
|
4374
|
-
validatePhoneNumber(phone) {
|
|
4375
|
-
const cleaned = phone.replace(/\D/g, "");
|
|
4376
|
-
return cleaned.length >= 7 && cleaned.length <= 15;
|
|
4377
|
-
}
|
|
4378
|
-
validateCountryCode(code) {
|
|
4379
|
-
return /^\+[1-9]\d{0,3}$/.test(code);
|
|
4380
|
-
}
|
|
4381
4414
|
canProceedFromMergedStep() {
|
|
4382
|
-
if (this.addresses.length === 0 || this.doctors.length === 0)
|
|
4415
|
+
if (this.state.addresses.length === 0 || this.doctors.length === 0)
|
|
4383
4416
|
return false;
|
|
4384
|
-
if (this.addresses.length > 1 && !this.selectedAddress)
|
|
4417
|
+
if (this.state.addresses.length > 1 && !this.state.selectedAddress)
|
|
4385
4418
|
return false;
|
|
4386
|
-
if (this.doctors.length > 1 && !this.selectedDoctor)
|
|
4419
|
+
if (this.doctors.length > 1 && !this.state.selectedDoctor)
|
|
4387
4420
|
return false;
|
|
4388
4421
|
return true;
|
|
4389
4422
|
}
|
|
4390
4423
|
async sendOtp() {
|
|
4391
|
-
this.
|
|
4392
|
-
if (!this.countryCode) {
|
|
4393
|
-
this.
|
|
4424
|
+
this.setState({ error: null });
|
|
4425
|
+
if (!this.state.countryCode) {
|
|
4426
|
+
this.setState({ error: "Please enter country code." });
|
|
4394
4427
|
return;
|
|
4395
4428
|
}
|
|
4396
|
-
if (!
|
|
4397
|
-
this.
|
|
4429
|
+
if (!validateCountryCode$1(this.state.countryCode)) {
|
|
4430
|
+
this.setState({
|
|
4431
|
+
error: "Please enter a valid country code (e.g., +91, +1).",
|
|
4432
|
+
});
|
|
4398
4433
|
return;
|
|
4399
4434
|
}
|
|
4400
|
-
if (!this.patientPhone) {
|
|
4401
|
-
this.
|
|
4435
|
+
if (!this.state.patientPhone) {
|
|
4436
|
+
this.setState({ error: "Please enter phone number." });
|
|
4402
4437
|
return;
|
|
4403
4438
|
}
|
|
4404
|
-
if (!
|
|
4405
|
-
this.
|
|
4439
|
+
if (!validatePhoneNumber$1(this.state.patientPhone)) {
|
|
4440
|
+
this.setState({
|
|
4441
|
+
error: "Please enter a valid phone number (7-15 digits).",
|
|
4442
|
+
});
|
|
4406
4443
|
return;
|
|
4407
4444
|
}
|
|
4408
|
-
this.otpSending
|
|
4445
|
+
this.setState({ otpSending: true });
|
|
4409
4446
|
this.render();
|
|
4410
4447
|
try {
|
|
4411
4448
|
await PatientService.sendPhoneVerificationOtp({
|
|
4412
|
-
countryCode: this.countryCode,
|
|
4413
|
-
phoneNumber: this.patientPhone,
|
|
4449
|
+
countryCode: this.state.countryCode,
|
|
4450
|
+
phoneNumber: this.state.patientPhone,
|
|
4414
4451
|
});
|
|
4415
|
-
this.otpSent
|
|
4416
|
-
this.setError(null);
|
|
4452
|
+
this.setState({ otpSent: true, error: null });
|
|
4417
4453
|
}
|
|
4418
4454
|
catch (e) {
|
|
4419
4455
|
const msg = e.message || "Failed to send OTP";
|
|
4420
|
-
this.
|
|
4456
|
+
this.setState({ error: msg });
|
|
4421
4457
|
this.options.onError?.(e);
|
|
4422
4458
|
}
|
|
4423
4459
|
finally {
|
|
4424
|
-
this.otpSending
|
|
4460
|
+
this.setState({ otpSending: false });
|
|
4425
4461
|
this.render();
|
|
4426
4462
|
}
|
|
4427
4463
|
}
|
|
4428
4464
|
async verifyOtp() {
|
|
4429
|
-
this.
|
|
4430
|
-
if (!this.countryCode ||
|
|
4431
|
-
this.
|
|
4465
|
+
this.setState({ error: null });
|
|
4466
|
+
if (!this.state.countryCode ||
|
|
4467
|
+
!this.state.patientPhone ||
|
|
4468
|
+
!this.state.otpCode) {
|
|
4469
|
+
this.setState({ error: "Please enter all required fields." });
|
|
4432
4470
|
return;
|
|
4433
4471
|
}
|
|
4434
|
-
if (this.otpCode.length !== 6) {
|
|
4435
|
-
this.
|
|
4472
|
+
if (this.state.otpCode.length !== 6) {
|
|
4473
|
+
this.setState({ error: "Please enter a 6-digit OTP code." });
|
|
4436
4474
|
return;
|
|
4437
4475
|
}
|
|
4438
|
-
this.otpVerifying
|
|
4476
|
+
this.setState({ otpVerifying: true });
|
|
4439
4477
|
this.render();
|
|
4440
4478
|
try {
|
|
4441
4479
|
await PatientService.verifyPhoneVerificationOtp({
|
|
4442
|
-
countryCode: this.countryCode,
|
|
4443
|
-
phoneNumber: this.patientPhone,
|
|
4444
|
-
otpCode: this.otpCode,
|
|
4480
|
+
countryCode: this.state.countryCode,
|
|
4481
|
+
phoneNumber: this.state.patientPhone,
|
|
4482
|
+
otpCode: this.state.otpCode,
|
|
4445
4483
|
});
|
|
4446
|
-
this.otpVerified
|
|
4447
|
-
this.setError(null);
|
|
4484
|
+
this.setState({ otpVerified: true, error: null });
|
|
4448
4485
|
}
|
|
4449
4486
|
catch (e) {
|
|
4450
4487
|
const msg = e.message || "Invalid OTP code";
|
|
4451
|
-
this.
|
|
4488
|
+
this.setState({ error: msg });
|
|
4452
4489
|
this.options.onError?.(e);
|
|
4453
4490
|
}
|
|
4454
4491
|
finally {
|
|
4455
|
-
this.otpVerifying
|
|
4492
|
+
this.setState({ otpVerifying: false });
|
|
4456
4493
|
this.render();
|
|
4457
4494
|
}
|
|
4458
4495
|
}
|
|
4459
4496
|
async submitAppointment() {
|
|
4460
|
-
this.
|
|
4461
|
-
if (!this.selectedDoctor ||
|
|
4462
|
-
!this.selectedSlot ||
|
|
4463
|
-
!this.workspaceId ||
|
|
4464
|
-
!this.selectedAddress ||
|
|
4465
|
-
!this.patientAddress ||
|
|
4466
|
-
!this.patientCity ||
|
|
4467
|
-
!this.patientState ||
|
|
4468
|
-
!this.patientCountry ||
|
|
4469
|
-
!this.patientZipcode) {
|
|
4470
|
-
this.
|
|
4497
|
+
this.setState({ error: null });
|
|
4498
|
+
if (!this.state.selectedDoctor ||
|
|
4499
|
+
!this.state.selectedSlot ||
|
|
4500
|
+
!this.state.workspaceId ||
|
|
4501
|
+
!this.state.selectedAddress ||
|
|
4502
|
+
!this.state.patientAddress ||
|
|
4503
|
+
!this.state.patientCity ||
|
|
4504
|
+
!this.state.patientState ||
|
|
4505
|
+
!this.state.patientCountry ||
|
|
4506
|
+
!this.state.patientZipcode) {
|
|
4507
|
+
this.setState({
|
|
4508
|
+
error: "Please ensure all required fields are complete.",
|
|
4509
|
+
});
|
|
4471
4510
|
return;
|
|
4472
4511
|
}
|
|
4473
|
-
if (!this.otpVerified) {
|
|
4474
|
-
this.
|
|
4512
|
+
if (!this.state.otpVerified) {
|
|
4513
|
+
this.setState({ error: "Please verify your phone number first." });
|
|
4475
4514
|
return;
|
|
4476
4515
|
}
|
|
4477
|
-
this.
|
|
4516
|
+
this.setState({ loading: true });
|
|
4478
4517
|
this.render();
|
|
4479
4518
|
try {
|
|
4480
|
-
const
|
|
4481
|
-
const
|
|
4482
|
-
const
|
|
4483
|
-
const
|
|
4484
|
-
const endDate = new Date(this.selectedSlot.end);
|
|
4485
|
-
const appointmentDate = startDate.toISOString().split("T")[0];
|
|
4519
|
+
const { firstName, lastName } = parsePatientName(this.state.patientName || "Patient");
|
|
4520
|
+
const startDate = new Date(this.state.selectedSlot.start);
|
|
4521
|
+
const endDate = new Date(this.state.selectedSlot.end);
|
|
4522
|
+
const appointmentDate = formatDateToISO(startDate);
|
|
4486
4523
|
const formatTime = (date) => {
|
|
4487
4524
|
const hours = String(date.getHours()).padStart(2, "0");
|
|
4488
4525
|
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
@@ -4491,112 +4528,92 @@
|
|
|
4491
4528
|
const fromDateTimeTs = formatTime(startDate);
|
|
4492
4529
|
const toDateTimeTs = formatTime(endDate);
|
|
4493
4530
|
const patientAddressPayload = {
|
|
4494
|
-
addressLine1: this.patientAddress,
|
|
4495
|
-
city: this.patientCity,
|
|
4496
|
-
state: this.patientState,
|
|
4497
|
-
country: this.patientCountry,
|
|
4498
|
-
zipcode: this.patientZipcode,
|
|
4499
|
-
landmark: this.patientLandmark || undefined,
|
|
4531
|
+
addressLine1: this.state.patientAddress,
|
|
4532
|
+
city: this.state.patientCity,
|
|
4533
|
+
state: this.state.patientState,
|
|
4534
|
+
country: this.state.patientCountry,
|
|
4535
|
+
zipcode: this.state.patientZipcode,
|
|
4536
|
+
landmark: this.state.patientLandmark || undefined,
|
|
4500
4537
|
};
|
|
4501
4538
|
await AppointmentService.createAppointment({
|
|
4502
|
-
workspaceId: this.workspaceId,
|
|
4503
|
-
workspaceAddressId: this.selectedAddress,
|
|
4504
|
-
doctorId: this.selectedDoctor,
|
|
4539
|
+
workspaceId: this.state.workspaceId,
|
|
4540
|
+
workspaceAddressId: this.state.selectedAddress,
|
|
4541
|
+
doctorId: this.state.selectedDoctor,
|
|
4505
4542
|
mode: "OFFLINE",
|
|
4506
4543
|
appointmentDate,
|
|
4507
4544
|
fromDateTimeTs,
|
|
4508
4545
|
toDateTimeTs,
|
|
4509
|
-
consultationCharge: this.consultationCharge || "0",
|
|
4546
|
+
consultationCharge: this.state.consultationCharge || "0",
|
|
4510
4547
|
type: "CONSULTATION",
|
|
4511
4548
|
source: "SDK_POWERED_WEBSITE",
|
|
4512
4549
|
patientPayload: {
|
|
4513
4550
|
firstName,
|
|
4514
4551
|
lastName,
|
|
4515
|
-
email: this.patientEmail || undefined,
|
|
4516
|
-
countryCode: this.countryCode,
|
|
4517
|
-
phoneNumber: this.patientPhone,
|
|
4518
|
-
age: this.
|
|
4519
|
-
|
|
4520
|
-
|
|
4552
|
+
email: this.state.patientEmail || undefined,
|
|
4553
|
+
countryCode: this.state.countryCode,
|
|
4554
|
+
phoneNumber: this.state.patientPhone,
|
|
4555
|
+
age: this.state.patientAge
|
|
4556
|
+
? parseInt(this.state.patientAge, 10)
|
|
4557
|
+
: undefined,
|
|
4558
|
+
gender: this.state.patientGender
|
|
4559
|
+
? this.state.patientGender.toUpperCase()
|
|
4521
4560
|
: undefined,
|
|
4522
4561
|
},
|
|
4523
4562
|
patientAddress: patientAddressPayload,
|
|
4524
4563
|
});
|
|
4525
|
-
this.step = 5;
|
|
4564
|
+
this.state.step = 5;
|
|
4526
4565
|
this.options.onSuccess?.();
|
|
4527
4566
|
}
|
|
4528
4567
|
catch (e) {
|
|
4529
4568
|
const msg = e.message || "Failed to create appointment";
|
|
4530
|
-
this.
|
|
4569
|
+
this.setState({ error: msg });
|
|
4531
4570
|
this.options.onError?.(e);
|
|
4532
4571
|
}
|
|
4533
4572
|
finally {
|
|
4534
|
-
this.
|
|
4573
|
+
this.setState({ loading: false });
|
|
4535
4574
|
this.render();
|
|
4536
4575
|
}
|
|
4537
4576
|
}
|
|
4538
4577
|
goToNext() {
|
|
4539
|
-
if (this.step === 0) {
|
|
4540
|
-
if (this.addresses.length > 1 && !this.selectedAddress)
|
|
4578
|
+
if (this.state.step === 0) {
|
|
4579
|
+
if (this.state.addresses.length > 1 && !this.state.selectedAddress)
|
|
4541
4580
|
return;
|
|
4542
|
-
if (this.doctors.length > 1 && !this.selectedDoctor)
|
|
4581
|
+
if (this.doctors.length > 1 && !this.state.selectedDoctor)
|
|
4543
4582
|
return;
|
|
4544
|
-
this.step = 1;
|
|
4583
|
+
this.state.step = 1;
|
|
4545
4584
|
this.render();
|
|
4546
4585
|
return;
|
|
4547
4586
|
}
|
|
4548
|
-
|
|
4549
|
-
|
|
4587
|
+
const dateStr = formatDateToISO(this.state.selectedDate);
|
|
4588
|
+
if (this.state.step === 1 && dateStr) {
|
|
4589
|
+
this.state.step = 2;
|
|
4550
4590
|
this.loadSlots();
|
|
4551
4591
|
return;
|
|
4552
4592
|
}
|
|
4553
|
-
if (this.step === 2 && this.selectedSlot) {
|
|
4554
|
-
this.step = 3;
|
|
4593
|
+
if (this.state.step === 2 && this.state.selectedSlot) {
|
|
4594
|
+
this.state.step = 3;
|
|
4555
4595
|
this.render();
|
|
4556
4596
|
return;
|
|
4557
4597
|
}
|
|
4558
|
-
if (this.step === 3 && this.otpVerified) {
|
|
4559
|
-
this.step = 4;
|
|
4598
|
+
if (this.state.step === 3 && this.state.otpVerified) {
|
|
4599
|
+
this.state.step = 4;
|
|
4560
4600
|
this.render();
|
|
4561
4601
|
return;
|
|
4562
4602
|
}
|
|
4563
|
-
this.step = Math.min(5, this.step + 1);
|
|
4603
|
+
this.state.step = Math.min(5, this.state.step + 1);
|
|
4564
4604
|
this.render();
|
|
4565
4605
|
}
|
|
4566
4606
|
goBack() {
|
|
4567
|
-
this.step = Math.max(0, this.step - 1);
|
|
4607
|
+
this.state.step = Math.max(0, this.state.step - 1);
|
|
4568
4608
|
this.render();
|
|
4569
4609
|
}
|
|
4570
4610
|
reset() {
|
|
4571
|
-
this.
|
|
4572
|
-
this.
|
|
4573
|
-
this.selectedDoctor = null;
|
|
4574
|
-
this.date = "";
|
|
4575
|
-
this.patientName = "";
|
|
4576
|
-
this.patientAge = "";
|
|
4577
|
-
this.patientAddress = "";
|
|
4578
|
-
this.patientCity = "";
|
|
4579
|
-
this.patientState = "";
|
|
4580
|
-
this.patientCountry = "";
|
|
4581
|
-
this.patientZipcode = "";
|
|
4582
|
-
this.patientLandmark = "";
|
|
4583
|
-
this.patientEmail = "";
|
|
4584
|
-
this.patientGender = "";
|
|
4585
|
-
this.problemFacing = "";
|
|
4586
|
-
this.consultationCharge = "";
|
|
4587
|
-
this.countryCode = "+91";
|
|
4588
|
-
this.patientPhone = "";
|
|
4589
|
-
this.otpCode = "";
|
|
4590
|
-
this.otpSent = false;
|
|
4591
|
-
this.otpVerified = false;
|
|
4592
|
-
this.slots = [];
|
|
4611
|
+
this.state = { ...INITIAL_STATE };
|
|
4612
|
+
this.doctors = [];
|
|
4593
4613
|
this.render();
|
|
4594
4614
|
}
|
|
4595
|
-
|
|
4596
|
-
this.
|
|
4597
|
-
}
|
|
4598
|
-
setError(error) {
|
|
4599
|
-
this.error = error;
|
|
4615
|
+
setState(updates) {
|
|
4616
|
+
this.state = { ...this.state, ...updates };
|
|
4600
4617
|
}
|
|
4601
4618
|
render() {
|
|
4602
4619
|
if (!this.mounted)
|
|
@@ -4607,16 +4624,20 @@
|
|
|
4607
4624
|
<div class="medos-appointment-header">
|
|
4608
4625
|
<h2 class="medos-appointment-title">Book Appointment</h2>
|
|
4609
4626
|
<div class="medos-appointment-stepper">
|
|
4610
|
-
<div class="medos-appointment-step-pill ${this.step === 0 ? "active" : ""}">1 Address</div>
|
|
4611
|
-
<div class="medos-appointment-step-pill ${this.step === 1 ? "active" : ""}">2 Date</div>
|
|
4612
|
-
<div class="medos-appointment-step-pill ${this.step === 2 ? "active" : ""}">3 Slot</div>
|
|
4613
|
-
<div class="medos-appointment-step-pill ${this.step === 3 ? "active" : ""}">4 Phone</div>
|
|
4614
|
-
<div class="medos-appointment-step-pill ${this.step === 4 ? "active" : ""}">5 Details</div>
|
|
4627
|
+
<div class="medos-appointment-step-pill ${this.state.step === 0 ? "active" : ""}">1 Address</div>
|
|
4628
|
+
<div class="medos-appointment-step-pill ${this.state.step === 1 ? "active" : ""}">2 Date</div>
|
|
4629
|
+
<div class="medos-appointment-step-pill ${this.state.step === 2 ? "active" : ""}">3 Slot</div>
|
|
4630
|
+
<div class="medos-appointment-step-pill ${this.state.step === 3 ? "active" : ""}">4 Phone</div>
|
|
4631
|
+
<div class="medos-appointment-step-pill ${this.state.step === 4 ? "active" : ""}">5 Details</div>
|
|
4615
4632
|
</div>
|
|
4616
4633
|
</div>
|
|
4617
4634
|
|
|
4618
|
-
${this.loading
|
|
4619
|
-
|
|
4635
|
+
${this.state.loading
|
|
4636
|
+
? '<div class="medos-appointment-loading">Loading...</div>'
|
|
4637
|
+
: ""}
|
|
4638
|
+
${this.state.error
|
|
4639
|
+
? `<div class="medos-appointment-error">${this.escapeHtml(this.state.error)}</div>`
|
|
4640
|
+
: ""}
|
|
4620
4641
|
|
|
4621
4642
|
${this.renderStep()}
|
|
4622
4643
|
</div>
|
|
@@ -4625,7 +4646,7 @@
|
|
|
4625
4646
|
this.attachEventListeners();
|
|
4626
4647
|
}
|
|
4627
4648
|
renderStep() {
|
|
4628
|
-
switch (this.step) {
|
|
4649
|
+
switch (this.state.step) {
|
|
4629
4650
|
case 0:
|
|
4630
4651
|
return this.renderStep0();
|
|
4631
4652
|
case 1:
|
|
@@ -4649,14 +4670,16 @@
|
|
|
4649
4670
|
<div class="medos-appointment-form-grid-2col">
|
|
4650
4671
|
<div>
|
|
4651
4672
|
<label class="medos-appointment-label">Address</label>
|
|
4652
|
-
${this.addresses.length === 0
|
|
4673
|
+
${this.state.addresses.length === 0
|
|
4653
4674
|
? '<div class="medos-appointment-small-muted">No addresses available</div>'
|
|
4654
|
-
: this.addresses.length === 1
|
|
4655
|
-
? `<div class="medos-appointment-small-muted" style="font-weight: 600">${this.escapeHtml(this.addresses[0].label)}</div>`
|
|
4675
|
+
: this.state.addresses.length === 1
|
|
4676
|
+
? `<div class="medos-appointment-small-muted" style="font-weight: 600">${this.escapeHtml(this.state.addresses[0].label || "")}</div>`
|
|
4656
4677
|
: `
|
|
4657
4678
|
<select class="medos-appointment-select" id="medos-address-select">
|
|
4658
4679
|
<option value="">-- choose address --</option>
|
|
4659
|
-
${this.addresses
|
|
4680
|
+
${this.state.addresses
|
|
4681
|
+
.map((a) => `<option value="${this.escapeHtml(a.id.toString())}" ${this.state.selectedAddress === a.id ? "selected" : ""}>${this.escapeHtml(a.label || "")}</option>`)
|
|
4682
|
+
.join("")}
|
|
4660
4683
|
</select>
|
|
4661
4684
|
`}
|
|
4662
4685
|
</div>
|
|
@@ -4665,11 +4688,17 @@
|
|
|
4665
4688
|
${this.doctors.length === 0
|
|
4666
4689
|
? '<div class="medos-appointment-small-muted">No doctors available</div>'
|
|
4667
4690
|
: this.doctors.length === 1
|
|
4668
|
-
? `<div class="medos-appointment-small-muted" style="font-weight: 600">${this.escapeHtml(this.doctors[0].name)}${this.doctors[0].specialty
|
|
4691
|
+
? `<div class="medos-appointment-small-muted" style="font-weight: 600">${this.escapeHtml(this.doctors[0].name)}${this.doctors[0].specialty
|
|
4692
|
+
? ` • ${this.escapeHtml(this.doctors[0].specialty)}`
|
|
4693
|
+
: ""}</div>`
|
|
4669
4694
|
: `
|
|
4670
4695
|
<select class="medos-appointment-select" id="medos-doctor-select">
|
|
4671
4696
|
<option value="">-- choose doctor --</option>
|
|
4672
|
-
${this.doctors
|
|
4697
|
+
${this.doctors
|
|
4698
|
+
.map((d) => `<option value="${this.escapeHtml(d.id.toString())}" ${this.state.selectedDoctor === d.id ? "selected" : ""}>${this.escapeHtml(d.name)}${d.specialty
|
|
4699
|
+
? ` (${this.escapeHtml(d.specialty)})`
|
|
4700
|
+
: ""}</option>`)
|
|
4701
|
+
.join("")}
|
|
4673
4702
|
</select>
|
|
4674
4703
|
`}
|
|
4675
4704
|
</div>
|
|
@@ -4682,13 +4711,14 @@
|
|
|
4682
4711
|
`;
|
|
4683
4712
|
}
|
|
4684
4713
|
renderStep1() {
|
|
4714
|
+
const dateStr = formatDateToISO(this.state.selectedDate);
|
|
4685
4715
|
return `
|
|
4686
4716
|
<div class="medos-appointment-section">
|
|
4687
4717
|
<label class="medos-appointment-label">Select Date</label>
|
|
4688
|
-
<input type="date" class="medos-appointment-input" id="medos-date-input" value="${this.escapeHtml(
|
|
4718
|
+
<input type="date" class="medos-appointment-input" id="medos-date-input" value="${this.escapeHtml(dateStr)}" />
|
|
4689
4719
|
<div class="medos-appointment-actions">
|
|
4690
4720
|
<button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-back">Back</button>
|
|
4691
|
-
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-next" ${!
|
|
4721
|
+
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-next" ${!dateStr ? "disabled" : ""} style="opacity: ${dateStr ? 1 : 0.6}">Next</button>
|
|
4692
4722
|
</div>
|
|
4693
4723
|
</div>
|
|
4694
4724
|
`;
|
|
@@ -4697,50 +4727,63 @@
|
|
|
4697
4727
|
return `
|
|
4698
4728
|
<div class="medos-appointment-section">
|
|
4699
4729
|
<label class="medos-appointment-label">Choose Time Slot</label>
|
|
4700
|
-
${this.slots.length === 0
|
|
4730
|
+
${this.state.slots.length === 0
|
|
4701
4731
|
? '<div class="medos-appointment-small-muted">No slots available for selected date</div>'
|
|
4702
4732
|
: `
|
|
4703
4733
|
<div class="medos-appointment-slot-grid">
|
|
4704
|
-
${this.slots
|
|
4705
|
-
|
|
4706
|
-
const
|
|
4707
|
-
|
|
4734
|
+
${this.state.slots
|
|
4735
|
+
.map((s) => {
|
|
4736
|
+
const start = new Date(s.start).toLocaleTimeString([], {
|
|
4737
|
+
hour: "2-digit",
|
|
4738
|
+
minute: "2-digit",
|
|
4739
|
+
});
|
|
4740
|
+
const end = new Date(s.end).toLocaleTimeString([], {
|
|
4741
|
+
hour: "2-digit",
|
|
4742
|
+
minute: "2-digit",
|
|
4743
|
+
});
|
|
4744
|
+
const selected = this.state.selectedSlot?.start === s.start &&
|
|
4745
|
+
this.state.selectedSlot?.end === s.end;
|
|
4708
4746
|
return `
|
|
4709
4747
|
<div class="medos-appointment-slot-card ${selected ? "selected" : ""}" data-slot-id="${this.escapeHtml(s.id || `${s.start}-${s.end}`)}" data-slot-start="${this.escapeHtml(s.start)}" data-slot-end="${this.escapeHtml(s.end)}">
|
|
4710
4748
|
<div class="medos-appointment-slot-time">${start} — ${end}</div>
|
|
4711
4749
|
</div>
|
|
4712
4750
|
`;
|
|
4713
|
-
})
|
|
4751
|
+
})
|
|
4752
|
+
.join("")}
|
|
4714
4753
|
</div>
|
|
4715
4754
|
`}
|
|
4716
4755
|
<div class="medos-appointment-actions">
|
|
4717
4756
|
<button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-back">Back</button>
|
|
4718
|
-
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-next" ${!this.selectedSlot ? "disabled" : ""} style="opacity: ${this.selectedSlot ? 1 : 0.6}">Next</button>
|
|
4757
|
+
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-next" ${!this.state.selectedSlot ? "disabled" : ""} style="opacity: ${this.state.selectedSlot ? 1 : 0.6}">Next</button>
|
|
4719
4758
|
</div>
|
|
4720
4759
|
</div>
|
|
4721
4760
|
`;
|
|
4722
4761
|
}
|
|
4723
4762
|
renderStep3() {
|
|
4724
|
-
const countryCodeValid = this.countryCode &&
|
|
4725
|
-
const phoneValid = this.patientPhone &&
|
|
4726
|
-
const canSendOtp = countryCodeValid && phoneValid && !this.otpSending;
|
|
4727
|
-
if (!this.otpSent) {
|
|
4763
|
+
const countryCodeValid = this.state.countryCode && validateCountryCode$1(this.state.countryCode);
|
|
4764
|
+
const phoneValid = this.state.patientPhone && validatePhoneNumber$1(this.state.patientPhone);
|
|
4765
|
+
const canSendOtp = countryCodeValid && phoneValid && !this.state.otpSending;
|
|
4766
|
+
if (!this.state.otpSent) {
|
|
4728
4767
|
return `
|
|
4729
4768
|
<div class="medos-appointment-section">
|
|
4730
4769
|
<label class="medos-appointment-label">Country Code</label>
|
|
4731
|
-
<input type="text" class="medos-appointment-input" id="medos-country-code" placeholder="+91" value="${this.escapeHtml(this.countryCode)}" />
|
|
4732
|
-
${this.countryCode && !countryCodeValid
|
|
4770
|
+
<input type="text" class="medos-appointment-input" id="medos-country-code" placeholder="+91" value="${this.escapeHtml(this.state.countryCode)}" />
|
|
4771
|
+
${this.state.countryCode && !countryCodeValid
|
|
4772
|
+
? '<div class="medos-appointment-validation-error">Please enter a valid country code (e.g., +91, +1)</div>'
|
|
4773
|
+
: ""}
|
|
4733
4774
|
<label class="medos-appointment-label" style="margin-top: 12px">Phone Number</label>
|
|
4734
|
-
<input type="tel" class="medos-appointment-input" id="medos-phone" placeholder="9311840587" value="${this.escapeHtml(this.patientPhone)}" maxlength="15" />
|
|
4735
|
-
${this.patientPhone && !phoneValid
|
|
4775
|
+
<input type="tel" class="medos-appointment-input" id="medos-phone" placeholder="9311840587" value="${this.escapeHtml(this.state.patientPhone)}" maxlength="15" />
|
|
4776
|
+
${this.state.patientPhone && !phoneValid
|
|
4777
|
+
? '<div class="medos-appointment-validation-error">Phone number should be 7-15 digits</div>'
|
|
4778
|
+
: ""}
|
|
4736
4779
|
<div class="medos-appointment-actions">
|
|
4737
4780
|
<button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-back">Back</button>
|
|
4738
|
-
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-send-otp" ${!canSendOtp ? "disabled" : ""} style="opacity: ${canSendOtp ? 1 : 0.6}">${this.otpSending ? "Sending..." : "Send OTP"}</button>
|
|
4781
|
+
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-send-otp" ${!canSendOtp ? "disabled" : ""} style="opacity: ${canSendOtp ? 1 : 0.6}">${this.state.otpSending ? "Sending..." : "Send OTP"}</button>
|
|
4739
4782
|
</div>
|
|
4740
4783
|
</div>
|
|
4741
4784
|
`;
|
|
4742
4785
|
}
|
|
4743
|
-
if (this.otpVerified) {
|
|
4786
|
+
if (this.state.otpVerified) {
|
|
4744
4787
|
return `
|
|
4745
4788
|
<div class="medos-appointment-section">
|
|
4746
4789
|
<div class="medos-appointment-verified">✓ Phone verified successfully</div>
|
|
@@ -4754,61 +4797,69 @@
|
|
|
4754
4797
|
return `
|
|
4755
4798
|
<div class="medos-appointment-section">
|
|
4756
4799
|
<label class="medos-appointment-label">Enter OTP</label>
|
|
4757
|
-
<input type="text" class="medos-appointment-input" id="medos-otp" placeholder="Enter 6-digit OTP" value="${this.escapeHtml(this.otpCode)}" maxlength="6" />
|
|
4758
|
-
<div class="medos-appointment-otp-info">OTP sent to ${this.escapeHtml(this.countryCode)} ${this.escapeHtml(this.patientPhone)}</div>
|
|
4800
|
+
<input type="text" class="medos-appointment-input" id="medos-otp" placeholder="Enter 6-digit OTP" value="${this.escapeHtml(this.state.otpCode)}" maxlength="6" />
|
|
4801
|
+
<div class="medos-appointment-otp-info">OTP sent to ${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</div>
|
|
4759
4802
|
<div class="medos-appointment-actions">
|
|
4760
4803
|
<button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-change-number">Change Number</button>
|
|
4761
|
-
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-verify-otp" ${this.otpCode.length !== 6 || this.
|
|
4804
|
+
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-verify-otp" ${this.state.otpCode.length !== 6 || this.state.otpVerifying
|
|
4805
|
+
? "disabled"
|
|
4806
|
+
: ""} style="opacity: ${this.state.otpCode.length === 6 && !this.state.otpVerifying ? 1 : 0.6}">${this.state.otpVerifying ? "Verifying..." : "Verify OTP"}</button>
|
|
4762
4807
|
</div>
|
|
4763
4808
|
</div>
|
|
4764
4809
|
`;
|
|
4765
4810
|
}
|
|
4766
4811
|
renderStep4() {
|
|
4767
|
-
const canSubmit = this.patientName &&
|
|
4812
|
+
const canSubmit = this.state.patientName &&
|
|
4813
|
+
this.state.patientAddress &&
|
|
4814
|
+
this.state.patientCity &&
|
|
4815
|
+
this.state.patientState &&
|
|
4816
|
+
this.state.patientCountry &&
|
|
4817
|
+
this.state.patientZipcode &&
|
|
4818
|
+
this.state.otpVerified;
|
|
4768
4819
|
return `
|
|
4769
4820
|
<div class="medos-appointment-section">
|
|
4770
4821
|
<label class="medos-appointment-label">Patient Name</label>
|
|
4771
|
-
<input type="text" class="medos-appointment-input" id="medos-patient-name" placeholder="Full name" value="${this.escapeHtml(this.patientName)}" />
|
|
4822
|
+
<input type="text" class="medos-appointment-input" id="medos-patient-name" placeholder="Full name" value="${this.escapeHtml(this.state.patientName)}" />
|
|
4772
4823
|
<label class="medos-appointment-label" style="margin-top: 12px">Age</label>
|
|
4773
|
-
<input type="number" class="medos-appointment-input" id="medos-patient-age" placeholder="Age" value="${this.escapeHtml(this.patientAge)}" />
|
|
4824
|
+
<input type="number" class="medos-appointment-input" id="medos-patient-age" placeholder="Age" value="${this.escapeHtml(this.state.patientAge)}" />
|
|
4774
4825
|
<label class="medos-appointment-label" style="margin-top: 12px">Email (Optional)</label>
|
|
4775
|
-
<input type="email" class="medos-appointment-input" id="medos-patient-email" placeholder="patient@example.com" value="${this.escapeHtml(this.patientEmail)}" />
|
|
4826
|
+
<input type="email" class="medos-appointment-input" id="medos-patient-email" placeholder="patient@example.com" value="${this.escapeHtml(this.state.patientEmail)}" />
|
|
4776
4827
|
<label class="medos-appointment-label" style="margin-top: 12px">Gender (Optional)</label>
|
|
4777
4828
|
<select class="medos-appointment-select" id="medos-patient-gender">
|
|
4778
4829
|
<option value="">-- Select Gender --</option>
|
|
4779
|
-
<option value="MALE" ${this.patientGender === "MALE" ? "selected" : ""}>Male</option>
|
|
4780
|
-
<option value="FEMALE" ${this.patientGender === "FEMALE" ? "selected" : ""}>Female</option>
|
|
4781
|
-
<option value="OTHER" ${this.patientGender === "OTHER" ? "selected" : ""}>Other</option>
|
|
4830
|
+
<option value="MALE" ${this.state.patientGender === "MALE" ? "selected" : ""}>Male</option>
|
|
4831
|
+
<option value="FEMALE" ${this.state.patientGender === "FEMALE" ? "selected" : ""}>Female</option>
|
|
4832
|
+
<option value="OTHER" ${this.state.patientGender === "OTHER" ? "selected" : ""}>Other</option>
|
|
4782
4833
|
</select>
|
|
4783
4834
|
<label class="medos-appointment-label" style="margin-top: 12px">Address Line 1 *</label>
|
|
4784
|
-
<input type="text" class="medos-appointment-input" id="medos-patient-address" placeholder="Street address, building name, etc." value="${this.escapeHtml(this.patientAddress)}" />
|
|
4835
|
+
<input type="text" class="medos-appointment-input" id="medos-patient-address" placeholder="Street address, building name, etc." value="${this.escapeHtml(this.state.patientAddress)}" />
|
|
4785
4836
|
<div class="medos-appointment-form-grid">
|
|
4786
4837
|
<div>
|
|
4787
4838
|
<label class="medos-appointment-label">City *</label>
|
|
4788
|
-
<input type="text" class="medos-appointment-input" id="medos-patient-city" placeholder="City" value="${this.escapeHtml(this.patientCity)}" />
|
|
4839
|
+
<input type="text" class="medos-appointment-input" id="medos-patient-city" placeholder="City" value="${this.escapeHtml(this.state.patientCity)}" />
|
|
4789
4840
|
</div>
|
|
4790
4841
|
<div>
|
|
4791
4842
|
<label class="medos-appointment-label">State *</label>
|
|
4792
|
-
<input type="text" class="medos-appointment-input" id="medos-patient-state" placeholder="State" value="${this.escapeHtml(this.patientState)}" />
|
|
4843
|
+
<input type="text" class="medos-appointment-input" id="medos-patient-state" placeholder="State" value="${this.escapeHtml(this.state.patientState)}" />
|
|
4793
4844
|
</div>
|
|
4794
4845
|
</div>
|
|
4795
4846
|
<div class="medos-appointment-form-grid">
|
|
4796
4847
|
<div>
|
|
4797
4848
|
<label class="medos-appointment-label">Country *</label>
|
|
4798
|
-
<input type="text" class="medos-appointment-input" id="medos-patient-country" placeholder="Country" value="${this.escapeHtml(this.patientCountry)}" />
|
|
4849
|
+
<input type="text" class="medos-appointment-input" id="medos-patient-country" placeholder="Country" value="${this.escapeHtml(this.state.patientCountry)}" />
|
|
4799
4850
|
</div>
|
|
4800
4851
|
<div>
|
|
4801
4852
|
<label class="medos-appointment-label">Zipcode *</label>
|
|
4802
|
-
<input type="text" class="medos-appointment-input" id="medos-patient-zipcode" placeholder="Zipcode" value="${this.escapeHtml(this.patientZipcode)}" />
|
|
4853
|
+
<input type="text" class="medos-appointment-input" id="medos-patient-zipcode" placeholder="Zipcode" value="${this.escapeHtml(this.state.patientZipcode)}" />
|
|
4803
4854
|
</div>
|
|
4804
4855
|
</div>
|
|
4805
4856
|
<label class="medos-appointment-label" style="margin-top: 12px">Landmark (Optional)</label>
|
|
4806
|
-
<input type="text" class="medos-appointment-input" id="medos-patient-landmark" placeholder="Nearby landmark" value="${this.escapeHtml(this.patientLandmark)}" />
|
|
4857
|
+
<input type="text" class="medos-appointment-input" id="medos-patient-landmark" placeholder="Nearby landmark" value="${this.escapeHtml(this.state.patientLandmark)}" />
|
|
4807
4858
|
<label class="medos-appointment-label" style="margin-top: 12px">Problem Facing</label>
|
|
4808
|
-
<textarea class="medos-appointment-textarea" id="medos-problem-facing" placeholder="Describe the problem you're facing">${this.escapeHtml(this.
|
|
4859
|
+
<textarea class="medos-appointment-textarea" id="medos-problem-facing" placeholder="Describe the problem you're facing">${this.escapeHtml(this.state.patientName)}</textarea>
|
|
4809
4860
|
<div class="medos-appointment-actions">
|
|
4810
4861
|
<button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-back">Back</button>
|
|
4811
|
-
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-submit" ${!canSubmit || this.loading ? "disabled" : ""} style="opacity: ${canSubmit && !this.loading ? 1 : 0.6}">${this.loading ? "Booking..." : "Book Appointment"}</button>
|
|
4862
|
+
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-submit" ${!canSubmit || this.state.loading ? "disabled" : ""} style="opacity: ${canSubmit && !this.state.loading ? 1 : 0.6}">${this.state.loading ? "Booking..." : "Book Appointment"}</button>
|
|
4812
4863
|
</div>
|
|
4813
4864
|
</div>
|
|
4814
4865
|
`;
|
|
@@ -4819,7 +4870,7 @@
|
|
|
4819
4870
|
<div class="medos-appointment-success-card">
|
|
4820
4871
|
<div class="medos-appointment-success-icon">✓</div>
|
|
4821
4872
|
<div class="medos-appointment-success-title">Appointment Confirmed</div>
|
|
4822
|
-
<div class="medos-appointment-small-muted">Thank you, ${this.escapeHtml(this.patientName || "Patient")}. Your appointment is confirmed.</div>
|
|
4873
|
+
<div class="medos-appointment-small-muted">Thank you, ${this.escapeHtml(this.state.patientName || "Patient")}. Your appointment is confirmed.</div>
|
|
4823
4874
|
</div>
|
|
4824
4875
|
<div style="margin-top: 14px; display: flex; justify-content: center">
|
|
4825
4876
|
<button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-book-another" style="width: 160px">Book Another</button>
|
|
@@ -4832,14 +4883,14 @@
|
|
|
4832
4883
|
if (addressSelect) {
|
|
4833
4884
|
addressSelect.addEventListener("change", (e) => {
|
|
4834
4885
|
const target = e.target;
|
|
4835
|
-
this.handleAddressChange(target.value || null);
|
|
4886
|
+
this.handleAddressChange(Number(target.value) || null);
|
|
4836
4887
|
});
|
|
4837
4888
|
}
|
|
4838
4889
|
const doctorSelect = this.container.querySelector("#medos-doctor-select");
|
|
4839
4890
|
if (doctorSelect) {
|
|
4840
4891
|
doctorSelect.addEventListener("change", (e) => {
|
|
4841
4892
|
const target = e.target;
|
|
4842
|
-
this.selectedDoctor = target.value || null;
|
|
4893
|
+
this.state.selectedDoctor = Number(target.value) || null;
|
|
4843
4894
|
this.render();
|
|
4844
4895
|
});
|
|
4845
4896
|
}
|
|
@@ -4847,18 +4898,22 @@
|
|
|
4847
4898
|
if (dateInput) {
|
|
4848
4899
|
dateInput.addEventListener("change", (e) => {
|
|
4849
4900
|
const target = e.target;
|
|
4850
|
-
this.
|
|
4901
|
+
this.state.selectedDate = new Date(target.value);
|
|
4851
4902
|
this.render();
|
|
4852
4903
|
});
|
|
4853
4904
|
}
|
|
4854
4905
|
const slotCards = this.container.querySelectorAll(".medos-appointment-slot-card");
|
|
4855
|
-
slotCards.forEach(card => {
|
|
4906
|
+
slotCards.forEach((card) => {
|
|
4856
4907
|
card.addEventListener("click", () => {
|
|
4857
4908
|
const slotId = card.getAttribute("data-slot-id");
|
|
4858
4909
|
const slotStart = card.getAttribute("data-slot-start");
|
|
4859
4910
|
const slotEnd = card.getAttribute("data-slot-end");
|
|
4860
4911
|
if (slotStart && slotEnd) {
|
|
4861
|
-
this.selectedSlot = {
|
|
4912
|
+
this.state.selectedSlot = {
|
|
4913
|
+
start: slotStart,
|
|
4914
|
+
end: slotEnd,
|
|
4915
|
+
id: slotId || undefined,
|
|
4916
|
+
};
|
|
4862
4917
|
this.render();
|
|
4863
4918
|
}
|
|
4864
4919
|
});
|
|
@@ -4872,7 +4927,7 @@
|
|
|
4872
4927
|
value = "+" + value;
|
|
4873
4928
|
}
|
|
4874
4929
|
value = value.replace(/[^\d+]/g, "");
|
|
4875
|
-
this.countryCode = value;
|
|
4930
|
+
this.state.countryCode = value;
|
|
4876
4931
|
target.value = value;
|
|
4877
4932
|
this.render();
|
|
4878
4933
|
});
|
|
@@ -4881,8 +4936,8 @@
|
|
|
4881
4936
|
if (phoneInput) {
|
|
4882
4937
|
phoneInput.addEventListener("input", (e) => {
|
|
4883
4938
|
const target = e.target;
|
|
4884
|
-
this.patientPhone = target.value.replace(/\D/g, "");
|
|
4885
|
-
target.value = this.patientPhone;
|
|
4939
|
+
this.state.patientPhone = target.value.replace(/\D/g, "");
|
|
4940
|
+
target.value = this.state.patientPhone;
|
|
4886
4941
|
this.render();
|
|
4887
4942
|
});
|
|
4888
4943
|
}
|
|
@@ -4890,7 +4945,7 @@
|
|
|
4890
4945
|
if (otpInput) {
|
|
4891
4946
|
otpInput.addEventListener("input", (e) => {
|
|
4892
4947
|
const target = e.target;
|
|
4893
|
-
this.otpCode = target.value;
|
|
4948
|
+
this.state.otpCode = target.value;
|
|
4894
4949
|
this.render();
|
|
4895
4950
|
});
|
|
4896
4951
|
}
|
|
@@ -4898,77 +4953,70 @@
|
|
|
4898
4953
|
if (patientNameInput) {
|
|
4899
4954
|
patientNameInput.addEventListener("input", (e) => {
|
|
4900
4955
|
const target = e.target;
|
|
4901
|
-
this.patientName = target.value;
|
|
4956
|
+
this.state.patientName = target.value;
|
|
4902
4957
|
});
|
|
4903
4958
|
}
|
|
4904
4959
|
const patientAgeInput = this.container.querySelector("#medos-patient-age");
|
|
4905
4960
|
if (patientAgeInput) {
|
|
4906
4961
|
patientAgeInput.addEventListener("input", (e) => {
|
|
4907
4962
|
const target = e.target;
|
|
4908
|
-
this.patientAge = target.value;
|
|
4963
|
+
this.state.patientAge = target.value;
|
|
4909
4964
|
});
|
|
4910
4965
|
}
|
|
4911
4966
|
const patientEmailInput = this.container.querySelector("#medos-patient-email");
|
|
4912
4967
|
if (patientEmailInput) {
|
|
4913
4968
|
patientEmailInput.addEventListener("input", (e) => {
|
|
4914
4969
|
const target = e.target;
|
|
4915
|
-
this.patientEmail = target.value;
|
|
4970
|
+
this.state.patientEmail = target.value;
|
|
4916
4971
|
});
|
|
4917
4972
|
}
|
|
4918
4973
|
const patientGenderSelect = this.container.querySelector("#medos-patient-gender");
|
|
4919
4974
|
if (patientGenderSelect) {
|
|
4920
4975
|
patientGenderSelect.addEventListener("change", (e) => {
|
|
4921
4976
|
const target = e.target;
|
|
4922
|
-
this.patientGender = target.value;
|
|
4977
|
+
this.state.patientGender = target.value;
|
|
4923
4978
|
});
|
|
4924
4979
|
}
|
|
4925
4980
|
const patientAddressInput = this.container.querySelector("#medos-patient-address");
|
|
4926
4981
|
if (patientAddressInput) {
|
|
4927
4982
|
patientAddressInput.addEventListener("input", (e) => {
|
|
4928
4983
|
const target = e.target;
|
|
4929
|
-
this.patientAddress = target.value;
|
|
4984
|
+
this.state.patientAddress = target.value;
|
|
4930
4985
|
});
|
|
4931
4986
|
}
|
|
4932
4987
|
const patientCityInput = this.container.querySelector("#medos-patient-city");
|
|
4933
4988
|
if (patientCityInput) {
|
|
4934
4989
|
patientCityInput.addEventListener("input", (e) => {
|
|
4935
4990
|
const target = e.target;
|
|
4936
|
-
this.patientCity = target.value;
|
|
4991
|
+
this.state.patientCity = target.value;
|
|
4937
4992
|
});
|
|
4938
4993
|
}
|
|
4939
4994
|
const patientStateInput = this.container.querySelector("#medos-patient-state");
|
|
4940
4995
|
if (patientStateInput) {
|
|
4941
4996
|
patientStateInput.addEventListener("input", (e) => {
|
|
4942
4997
|
const target = e.target;
|
|
4943
|
-
this.patientState = target.value;
|
|
4998
|
+
this.state.patientState = target.value;
|
|
4944
4999
|
});
|
|
4945
5000
|
}
|
|
4946
5001
|
const patientCountryInput = this.container.querySelector("#medos-patient-country");
|
|
4947
5002
|
if (patientCountryInput) {
|
|
4948
5003
|
patientCountryInput.addEventListener("input", (e) => {
|
|
4949
5004
|
const target = e.target;
|
|
4950
|
-
this.patientCountry = target.value;
|
|
5005
|
+
this.state.patientCountry = target.value;
|
|
4951
5006
|
});
|
|
4952
5007
|
}
|
|
4953
5008
|
const patientZipcodeInput = this.container.querySelector("#medos-patient-zipcode");
|
|
4954
5009
|
if (patientZipcodeInput) {
|
|
4955
5010
|
patientZipcodeInput.addEventListener("input", (e) => {
|
|
4956
5011
|
const target = e.target;
|
|
4957
|
-
this.patientZipcode = target.value;
|
|
5012
|
+
this.state.patientZipcode = target.value;
|
|
4958
5013
|
});
|
|
4959
5014
|
}
|
|
4960
5015
|
const patientLandmarkInput = this.container.querySelector("#medos-patient-landmark");
|
|
4961
5016
|
if (patientLandmarkInput) {
|
|
4962
5017
|
patientLandmarkInput.addEventListener("input", (e) => {
|
|
4963
5018
|
const target = e.target;
|
|
4964
|
-
this.patientLandmark = target.value;
|
|
4965
|
-
});
|
|
4966
|
-
}
|
|
4967
|
-
const problemFacingInput = this.container.querySelector("#medos-problem-facing");
|
|
4968
|
-
if (problemFacingInput) {
|
|
4969
|
-
problemFacingInput.addEventListener("input", (e) => {
|
|
4970
|
-
const target = e.target;
|
|
4971
|
-
this.problemFacing = target.value;
|
|
5019
|
+
this.state.patientLandmark = target.value;
|
|
4972
5020
|
});
|
|
4973
5021
|
}
|
|
4974
5022
|
const nextBtn = this.container.querySelector("#medos-btn-next");
|
|
@@ -4990,9 +5038,7 @@
|
|
|
4990
5038
|
const changeNumberBtn = this.container.querySelector("#medos-btn-change-number");
|
|
4991
5039
|
if (changeNumberBtn) {
|
|
4992
5040
|
changeNumberBtn.addEventListener("click", () => {
|
|
4993
|
-
this.otpSent
|
|
4994
|
-
this.otpCode = "";
|
|
4995
|
-
this.otpVerified = false;
|
|
5041
|
+
this.setState({ otpSent: false, otpCode: "", otpVerified: false });
|
|
4996
5042
|
this.render();
|
|
4997
5043
|
});
|
|
4998
5044
|
}
|
|
@@ -5023,14 +5069,493 @@
|
|
|
5023
5069
|
return new AppointmentCalendarWidget(container, options);
|
|
5024
5070
|
}
|
|
5025
5071
|
|
|
5072
|
+
const EnquiryService = {
|
|
5073
|
+
async submitEnquiry(payload) {
|
|
5074
|
+
try {
|
|
5075
|
+
const client = await MedosClient.ensureInitialized();
|
|
5076
|
+
const enquiryData = {
|
|
5077
|
+
patientName: payload.patientName,
|
|
5078
|
+
patientEmail: payload.patientEmail,
|
|
5079
|
+
countryCode: payload.countryCode,
|
|
5080
|
+
patientPhone: payload.patientPhone,
|
|
5081
|
+
inquirySubject: payload.inquirySubject,
|
|
5082
|
+
inquiryMessage: payload.inquiryMessage,
|
|
5083
|
+
preferredContactMethod: payload.preferredContactMethod,
|
|
5084
|
+
};
|
|
5085
|
+
const res = await client.post("/enquiries/submit", enquiryData, {
|
|
5086
|
+
headers: {
|
|
5087
|
+
"Content-Type": "application/json",
|
|
5088
|
+
},
|
|
5089
|
+
});
|
|
5090
|
+
return res.data;
|
|
5091
|
+
}
|
|
5092
|
+
catch (error) {
|
|
5093
|
+
if (error instanceof Error) {
|
|
5094
|
+
throw new Error(`Failed to submit enquiry: ${error.message}`);
|
|
5095
|
+
}
|
|
5096
|
+
throw new Error("Failed to submit enquiry: Unknown error");
|
|
5097
|
+
}
|
|
5098
|
+
},
|
|
5099
|
+
};
|
|
5100
|
+
|
|
5101
|
+
const validateName = (name) => {
|
|
5102
|
+
return name.trim().length > 0;
|
|
5103
|
+
};
|
|
5104
|
+
const validateEmail = (email) => {
|
|
5105
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
5106
|
+
return emailRegex.test(email);
|
|
5107
|
+
};
|
|
5108
|
+
const validatePhoneNumber = (phone) => {
|
|
5109
|
+
const cleaned = phone.replace(/\D/g, "");
|
|
5110
|
+
return cleaned.length >= 7 && cleaned.length <= 15;
|
|
5111
|
+
};
|
|
5112
|
+
const validateSubject = (subject) => {
|
|
5113
|
+
return subject.trim().length > 0;
|
|
5114
|
+
};
|
|
5115
|
+
const validateMessage = (message) => {
|
|
5116
|
+
const trimmed = message.trim();
|
|
5117
|
+
return trimmed.length > 0 && trimmed.length <= 1000;
|
|
5118
|
+
};
|
|
5119
|
+
const validateCountryCode = (code) => {
|
|
5120
|
+
return /^\+[1-9]\d{0,3}$/.test(code);
|
|
5121
|
+
};
|
|
5122
|
+
|
|
5123
|
+
class EnquiryFormWidget {
|
|
5124
|
+
constructor(container, options) {
|
|
5125
|
+
this.mounted = true;
|
|
5126
|
+
if (typeof container === "string") {
|
|
5127
|
+
const el = document.getElementById(container);
|
|
5128
|
+
if (!el) {
|
|
5129
|
+
throw new Error(`Container element with id "${container}" not found`);
|
|
5130
|
+
}
|
|
5131
|
+
this.container = el;
|
|
5132
|
+
}
|
|
5133
|
+
else {
|
|
5134
|
+
this.container = container;
|
|
5135
|
+
}
|
|
5136
|
+
this.options = options;
|
|
5137
|
+
this.state = {
|
|
5138
|
+
step: 0,
|
|
5139
|
+
loading: false,
|
|
5140
|
+
error: null,
|
|
5141
|
+
patientName: "",
|
|
5142
|
+
patientEmail: "",
|
|
5143
|
+
countryCode: "+91",
|
|
5144
|
+
patientPhone: "",
|
|
5145
|
+
inquirySubject: "",
|
|
5146
|
+
inquiryMessage: "",
|
|
5147
|
+
preferredContactMethod: "EMAIL",
|
|
5148
|
+
submitted: false,
|
|
5149
|
+
};
|
|
5150
|
+
this.init();
|
|
5151
|
+
}
|
|
5152
|
+
async init() {
|
|
5153
|
+
if (this.options.apiKey) {
|
|
5154
|
+
await MedosClient.init({
|
|
5155
|
+
apiKey: this.options.apiKey,
|
|
5156
|
+
});
|
|
5157
|
+
}
|
|
5158
|
+
else if (this.options.sessionToken) {
|
|
5159
|
+
await MedosClient.initWithSession({
|
|
5160
|
+
sessionToken: this.options.sessionToken,
|
|
5161
|
+
});
|
|
5162
|
+
}
|
|
5163
|
+
else {
|
|
5164
|
+
throw new Error("Either apiKey or sessionToken must be provided");
|
|
5165
|
+
}
|
|
5166
|
+
this.render();
|
|
5167
|
+
}
|
|
5168
|
+
validateContactStep() {
|
|
5169
|
+
this.setState({ error: null });
|
|
5170
|
+
if (!validateName(this.state.patientName)) {
|
|
5171
|
+
this.setState({ error: "Please enter a valid name." });
|
|
5172
|
+
return false;
|
|
5173
|
+
}
|
|
5174
|
+
if (!validateEmail(this.state.patientEmail)) {
|
|
5175
|
+
this.setState({ error: "Please enter a valid email address." });
|
|
5176
|
+
return false;
|
|
5177
|
+
}
|
|
5178
|
+
if (!validateCountryCode(this.state.countryCode)) {
|
|
5179
|
+
this.setState({
|
|
5180
|
+
error: "Please enter a valid country code (e.g., +91, +1).",
|
|
5181
|
+
});
|
|
5182
|
+
return false;
|
|
5183
|
+
}
|
|
5184
|
+
if (!validatePhoneNumber(this.state.patientPhone)) {
|
|
5185
|
+
this.setState({
|
|
5186
|
+
error: "Please enter a valid phone number (7-15 digits).",
|
|
5187
|
+
});
|
|
5188
|
+
return false;
|
|
5189
|
+
}
|
|
5190
|
+
return true;
|
|
5191
|
+
}
|
|
5192
|
+
validateInquiryStep() {
|
|
5193
|
+
this.setState({ error: null });
|
|
5194
|
+
if (!validateSubject(this.state.inquirySubject)) {
|
|
5195
|
+
this.setState({ error: "Please enter a valid subject." });
|
|
5196
|
+
return false;
|
|
5197
|
+
}
|
|
5198
|
+
if (!validateMessage(this.state.inquiryMessage)) {
|
|
5199
|
+
this.setState({
|
|
5200
|
+
error: "Please enter a valid message (max 1000 characters).",
|
|
5201
|
+
});
|
|
5202
|
+
return false;
|
|
5203
|
+
}
|
|
5204
|
+
return true;
|
|
5205
|
+
}
|
|
5206
|
+
goToNext() {
|
|
5207
|
+
if (this.state.step === 0) {
|
|
5208
|
+
if (!this.validateContactStep()) {
|
|
5209
|
+
this.render();
|
|
5210
|
+
return;
|
|
5211
|
+
}
|
|
5212
|
+
}
|
|
5213
|
+
else if (this.state.step === 1) {
|
|
5214
|
+
if (!this.validateInquiryStep()) {
|
|
5215
|
+
this.render();
|
|
5216
|
+
return;
|
|
5217
|
+
}
|
|
5218
|
+
}
|
|
5219
|
+
this.state.step = Math.min(3, this.state.step + 1);
|
|
5220
|
+
this.render();
|
|
5221
|
+
}
|
|
5222
|
+
goBack() {
|
|
5223
|
+
this.state.step = Math.max(0, this.state.step - 1);
|
|
5224
|
+
this.render();
|
|
5225
|
+
}
|
|
5226
|
+
async submitEnquiry() {
|
|
5227
|
+
this.setState({ error: null });
|
|
5228
|
+
if (!this.validateContactStep() || !this.validateInquiryStep()) {
|
|
5229
|
+
this.render();
|
|
5230
|
+
return;
|
|
5231
|
+
}
|
|
5232
|
+
this.setState({ loading: true });
|
|
5233
|
+
this.render();
|
|
5234
|
+
try {
|
|
5235
|
+
const payload = {
|
|
5236
|
+
patientName: this.state.patientName,
|
|
5237
|
+
patientEmail: this.state.patientEmail,
|
|
5238
|
+
countryCode: this.state.countryCode,
|
|
5239
|
+
patientPhone: this.state.patientPhone,
|
|
5240
|
+
inquirySubject: this.state.inquirySubject,
|
|
5241
|
+
inquiryMessage: this.state.inquiryMessage,
|
|
5242
|
+
preferredContactMethod: this.state.preferredContactMethod,
|
|
5243
|
+
};
|
|
5244
|
+
await EnquiryService.submitEnquiry(payload);
|
|
5245
|
+
this.state.step = 3;
|
|
5246
|
+
this.options.onSuccess?.(payload);
|
|
5247
|
+
}
|
|
5248
|
+
catch (e) {
|
|
5249
|
+
const msg = e.message || "Failed to submit enquiry";
|
|
5250
|
+
this.setState({ error: msg });
|
|
5251
|
+
this.options.onError?.(e);
|
|
5252
|
+
}
|
|
5253
|
+
finally {
|
|
5254
|
+
this.setState({ loading: false });
|
|
5255
|
+
this.render();
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
resetForm() {
|
|
5259
|
+
this.state = {
|
|
5260
|
+
step: 0,
|
|
5261
|
+
loading: false,
|
|
5262
|
+
error: null,
|
|
5263
|
+
patientName: "",
|
|
5264
|
+
patientEmail: "",
|
|
5265
|
+
countryCode: "+91",
|
|
5266
|
+
patientPhone: "",
|
|
5267
|
+
inquirySubject: "",
|
|
5268
|
+
inquiryMessage: "",
|
|
5269
|
+
preferredContactMethod: "EMAIL",
|
|
5270
|
+
submitted: false,
|
|
5271
|
+
};
|
|
5272
|
+
this.render();
|
|
5273
|
+
}
|
|
5274
|
+
setState(updates) {
|
|
5275
|
+
this.state = { ...this.state, ...updates };
|
|
5276
|
+
}
|
|
5277
|
+
render() {
|
|
5278
|
+
if (!this.mounted)
|
|
5279
|
+
return;
|
|
5280
|
+
this.container.innerHTML = `
|
|
5281
|
+
<div class="medos-enquiry-container">
|
|
5282
|
+
<div class="medos-enquiry-card">
|
|
5283
|
+
<div class="medos-enquiry-header">
|
|
5284
|
+
<h2 class="medos-enquiry-title">Submit Inquiry</h2>
|
|
5285
|
+
<p class="medos-enquiry-step-indicator">Step ${this.state.step + 1} of 4</p>
|
|
5286
|
+
</div>
|
|
5287
|
+
|
|
5288
|
+
${this.state.loading
|
|
5289
|
+
? '<div class="medos-enquiry-loading">Loading...</div>'
|
|
5290
|
+
: ""}
|
|
5291
|
+
${this.state.error
|
|
5292
|
+
? `<div class="medos-enquiry-error">${this.escapeHtml(this.state.error)}</div>`
|
|
5293
|
+
: ""}
|
|
5294
|
+
|
|
5295
|
+
${this.renderStep()}
|
|
5296
|
+
</div>
|
|
5297
|
+
</div>
|
|
5298
|
+
`;
|
|
5299
|
+
this.attachEventListeners();
|
|
5300
|
+
}
|
|
5301
|
+
renderStep() {
|
|
5302
|
+
switch (this.state.step) {
|
|
5303
|
+
case 0:
|
|
5304
|
+
return this.renderStep0();
|
|
5305
|
+
case 1:
|
|
5306
|
+
return this.renderStep1();
|
|
5307
|
+
case 2:
|
|
5308
|
+
return this.renderStep2();
|
|
5309
|
+
case 3:
|
|
5310
|
+
return this.renderStep3();
|
|
5311
|
+
default:
|
|
5312
|
+
return "";
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
5315
|
+
renderStep0() {
|
|
5316
|
+
return `
|
|
5317
|
+
<div class="medos-enquiry-section">
|
|
5318
|
+
<label class="medos-enquiry-label">Full Name *</label>
|
|
5319
|
+
<input
|
|
5320
|
+
type="text"
|
|
5321
|
+
class="medos-enquiry-input"
|
|
5322
|
+
id="medos-enquiry-name"
|
|
5323
|
+
placeholder="Enter your full name"
|
|
5324
|
+
value="${this.escapeHtml(this.state.patientName)}"
|
|
5325
|
+
/>
|
|
5326
|
+
|
|
5327
|
+
<label class="medos-enquiry-label" style="margin-top: 12px">Email Address *</label>
|
|
5328
|
+
<input
|
|
5329
|
+
type="email"
|
|
5330
|
+
class="medos-enquiry-input"
|
|
5331
|
+
id="medos-enquiry-email"
|
|
5332
|
+
placeholder="your.email@example.com"
|
|
5333
|
+
value="${this.escapeHtml(this.state.patientEmail)}"
|
|
5334
|
+
/>
|
|
5335
|
+
|
|
5336
|
+
<label class="medos-enquiry-label" style="margin-top: 12px">Country Code *</label>
|
|
5337
|
+
<input
|
|
5338
|
+
type="text"
|
|
5339
|
+
class="medos-enquiry-input"
|
|
5340
|
+
id="medos-enquiry-country-code"
|
|
5341
|
+
placeholder="+91"
|
|
5342
|
+
value="${this.escapeHtml(this.state.countryCode)}"
|
|
5343
|
+
/>
|
|
5344
|
+
|
|
5345
|
+
<label class="medos-enquiry-label" style="margin-top: 12px">Phone Number *</label>
|
|
5346
|
+
<input
|
|
5347
|
+
type="tel"
|
|
5348
|
+
class="medos-enquiry-input"
|
|
5349
|
+
id="medos-enquiry-phone"
|
|
5350
|
+
placeholder="9876543210"
|
|
5351
|
+
value="${this.escapeHtml(this.state.patientPhone)}"
|
|
5352
|
+
maxlength="15"
|
|
5353
|
+
/>
|
|
5354
|
+
|
|
5355
|
+
<div class="medos-enquiry-actions">
|
|
5356
|
+
<button class="medos-enquiry-btn medos-enquiry-btn-secondary" id="medos-enquiry-btn-cancel">Cancel</button>
|
|
5357
|
+
<button class="medos-enquiry-btn medos-enquiry-btn-primary" id="medos-enquiry-btn-next">Next</button>
|
|
5358
|
+
</div>
|
|
5359
|
+
</div>
|
|
5360
|
+
`;
|
|
5361
|
+
}
|
|
5362
|
+
renderStep1() {
|
|
5363
|
+
return `
|
|
5364
|
+
<div class="medos-enquiry-section">
|
|
5365
|
+
<label class="medos-enquiry-label">Subject *</label>
|
|
5366
|
+
<input
|
|
5367
|
+
type="text"
|
|
5368
|
+
class="medos-enquiry-input"
|
|
5369
|
+
id="medos-enquiry-subject"
|
|
5370
|
+
placeholder="What is your inquiry about?"
|
|
5371
|
+
value="${this.escapeHtml(this.state.inquirySubject)}"
|
|
5372
|
+
/>
|
|
5373
|
+
|
|
5374
|
+
<label class="medos-enquiry-label" style="margin-top: 12px">Message *</label>
|
|
5375
|
+
<textarea
|
|
5376
|
+
class="medos-enquiry-textarea"
|
|
5377
|
+
id="medos-enquiry-message"
|
|
5378
|
+
placeholder="Please describe your inquiry in detail (max 1000 characters)"
|
|
5379
|
+
maxlength="1000"
|
|
5380
|
+
>${this.escapeHtml(this.state.inquiryMessage)}</textarea>
|
|
5381
|
+
<div class="medos-enquiry-char-count">${this.state.inquiryMessage.length}/1000</div>
|
|
5382
|
+
|
|
5383
|
+
<div class="medos-enquiry-actions">
|
|
5384
|
+
<button class="medos-enquiry-btn medos-enquiry-btn-secondary" id="medos-enquiry-btn-back">Back</button>
|
|
5385
|
+
<button class="medos-enquiry-btn medos-enquiry-btn-primary" id="medos-enquiry-btn-next">Next</button>
|
|
5386
|
+
</div>
|
|
5387
|
+
</div>
|
|
5388
|
+
`;
|
|
5389
|
+
}
|
|
5390
|
+
renderStep2() {
|
|
5391
|
+
return `
|
|
5392
|
+
<div class="medos-enquiry-section">
|
|
5393
|
+
<label class="medos-enquiry-label">Preferred Contact Method *</label>
|
|
5394
|
+
<div class="medos-enquiry-radio-group">
|
|
5395
|
+
<label class="medos-enquiry-radio-label">
|
|
5396
|
+
<input
|
|
5397
|
+
type="radio"
|
|
5398
|
+
name="contact-method"
|
|
5399
|
+
value="PHONE"
|
|
5400
|
+
${this.state.preferredContactMethod === "PHONE" ? "checked" : ""}
|
|
5401
|
+
id="medos-enquiry-contact-phone"
|
|
5402
|
+
/>
|
|
5403
|
+
<span>Phone</span>
|
|
5404
|
+
</label>
|
|
5405
|
+
<label class="medos-enquiry-radio-label">
|
|
5406
|
+
<input
|
|
5407
|
+
type="radio"
|
|
5408
|
+
name="contact-method"
|
|
5409
|
+
value="EMAIL"
|
|
5410
|
+
${this.state.preferredContactMethod === "EMAIL" ? "checked" : ""}
|
|
5411
|
+
id="medos-enquiry-contact-email"
|
|
5412
|
+
/>
|
|
5413
|
+
<span>Email</span>
|
|
5414
|
+
</label>
|
|
5415
|
+
<label class="medos-enquiry-radio-label">
|
|
5416
|
+
<input
|
|
5417
|
+
type="radio"
|
|
5418
|
+
name="contact-method"
|
|
5419
|
+
value="BOTH"
|
|
5420
|
+
${this.state.preferredContactMethod === "BOTH" ? "checked" : ""}
|
|
5421
|
+
id="medos-enquiry-contact-both"
|
|
5422
|
+
/>
|
|
5423
|
+
<span>Both</span>
|
|
5424
|
+
</label>
|
|
5425
|
+
</div>
|
|
5426
|
+
|
|
5427
|
+
<div class="medos-enquiry-actions">
|
|
5428
|
+
<button class="medos-enquiry-btn medos-enquiry-btn-secondary" id="medos-enquiry-btn-back">Back</button>
|
|
5429
|
+
<button class="medos-enquiry-btn medos-enquiry-btn-primary" id="medos-enquiry-btn-submit" ${this.state.loading ? "disabled" : ""} style="opacity: ${this.state.loading ? 0.6 : 1}">${this.state.loading ? "Submitting..." : "Submit Inquiry"}</button>
|
|
5430
|
+
</div>
|
|
5431
|
+
</div>
|
|
5432
|
+
`;
|
|
5433
|
+
}
|
|
5434
|
+
renderStep3() {
|
|
5435
|
+
return `
|
|
5436
|
+
<div class="medos-enquiry-section" style="text-align: center">
|
|
5437
|
+
<div class="medos-enquiry-success-card">
|
|
5438
|
+
<div class="medos-enquiry-success-icon">✓</div>
|
|
5439
|
+
<div class="medos-enquiry-success-title">Inquiry Submitted Successfully</div>
|
|
5440
|
+
<div class="medos-enquiry-success-message">Thank you, ${this.escapeHtml(this.state.patientName || "Patient")}. We have received your inquiry and will get back to you soon.</div>
|
|
5441
|
+
</div>
|
|
5442
|
+
<div style="margin-top: 14px; display: flex; justify-content: center">
|
|
5443
|
+
<button class="medos-enquiry-btn medos-enquiry-btn-primary" id="medos-enquiry-btn-submit-another" style="width: 160px">Submit Another</button>
|
|
5444
|
+
</div>
|
|
5445
|
+
</div>
|
|
5446
|
+
`;
|
|
5447
|
+
}
|
|
5448
|
+
attachEventListeners() {
|
|
5449
|
+
const nameInput = this.container.querySelector("#medos-enquiry-name");
|
|
5450
|
+
if (nameInput) {
|
|
5451
|
+
nameInput.addEventListener("input", (e) => {
|
|
5452
|
+
const target = e.target;
|
|
5453
|
+
this.state.patientName = target.value;
|
|
5454
|
+
});
|
|
5455
|
+
}
|
|
5456
|
+
const emailInput = this.container.querySelector("#medos-enquiry-email");
|
|
5457
|
+
if (emailInput) {
|
|
5458
|
+
emailInput.addEventListener("input", (e) => {
|
|
5459
|
+
const target = e.target;
|
|
5460
|
+
this.state.patientEmail = target.value;
|
|
5461
|
+
});
|
|
5462
|
+
}
|
|
5463
|
+
const countryCodeInput = this.container.querySelector("#medos-enquiry-country-code");
|
|
5464
|
+
if (countryCodeInput) {
|
|
5465
|
+
countryCodeInput.addEventListener("input", (e) => {
|
|
5466
|
+
const target = e.target;
|
|
5467
|
+
let value = target.value;
|
|
5468
|
+
if (value && !value.startsWith("+")) {
|
|
5469
|
+
value = "+" + value;
|
|
5470
|
+
}
|
|
5471
|
+
value = value.replace(/[^\d+]/g, "");
|
|
5472
|
+
this.state.countryCode = value;
|
|
5473
|
+
target.value = value;
|
|
5474
|
+
});
|
|
5475
|
+
}
|
|
5476
|
+
const phoneInput = this.container.querySelector("#medos-enquiry-phone");
|
|
5477
|
+
if (phoneInput) {
|
|
5478
|
+
phoneInput.addEventListener("input", (e) => {
|
|
5479
|
+
const target = e.target;
|
|
5480
|
+
this.state.patientPhone = target.value.replace(/\D/g, "");
|
|
5481
|
+
target.value = this.state.patientPhone;
|
|
5482
|
+
});
|
|
5483
|
+
}
|
|
5484
|
+
const subjectInput = this.container.querySelector("#medos-enquiry-subject");
|
|
5485
|
+
if (subjectInput) {
|
|
5486
|
+
subjectInput.addEventListener("input", (e) => {
|
|
5487
|
+
const target = e.target;
|
|
5488
|
+
this.state.inquirySubject = target.value;
|
|
5489
|
+
});
|
|
5490
|
+
}
|
|
5491
|
+
const messageInput = this.container.querySelector("#medos-enquiry-message");
|
|
5492
|
+
if (messageInput) {
|
|
5493
|
+
messageInput.addEventListener("input", (e) => {
|
|
5494
|
+
const target = e.target;
|
|
5495
|
+
this.state.inquiryMessage = target.value;
|
|
5496
|
+
this.render();
|
|
5497
|
+
});
|
|
5498
|
+
}
|
|
5499
|
+
const contactMethodRadios = this.container.querySelectorAll('input[name="contact-method"]');
|
|
5500
|
+
contactMethodRadios.forEach((radio) => {
|
|
5501
|
+
radio.addEventListener("change", (e) => {
|
|
5502
|
+
const target = e.target;
|
|
5503
|
+
this.state.preferredContactMethod = target.value;
|
|
5504
|
+
});
|
|
5505
|
+
});
|
|
5506
|
+
const nextBtn = this.container.querySelector("#medos-enquiry-btn-next");
|
|
5507
|
+
if (nextBtn) {
|
|
5508
|
+
nextBtn.addEventListener("click", () => this.goToNext());
|
|
5509
|
+
}
|
|
5510
|
+
const backBtn = this.container.querySelector("#medos-enquiry-btn-back");
|
|
5511
|
+
if (backBtn) {
|
|
5512
|
+
backBtn.addEventListener("click", () => this.goBack());
|
|
5513
|
+
}
|
|
5514
|
+
const submitBtn = this.container.querySelector("#medos-enquiry-btn-submit");
|
|
5515
|
+
if (submitBtn) {
|
|
5516
|
+
submitBtn.addEventListener("click", () => this.submitEnquiry());
|
|
5517
|
+
}
|
|
5518
|
+
const cancelBtn = this.container.querySelector("#medos-enquiry-btn-cancel");
|
|
5519
|
+
if (cancelBtn) {
|
|
5520
|
+
cancelBtn.addEventListener("click", () => this.resetForm());
|
|
5521
|
+
}
|
|
5522
|
+
const submitAnotherBtn = this.container.querySelector("#medos-enquiry-btn-submit-another");
|
|
5523
|
+
if (submitAnotherBtn) {
|
|
5524
|
+
submitAnotherBtn.addEventListener("click", () => this.resetForm());
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5527
|
+
escapeHtml(text) {
|
|
5528
|
+
const div = document.createElement("div");
|
|
5529
|
+
div.textContent = text;
|
|
5530
|
+
return div.innerHTML;
|
|
5531
|
+
}
|
|
5532
|
+
destroy() {
|
|
5533
|
+
this.mounted = false;
|
|
5534
|
+
this.container.innerHTML = "";
|
|
5535
|
+
}
|
|
5536
|
+
}
|
|
5537
|
+
function initEnquiryForm(options) {
|
|
5538
|
+
const container = document.getElementById(options.containerId);
|
|
5539
|
+
if (!container) {
|
|
5540
|
+
throw new Error(`Container element with id "${options.containerId}" not found`);
|
|
5541
|
+
}
|
|
5542
|
+
return new EnquiryFormWidget(container, options);
|
|
5543
|
+
}
|
|
5544
|
+
|
|
5026
5545
|
if (typeof window !== "undefined") {
|
|
5027
5546
|
window.MedosAppointmentCalendar = {
|
|
5028
5547
|
init: initAppointmentCalendar,
|
|
5029
5548
|
Widget: AppointmentCalendarWidget,
|
|
5030
5549
|
};
|
|
5550
|
+
window.MedosEnquiryForm = {
|
|
5551
|
+
init: initEnquiryForm,
|
|
5552
|
+
Widget: EnquiryFormWidget,
|
|
5553
|
+
};
|
|
5031
5554
|
}
|
|
5032
5555
|
|
|
5033
5556
|
exports.AppointmentCalendarWidget = AppointmentCalendarWidget;
|
|
5557
|
+
exports.EnquiryFormWidget = EnquiryFormWidget;
|
|
5034
5558
|
exports.initAppointmentCalendar = initAppointmentCalendar;
|
|
5559
|
+
exports.initEnquiryForm = initEnquiryForm;
|
|
5035
5560
|
|
|
5036
5561
|
}));
|