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.
Files changed (167) hide show
  1. package/README.md +39 -0
  2. package/dist/client/MedosClient.d.ts +3 -5
  3. package/dist/client/MedosClient.js +4 -4
  4. package/dist/components/AppointmentCalender.d.ts +1 -4
  5. package/dist/components/AppointmentCalender.js +323 -530
  6. package/dist/components/AppointmentDateTimeModal.d.ts +14 -0
  7. package/dist/components/AppointmentDateTimeModal.js +220 -0
  8. package/dist/components/ConfigurableCard.d.ts +12 -0
  9. package/dist/components/ConfigurableCard.js +29 -0
  10. package/dist/components/ContactInformationStep.d.ts +13 -0
  11. package/dist/components/ContactInformationStep.js +14 -0
  12. package/dist/components/ContactPreferenceStep.d.ts +9 -0
  13. package/dist/components/ContactPreferenceStep.js +16 -0
  14. package/dist/components/DoctorSelectModal.d.ts +7 -0
  15. package/dist/components/DoctorSelectModal.js +93 -0
  16. package/dist/components/EnquiryForm.d.ts +7 -0
  17. package/dist/components/EnquiryForm.js +212 -0
  18. package/dist/components/Icons/Check.d.ts +6 -0
  19. package/dist/components/Icons/Check.js +2 -0
  20. package/dist/components/Icons/ChevronDownIcon.d.ts +4 -0
  21. package/dist/components/Icons/ChevronDownIcon.js +2 -0
  22. package/dist/components/Icons/ChevronLeft.d.ts +3 -0
  23. package/dist/components/Icons/ChevronLeft.js +3 -0
  24. package/dist/components/Icons/ChevronRight.d.ts +3 -0
  25. package/dist/components/Icons/ChevronRight.js +3 -0
  26. package/dist/components/Icons/ConfirmationCheck.d.ts +1 -0
  27. package/dist/components/Icons/ConfirmationCheck.js +9 -0
  28. package/dist/components/Icons/ConsultationType.d.ts +1 -0
  29. package/dist/components/Icons/ConsultationType.js +2 -0
  30. package/dist/components/Icons/Date&TimeIcon.d.ts +1 -0
  31. package/dist/components/Icons/Date&TimeIcon.js +2 -0
  32. package/dist/components/Icons/MapIcon.d.ts +1 -0
  33. package/dist/components/Icons/MapIcon.js +2 -0
  34. package/dist/components/Icons/PaymentMethodIcon.d.ts +1 -0
  35. package/dist/components/Icons/PaymentMethodIcon.js +2 -0
  36. package/dist/components/Icons/UserIcon.d.ts +1 -0
  37. package/dist/components/Icons/UserIcon.js +2 -0
  38. package/dist/components/InquiryDetailsStep.d.ts +10 -0
  39. package/dist/components/InquiryDetailsStep.js +15 -0
  40. package/dist/components/PatientDetailsStep.d.ts +3 -0
  41. package/dist/components/PatientDetailsStep.js +84 -0
  42. package/dist/components/PhoneVerificationStep.d.ts +3 -0
  43. package/dist/components/PhoneVerificationStep.js +49 -0
  44. package/dist/components/SuccessStep.d.ts +5 -0
  45. package/dist/components/SuccessStep.js +9 -0
  46. package/dist/components/custom-calendar.d.ts +5 -0
  47. package/dist/components/custom-calendar.js +171 -0
  48. package/dist/components/styles.d.ts +6 -0
  49. package/dist/components/styles.js +257 -0
  50. package/dist/components/theme-styles.d.ts +12 -0
  51. package/dist/components/theme-styles.js +319 -0
  52. package/dist/components/types.d.ts +181 -0
  53. package/dist/components/types.js +55 -0
  54. package/dist/components/ui/select.d.ts +10 -0
  55. package/dist/components/ui/select.js +21 -0
  56. package/dist/components/uiComponents/SelectDropdown.d.ts +41 -0
  57. package/dist/components/uiComponents/SelectDropdown.js +302 -0
  58. package/dist/components/utils.d.ts +5 -0
  59. package/dist/components/utils.js +15 -0
  60. package/dist/components/validation.d.ts +2 -0
  61. package/dist/components/validation.js +7 -0
  62. package/dist/context/TemplateContext.d.ts +12 -0
  63. package/dist/context/TemplateContext.js +19 -0
  64. package/dist/core/index.d.ts +4 -0
  65. package/dist/core/index.js +4 -0
  66. package/dist/core/theme/index.d.ts +3 -0
  67. package/dist/core/theme/index.js +3 -0
  68. package/dist/core/theme/themes.d.ts +8 -0
  69. package/dist/core/theme/themes.js +178 -0
  70. package/dist/core/theme/types.d.ts +106 -0
  71. package/dist/core/theme/types.js +1 -0
  72. package/dist/core/theme/utils.d.ts +8 -0
  73. package/dist/core/theme/utils.js +135 -0
  74. package/dist/enquiry-form/index.d.ts +4 -0
  75. package/dist/enquiry-form/index.js +4 -0
  76. package/dist/enquiry-form/provider.d.ts +3 -0
  77. package/dist/enquiry-form/provider.js +9 -0
  78. package/dist/enquiry-form/serialization.d.ts +4 -0
  79. package/dist/enquiry-form/serialization.js +57 -0
  80. package/dist/enquiry-form/types.d.ts +38 -0
  81. package/dist/enquiry-form/types.js +1 -0
  82. package/dist/enquiry-form/validation.d.ts +6 -0
  83. package/dist/enquiry-form/validation.js +21 -0
  84. package/dist/index.d.ts +9 -0
  85. package/dist/index.js +7 -0
  86. package/dist/lib/templateUtils.d.ts +3 -0
  87. package/dist/lib/templateUtils.js +28 -0
  88. package/dist/react/ThemeProvider.d.ts +18 -0
  89. package/dist/react/ThemeProvider.js +45 -0
  90. package/dist/react/hooks/useTheme.d.ts +1 -0
  91. package/dist/react/hooks/useTheme.js +1 -0
  92. package/dist/react/index.d.ts +5 -0
  93. package/dist/react/index.js +3 -0
  94. package/dist/services/AppointmentService.d.ts +4 -5
  95. package/dist/services/AppointmentService.js +12 -10
  96. package/dist/services/EnquiryService.d.ts +5 -0
  97. package/dist/services/EnquiryService.js +30 -0
  98. package/dist/templates/registry.d.ts +12 -0
  99. package/dist/templates/registry.js +58 -0
  100. package/dist/vanilla/AppointmentCalendarWidget.d.ts +2 -34
  101. package/dist/vanilla/AppointmentCalendarWidget.js +264 -275
  102. package/dist/vanilla/EnquiryFormWidget.d.ts +35 -0
  103. package/dist/vanilla/EnquiryFormWidget.js +425 -0
  104. package/dist/vanilla/client/MedosClient.d.ts +3 -5
  105. package/dist/vanilla/components/AppointmentCalender.d.ts +1 -4
  106. package/dist/vanilla/components/AppointmentDateTimeModal.d.ts +14 -0
  107. package/dist/vanilla/components/ConfigurableCard.d.ts +12 -0
  108. package/dist/vanilla/components/ContactInformationStep.d.ts +13 -0
  109. package/dist/vanilla/components/ContactPreferenceStep.d.ts +9 -0
  110. package/dist/vanilla/components/DoctorSelectModal.d.ts +7 -0
  111. package/dist/vanilla/components/EnquiryForm.d.ts +7 -0
  112. package/dist/vanilla/components/Icons/Check.d.ts +6 -0
  113. package/dist/vanilla/components/Icons/ChevronDownIcon.d.ts +4 -0
  114. package/dist/vanilla/components/Icons/ChevronLeft.d.ts +3 -0
  115. package/dist/vanilla/components/Icons/ChevronRight.d.ts +3 -0
  116. package/dist/vanilla/components/Icons/ConfirmationCheck.d.ts +1 -0
  117. package/dist/vanilla/components/Icons/ConsultationType.d.ts +1 -0
  118. package/dist/vanilla/components/Icons/Date&TimeIcon.d.ts +1 -0
  119. package/dist/vanilla/components/Icons/MapIcon.d.ts +1 -0
  120. package/dist/vanilla/components/Icons/PaymentMethodIcon.d.ts +1 -0
  121. package/dist/vanilla/components/Icons/UserIcon.d.ts +1 -0
  122. package/dist/vanilla/components/InquiryDetailsStep.d.ts +10 -0
  123. package/dist/vanilla/components/PatientDetailsStep.d.ts +3 -0
  124. package/dist/vanilla/components/PhoneVerificationStep.d.ts +3 -0
  125. package/dist/vanilla/components/SuccessStep.d.ts +5 -0
  126. package/dist/vanilla/components/custom-calendar.d.ts +5 -0
  127. package/dist/vanilla/components/styles.d.ts +6 -0
  128. package/dist/vanilla/components/theme-styles.d.ts +12 -0
  129. package/dist/vanilla/components/types.d.ts +181 -0
  130. package/dist/vanilla/components/ui/select.d.ts +10 -0
  131. package/dist/vanilla/components/uiComponents/SelectDropdown.d.ts +41 -0
  132. package/dist/vanilla/components/utils.d.ts +5 -0
  133. package/dist/vanilla/components/validation.d.ts +2 -0
  134. package/dist/vanilla/context/TemplateContext.d.ts +12 -0
  135. package/dist/vanilla/core/index.d.ts +4 -0
  136. package/dist/vanilla/core/theme/index.d.ts +3 -0
  137. package/dist/vanilla/core/theme/themes.d.ts +8 -0
  138. package/dist/vanilla/core/theme/types.d.ts +106 -0
  139. package/dist/vanilla/core/theme/utils.d.ts +8 -0
  140. package/dist/vanilla/enquiry-form/index.d.ts +4 -0
  141. package/dist/vanilla/enquiry-form/provider.d.ts +3 -0
  142. package/dist/vanilla/enquiry-form/serialization.d.ts +4 -0
  143. package/dist/vanilla/enquiry-form/types.d.ts +38 -0
  144. package/dist/vanilla/enquiry-form/validation.d.ts +6 -0
  145. package/dist/vanilla/enquiry-widget.js +4650 -0
  146. package/dist/vanilla/index.d.ts +9 -0
  147. package/dist/vanilla/index.js +3 -1
  148. package/dist/vanilla/lib/templateUtils.d.ts +3 -0
  149. package/dist/vanilla/react/ThemeProvider.d.ts +18 -0
  150. package/dist/vanilla/react/hooks/useTheme.d.ts +1 -0
  151. package/dist/vanilla/react/index.d.ts +5 -0
  152. package/dist/vanilla/services/AppointmentService.d.ts +4 -5
  153. package/dist/vanilla/services/EnquiryService.d.ts +5 -0
  154. package/dist/vanilla/templates/alternative.css +13 -0
  155. package/dist/vanilla/templates/default.css +13 -0
  156. package/dist/vanilla/templates/registry.d.ts +12 -0
  157. package/dist/vanilla/theme-injector.d.ts +6 -0
  158. package/dist/vanilla/theme-injector.js +44 -0
  159. package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +2 -34
  160. package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +35 -0
  161. package/dist/vanilla/vanilla/index.d.ts +3 -1
  162. package/dist/vanilla/vanilla/theme-injector.d.ts +6 -0
  163. package/dist/vanilla/vanilla/widget.d.ts +6 -1
  164. package/dist/vanilla/widget.css +173 -0
  165. package/dist/vanilla/widget.d.ts +6 -1
  166. package/dist/vanilla/widget.js +813 -288
  167. package/package.json +9 -4
@@ -3885,7 +3885,7 @@
3885
3885
  };
3886
3886
 
3887
3887
  class MedosClient {
3888
- static async init({ apiKey, baseURL = "https://api-dev.medapi.in/v1", }) {
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, baseURL);
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, baseURL = "https://api-dev.medapi.in/v1", }) {
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, baseURL);
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: String(d.id ?? ""),
4076
- name: `${d.firstName || ""} ${d.lastName || ""}`.trim() || "Doctor",
4077
- email: d.email,
4078
- gender: d.gender,
4079
- countryCode: d.countryCode,
4080
- phoneNumber: d.phoneNumber,
4081
- dob: d.dob,
4082
- platform: d.platform,
4083
- isKycCompleted: d.isKycCompleted,
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: String(addr.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.setLoading(true);
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 = String(a.id ?? idx);
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.setError("No doctors at this address. Please choose a different address.");
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.setError("No doctors available for the selected location(s).");
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.setError("No addresses or doctors available.");
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.setError(msg);
4336
+ this.setState({ error: msg });
4305
4337
  this.options.onError?.(e);
4306
4338
  }
4307
4339
  finally {
4308
- this.setLoading(false);
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.setLoading(true);
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.setError("No doctors at this address. Please select a different address.");
4369
+ this.setState({
4370
+ error: "No doctors at this address. Please select a different address.",
4371
+ });
4339
4372
  }
4340
4373
  else {
4341
- this.setError("No doctors available for the selected location(s).");
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.setError(e.message || "Failed to load doctors for address");
4381
+ this.setState({
4382
+ error: e.message || "Failed to load doctors for address",
4383
+ });
4347
4384
  }
4348
4385
  finally {
4349
- this.setLoading(false);
4386
+ this.setState({ loading: false });
4350
4387
  this.render();
4351
4388
  }
4352
4389
  }
4353
4390
  async loadSlots() {
4354
- if (!this.workspaceId || !this.selectedAddress || !this.selectedDoctor || !this.date) {
4355
- this.slots = [];
4356
- this.selectedSlot = null;
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.setLoading(true);
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, this.date);
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.setError(e.message || "Failed to load slots");
4407
+ this.setState({ error: e.message || "Failed to load slots" });
4368
4408
  }
4369
4409
  finally {
4370
- this.setLoading(false);
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.setError(null);
4392
- if (!this.countryCode) {
4393
- this.setError("Please enter country code.");
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 (!this.validateCountryCode(this.countryCode)) {
4397
- this.setError("Please enter a valid country code (e.g., +91, +1).");
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.setError("Please enter phone number.");
4435
+ if (!this.state.patientPhone) {
4436
+ this.setState({ error: "Please enter phone number." });
4402
4437
  return;
4403
4438
  }
4404
- if (!this.validatePhoneNumber(this.patientPhone)) {
4405
- this.setError("Please enter a valid phone number (7-15 digits).");
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 = true;
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 = true;
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.setError(msg);
4456
+ this.setState({ error: msg });
4421
4457
  this.options.onError?.(e);
4422
4458
  }
4423
4459
  finally {
4424
- this.otpSending = false;
4460
+ this.setState({ otpSending: false });
4425
4461
  this.render();
4426
4462
  }
4427
4463
  }
4428
4464
  async verifyOtp() {
4429
- this.setError(null);
4430
- if (!this.countryCode || !this.patientPhone || !this.otpCode) {
4431
- this.setError("Please enter all required fields.");
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.setError("Please enter a 6-digit OTP code.");
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 = true;
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 = true;
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.setError(msg);
4488
+ this.setState({ error: msg });
4452
4489
  this.options.onError?.(e);
4453
4490
  }
4454
4491
  finally {
4455
- this.otpVerifying = false;
4492
+ this.setState({ otpVerifying: false });
4456
4493
  this.render();
4457
4494
  }
4458
4495
  }
4459
4496
  async submitAppointment() {
4460
- this.setError(null);
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.setError("Please ensure all required fields are complete.");
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.setError("Please verify your phone number first.");
4512
+ if (!this.state.otpVerified) {
4513
+ this.setState({ error: "Please verify your phone number first." });
4475
4514
  return;
4476
4515
  }
4477
- this.setLoading(true);
4516
+ this.setState({ loading: true });
4478
4517
  this.render();
4479
4518
  try {
4480
- const nameParts = (this.patientName || "Patient").trim().split(/\s+/);
4481
- const firstName = nameParts[0] || "Patient";
4482
- const lastName = nameParts.slice(1).join(" ") || "";
4483
- const startDate = new Date(this.selectedSlot.start);
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.patientAge ? parseInt(this.patientAge, 10) : undefined,
4519
- gender: this.patientGender
4520
- ? this.patientGender.toUpperCase()
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.setError(msg);
4569
+ this.setState({ error: msg });
4531
4570
  this.options.onError?.(e);
4532
4571
  }
4533
4572
  finally {
4534
- this.setLoading(false);
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
- if (this.step === 1 && this.date) {
4549
- this.step = 2;
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.step = 0;
4572
- this.selectedSlot = null;
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
- setLoading(loading) {
4596
- this.loading = loading;
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 ? '<div class="medos-appointment-loading">Loading...</div>' : ""}
4619
- ${this.error ? `<div class="medos-appointment-error">${this.escapeHtml(this.error)}</div>` : ""}
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.map(a => `<option value="${this.escapeHtml(a.id)}" ${this.selectedAddress === a.id ? "selected" : ""}>${this.escapeHtml(a.label)}</option>`).join("")}
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 ? ` • ${this.escapeHtml(this.doctors[0].specialty)}` : ""}</div>`
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.map(d => `<option value="${this.escapeHtml(d.id)}" ${this.selectedDoctor === d.id ? "selected" : ""}>${this.escapeHtml(d.name)}${d.specialty ? ` (${this.escapeHtml(d.specialty)})` : ""}</option>`).join("")}
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(this.date)}" />
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" ${!this.date ? "disabled" : ""} style="opacity: ${this.date ? 1 : 0.6}">Next</button>
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.map(s => {
4705
- const start = new Date(s.start).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
4706
- const end = new Date(s.end).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
4707
- const selected = this.selectedSlot?.start === s.start && this.selectedSlot?.end === s.end;
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
- }).join("")}
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 && this.validateCountryCode(this.countryCode);
4725
- const phoneValid = this.patientPhone && this.validatePhoneNumber(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 ? '<div class="medos-appointment-validation-error">Please enter a valid country code (e.g., +91, +1)</div>' : ""}
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 ? '<div class="medos-appointment-validation-error">Phone number should be 7-15 digits</div>' : ""}
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.otpVerifying ? "disabled" : ""} style="opacity: ${this.otpCode.length === 6 && !this.otpVerifying ? 1 : 0.6}">${this.otpVerifying ? "Verifying..." : "Verify OTP"}</button>
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 && this.patientAddress && this.patientCity && this.patientState && this.patientCountry && this.patientZipcode && this.otpVerified;
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.problemFacing)}</textarea>
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.date = target.value;
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 = { start: slotStart, end: slotEnd, id: slotId || undefined };
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 = false;
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
  }));