medos-sdk 1.1.7 → 1.1.8

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 (27) hide show
  1. package/dist/components/SuccessStep.js +1 -1
  2. package/dist/vanilla/AppointmentCalendarWidget.d.ts +8 -0
  3. package/dist/vanilla/AppointmentCalendarWidget.js +463 -158
  4. package/dist/vanilla/EnquiryFormWidget.d.ts +2 -0
  5. package/dist/vanilla/EnquiryFormWidget.js +155 -100
  6. package/dist/vanilla/components/VanillaCalendar.d.ts +32 -0
  7. package/dist/vanilla/components/VanillaCalendar.js +366 -0
  8. package/dist/vanilla/components/VanillaIcons.d.ts +17 -0
  9. package/dist/vanilla/components/VanillaIcons.js +268 -0
  10. package/dist/vanilla/components/VanillaSelect.d.ts +46 -0
  11. package/dist/vanilla/components/VanillaSelect.js +523 -0
  12. package/dist/vanilla/components/index.d.ts +3 -0
  13. package/dist/vanilla/components/index.js +3 -0
  14. package/dist/vanilla/components/theme-injector.d.ts +1 -0
  15. package/dist/vanilla/components/theme-injector.js +447 -0
  16. package/dist/vanilla/enquiry-widget.js +1366 -100
  17. package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +8 -0
  18. package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +2 -0
  19. package/dist/vanilla/vanilla/components/VanillaCalendar.d.ts +32 -0
  20. package/dist/vanilla/vanilla/components/VanillaIcons.d.ts +17 -0
  21. package/dist/vanilla/vanilla/components/VanillaSelect.d.ts +46 -0
  22. package/dist/vanilla/vanilla/components/index.d.ts +3 -0
  23. package/dist/vanilla/vanilla/components/theme-injector.d.ts +1 -0
  24. package/dist/vanilla/vanilla/widget.d.ts +2 -0
  25. package/dist/vanilla/widget.d.ts +2 -0
  26. package/dist/vanilla/widget.js +2213 -257
  27. package/package.json +1 -1
@@ -4173,6 +4173,28 @@
4173
4173
  },
4174
4174
  };
4175
4175
 
4176
+ const COUNTRY_CODES = [
4177
+ { code: "+91", label: "🇮🇳 +91" },
4178
+ { code: "+1", label: "🇺🇸 +1" },
4179
+ { code: "+44", label: "🇬🇧 +44" },
4180
+ { code: "+86", label: "🇨🇳 +86" },
4181
+ { code: "+81", label: "🇯🇵 +81" },
4182
+ ];
4183
+ const GENDER_OPTIONS = [
4184
+ { value: "MALE", label: "Male" },
4185
+ { value: "FEMALE", label: "Female" },
4186
+ { value: "OTHER", label: "Other" },
4187
+ ];
4188
+ const BLOOD_GROUP_OPTIONS = [
4189
+ { value: "A+", label: "A+" },
4190
+ { value: "A-", label: "A-" },
4191
+ { value: "B+", label: "B+" },
4192
+ { value: "B-", label: "B-" },
4193
+ { value: "AB+", label: "AB+" },
4194
+ { value: "AB-", label: "AB-" },
4195
+ { value: "O+", label: "O+" },
4196
+ { value: "O-", label: "O-" },
4197
+ ];
4176
4198
  const INITIAL_STATE = {
4177
4199
  step: 0,
4178
4200
  loading: false,
@@ -4231,10 +4253,1596 @@
4231
4253
  };
4232
4254
  };
4233
4255
 
4256
+ const VanillaIcons = {
4257
+ chevronLeft: (size = 20, className = "") => `
4258
+ <svg
4259
+ xmlns="http://www.w3.org/2000/svg"
4260
+ width="${size}"
4261
+ height="${size}"
4262
+ viewBox="0 0 24 24"
4263
+ fill="none"
4264
+ stroke="currentColor"
4265
+ stroke-width="2"
4266
+ stroke-linecap="round"
4267
+ stroke-linejoin="round"
4268
+ class="medos-icon medos-icon-chevron-left ${className}"
4269
+ >
4270
+ <path d="m15 18-6-6 6-6" />
4271
+ </svg>
4272
+ `,
4273
+ chevronRight: (size = 20, className = "") => `
4274
+ <svg
4275
+ xmlns="http://www.w3.org/2000/svg"
4276
+ width="${size}"
4277
+ height="${size}"
4278
+ viewBox="0 0 24 24"
4279
+ fill="none"
4280
+ stroke="currentColor"
4281
+ stroke-width="2"
4282
+ stroke-linecap="round"
4283
+ stroke-linejoin="round"
4284
+ class="medos-icon medos-icon-chevron-right ${className}"
4285
+ >
4286
+ <path d="m9 18 6-6-6-6" />
4287
+ </svg>
4288
+ `,
4289
+ chevronDown: (size = 16, className = "") => `
4290
+ <svg
4291
+ xmlns="http://www.w3.org/2000/svg"
4292
+ width="${size}"
4293
+ height="${size}"
4294
+ viewBox="0 0 24 24"
4295
+ fill="none"
4296
+ stroke="currentColor"
4297
+ stroke-width="2"
4298
+ stroke-linecap="round"
4299
+ stroke-linejoin="round"
4300
+ class="medos-icon medos-icon-chevron-down ${className}"
4301
+ >
4302
+ <polyline points="6 9 12 15 18 9"></polyline>
4303
+ </svg>
4304
+ `,
4305
+ check: (size = 16, className = "") => `
4306
+ <svg
4307
+ xmlns="http://www.w3.org/2000/svg"
4308
+ width="${size}"
4309
+ height="${size}"
4310
+ viewBox="0 0 24 24"
4311
+ fill="none"
4312
+ stroke="currentColor"
4313
+ stroke-width="2"
4314
+ stroke-linecap="round"
4315
+ stroke-linejoin="round"
4316
+ class="medos-icon medos-icon-check ${className}"
4317
+ >
4318
+ <polyline points="20 6 9 17 4 12"></polyline>
4319
+ </svg>
4320
+ `,
4321
+ consultationType: (size = 18) => `
4322
+ <svg
4323
+ xmlns="http://www.w3.org/2000/svg"
4324
+ width="${size}"
4325
+ height="${Math.round((size * 20) / 18)}"
4326
+ viewBox="0 0 18 20"
4327
+ fill="none"
4328
+ class="medos-icon medos-icon-consultation"
4329
+ >
4330
+ <path
4331
+ d="M2 20C1.45 20 0.979167 19.8042 0.5875 19.4125C0.195833 19.0208 0 18.55 0 18V4C0 3.45 0.195833 2.97917 0.5875 2.5875C0.979167 2.19583 1.45 2 2 2H3V0H5V2H13V0H15V2H16C16.55 2 17.0208 2.19583 17.4125 2.5875C17.8042 2.97917 18 3.45 18 4V18C18 18.55 17.8042 19.0208 17.4125 19.4125C17.0208 19.8042 16.55 20 16 20H2ZM2 18H16V8H2V18ZM2 6H16V4H2V6ZM4 12V10H14V12H4ZM4 16V14H11V16H4Z"
4332
+ fill="currentColor"
4333
+ />
4334
+ </svg>
4335
+ `,
4336
+ dateTime: (size = 18) => `
4337
+ <svg
4338
+ xmlns="http://www.w3.org/2000/svg"
4339
+ width="${size}"
4340
+ height="${Math.round((size * 20) / 18)}"
4341
+ viewBox="0 0 18 20"
4342
+ fill="none"
4343
+ class="medos-icon medos-icon-datetime"
4344
+ >
4345
+ <path
4346
+ d="M2 20C1.45 20 0.979167 19.8042 0.5875 19.4125C0.195833 19.0208 0 18.55 0 18V4C0 3.45 0.195833 2.97917 0.5875 2.5875C0.979167 2.19583 1.45 2 2 2H3V0H5V2H13V0H15V2H16C16.55 2 17.0208 2.19583 17.4125 2.5875C17.8042 2.97917 18 3.45 18 4V18C18 18.55 17.8042 19.0208 17.4125 19.4125C17.0208 19.8042 16.55 20 16 20H2ZM2 18H16V8H2V18ZM2 6H16V4H2V6ZM4 12V10H14V12H4ZM4 16V14H11V16H4Z"
4347
+ fill="currentColor"
4348
+ />
4349
+ </svg>
4350
+ `,
4351
+ mapPin: (size = 14) => `
4352
+ <svg
4353
+ xmlns="http://www.w3.org/2000/svg"
4354
+ width="${size}"
4355
+ height="${Math.round((size * 20) / 14)}"
4356
+ viewBox="0 0 14 20"
4357
+ fill="none"
4358
+ class="medos-icon medos-icon-map-pin"
4359
+ >
4360
+ <path
4361
+ d="M7 20C5.23333 20 3.79167 19.7208 2.675 19.1625C1.55833 18.6042 1 17.8833 1 17C1 16.6 1.12083 16.2292 1.3625 15.8875C1.60417 15.5458 1.94167 15.25 2.375 15L3.95 16.475C3.8 16.5417 3.6375 16.6167 3.4625 16.7C3.2875 16.7833 3.15 16.8833 3.05 17C3.26667 17.2667 3.76667 17.5 4.55 17.7C5.33333 17.9 6.15 18 7 18C7.85 18 8.67083 17.9 9.4625 17.7C10.2542 17.5 10.7583 17.2667 10.975 17C10.8583 16.8667 10.7083 16.7583 10.525 16.675C10.3417 16.5917 10.1667 16.5167 10 16.45L11.55 14.95C12.0167 15.2167 12.375 15.5208 12.625 15.8625C12.875 16.2042 13 16.5833 13 17C13 17.8833 12.4417 18.6042 11.325 19.1625C10.2083 19.7208 8.76667 20 7 20ZM7.025 14.5C8.675 13.2833 9.91667 12.0625 10.75 10.8375C11.5833 9.6125 12 8.38333 12 7.15C12 5.45 11.4583 4.16667 10.375 3.3C9.29167 2.43333 8.16667 2 7 2C5.83333 2 4.70833 2.43333 3.625 3.3C2.54167 4.16667 2 5.45 2 7.15C2 8.26667 2.40833 9.42917 3.225 10.6375C4.04167 11.8458 5.30833 13.1333 7.025 14.5ZM7 17C4.65 15.2667 2.89583 13.5833 1.7375 11.95C0.579167 10.3167 0 8.71667 0 7.15C0 5.96667 0.2125 4.92917 0.6375 4.0375C1.0625 3.14583 1.60833 2.4 2.275 1.8C2.94167 1.2 3.69167 0.75 4.525 0.45C5.35833 0.15 6.18333 0 7 0C7.81667 0 8.64167 0.15 9.475 0.45C10.3083 0.75 11.0583 1.2 11.725 1.8C12.3917 2.4 12.9375 3.14583 13.3625 4.0375C13.7875 4.92917 14 5.96667 14 7.15C14 8.71667 13.4208 10.3167 12.2625 11.95C11.1042 13.5833 9.35 15.2667 7 17ZM7 9C7.55 9 8.02083 8.80417 8.4125 8.4125C8.80417 8.02083 9 7.55 9 7C9 6.45 8.80417 5.97917 8.4125 5.5875C8.02083 5.19583 7.55 5 7 5C6.45 5 5.97917 5.19583 5.5875 5.5875C5.19583 5.97917 5 6.45 5 7C5 7.55 5.19583 8.02083 5.5875 8.4125C5.97917 8.80417 6.45 9 7 9Z"
4362
+ fill="currentColor"
4363
+ />
4364
+ </svg>
4365
+ `,
4366
+ user: (size = 20) => `
4367
+ <svg
4368
+ xmlns="http://www.w3.org/2000/svg"
4369
+ width="${size}"
4370
+ height="${size}"
4371
+ viewBox="0 0 20 20"
4372
+ fill="none"
4373
+ class="medos-icon medos-icon-user"
4374
+ >
4375
+ <path
4376
+ d="M14 13C13.1667 13 12.4583 12.7083 11.875 12.125C11.2917 11.5417 11 10.8333 11 10C11 9.16667 11.2917 8.45833 11.875 7.875C12.4583 7.29167 13.1667 7 14 7C14.8333 7 15.5417 7.29167 16.125 7.875C16.7083 8.45833 17 9.16667 17 10C17 10.8333 16.7083 11.5417 16.125 12.125C15.5417 12.7083 14.8333 13 14 13ZM14 11C14.2833 11 14.5208 10.9042 14.7125 10.7125C14.9042 10.5208 15 10.2833 15 10C15 9.71667 14.9042 9.47917 14.7125 9.2875C14.5208 9.09583 14.2833 9 14 9C13.7167 9 13.4792 9.09583 13.2875 9.2875C13.0958 9.47917 13 9.71667 13 10C13 10.2833 13.0958 10.5208 13.2875 10.7125C13.4792 10.9042 13.7167 11 14 11ZM8 20V17.1C8 16.75 8.08333 16.4208 8.25 16.1125C8.41667 15.8042 8.65 15.5583 8.95 15.375C9.48333 15.0583 10.0458 14.7958 10.6375 14.5875C11.2292 14.3792 11.8333 14.225 12.45 14.125L14 16L15.55 14.125C16.1667 14.225 16.7667 14.3792 17.35 14.5875C17.9333 14.7958 18.4917 15.0583 19.025 15.375C19.325 15.5583 19.5625 15.8042 19.7375 16.1125C19.9125 16.4208 20 16.75 20 17.1V20H8ZM9.975 18H13.05L11.7 16.35C11.4 16.4333 11.1083 16.5417 10.825 16.675C10.5417 16.8083 10.2583 16.95 9.975 17.1V18ZM14.95 18H18V17.1C17.7333 16.9333 17.4583 16.7875 17.175 16.6625C16.8917 16.5375 16.6 16.4333 16.3 16.35L14.95 18ZM2 18C1.45 18 0.979167 17.8042 0.5875 17.4125C0.195833 17.0208 0 16.55 0 16V2C0 1.45 0.195833 0.979167 0.5875 0.5875C0.979167 0.195833 1.45 0 2 0H16C16.55 0 17.0208 0.195833 17.4125 0.5875C17.8042 0.979167 18 1.45 18 2V7C17.7333 6.66667 17.4417 6.35 17.125 6.05C16.8083 5.75 16.4333 5.55 16 5.45V2H2V16H6.15C6.1 16.1833 6.0625 16.3667 6.0375 16.55C6.0125 16.7333 6 16.9167 6 17.1V18H2ZM4 6H11C11.4333 5.66667 11.9083 5.41667 12.425 5.25C12.9417 5.08333 13.4667 5 14 5V4H4V6ZM4 10H9C9 9.65 9.0375 9.30833 9.1125 8.975C9.1875 8.64167 9.29167 8.31667 9.425 8H4V10ZM4 14H7.45C7.63333 13.85 7.82917 13.7167 8.0375 13.6C8.24583 13.4833 8.45833 13.375 8.675 13.275V12H4V14ZM2 16V2V5.425V5V16Z"
4377
+ fill="currentColor"
4378
+ />
4379
+ </svg>
4380
+ `,
4381
+ paymentMethod: (size = 21) => `
4382
+ <svg
4383
+ xmlns="http://www.w3.org/2000/svg"
4384
+ width="${size}"
4385
+ height="${Math.round((size * 15) / 21)}"
4386
+ viewBox="0 0 21 15"
4387
+ fill="none"
4388
+ class="medos-icon medos-icon-payment"
4389
+ >
4390
+ <path
4391
+ d="M11.9038 8.096C11.2051 8.096 10.6138 7.854 10.1298 7.37C9.64575 6.886 9.40375 6.29467 9.40375 5.596C9.40375 4.89733 9.64575 4.306 10.1298 3.822C10.6138 3.338 11.2051 3.096 11.9038 3.096C12.6024 3.096 13.1938 3.338 13.6778 3.822C14.1618 4.306 14.4038 4.89733 14.4038 5.596C14.4038 6.29467 14.1618 6.886 13.6778 7.37C13.1938 7.854 12.6024 8.096 11.9038 8.096ZM5.3075 11.1923C4.8105 11.1923 4.385 11.0153 4.031 10.6613C3.677 10.3073 3.5 9.88167 3.5 9.3845V1.8075C3.5 1.3105 3.677 0.885 4.031 0.531C4.385 0.177 4.8105 0 5.3075 0H18.4998C18.9969 0 19.4225 0.177 19.7765 0.531C20.1305 0.885 20.3075 1.3105 20.3075 1.8075V9.3845C20.3075 9.88167 20.1305 10.3073 19.7765 10.6613C19.4225 11.0153 18.9969 11.1923 18.4998 11.1923H5.3075ZM6.8075 9.69225H17C17 9.19358 17.177 8.76758 17.531 8.41425C17.885 8.06108 18.3105 7.8845 18.8075 7.8845V3.3075C18.3088 3.3075 17.8829 3.1305 17.5298 2.7765C17.1766 2.4225 17 1.997 17 1.5H6.8075C6.8075 1.99867 6.6305 2.42458 6.2765 2.77775C5.9225 3.13092 5.497 3.3075 5 3.3075V7.8845C5.49867 7.8845 5.92458 8.0615 6.27775 8.4155C6.63092 8.7695 6.8075 9.19508 6.8075 9.69225ZM17.3267 14.6923H1.80775C1.31058 14.6923 0.885 14.5153 0.531 14.1613C0.177 13.8073 0 13.3817 0 12.8845V2.98075H1.5V12.8845C1.5 12.9613 1.532 13.0318 1.596 13.096C1.66017 13.1602 1.73075 13.1923 1.80775 13.1923H17.3267V14.6923ZM5.3075 9.69225H5V1.5H5.3075C5.22417 1.5 5.15208 1.53042 5.09125 1.59125C5.03042 1.65208 5 1.72417 5 1.8075V9.3845C5 9.46783 5.03042 9.53992 5.09125 9.60075C5.15208 9.66175 5.22417 9.69225 5.3075 9.69225Z"
4392
+ fill="currentColor"
4393
+ />
4394
+ </svg>
4395
+ `,
4396
+ successBadge: (size = 64, shapeColor = "#006E0F", checkColor = "white") => `
4397
+ <div style="position: relative; display: inline-block;">
4398
+ <svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 41 41" fill="none">
4399
+ <path
4400
+ d="M31.1309 4.90254C32.388 4.98797 33.0166 5.03069 33.5247 5.25288C34.2598 5.57438 34.8467 6.16126 35.1682 6.8964C35.3904 7.40445 35.4331 8.03302 35.5185 9.29016L35.7135 12.159C35.748 12.6674 35.7653 12.9217 35.8206 13.1645C35.9004 13.5154 36.0391 13.8503 36.2308 14.1549C36.3634 14.3657 36.531 14.5576 36.8661 14.9416L38.7568 17.108C39.5853 18.0574 39.9996 18.532 40.2017 19.0484C40.4942 19.7955 40.4942 20.6255 40.2017 21.3727C39.9996 21.889 39.5853 22.3637 38.7568 23.313L36.8661 25.4795C36.531 25.8634 36.3634 26.0554 36.2308 26.2662C36.0391 26.5708 35.9004 26.9056 35.8206 27.2566C35.7653 27.4994 35.748 27.7536 35.7135 28.2621L35.5185 31.1309C35.4331 32.388 35.3904 33.0166 35.1682 33.5247C34.8467 34.2598 34.2598 34.8467 33.5247 35.1682C33.0166 35.3904 32.388 35.4331 31.1309 35.5185L28.2621 35.7135C27.7536 35.748 27.4994 35.7653 27.2566 35.8206C26.9056 35.9004 26.5708 36.0391 26.2662 36.2308C26.0554 36.3634 25.8634 36.531 25.4795 36.8661L23.313 38.7568C22.3637 39.5853 21.889 39.9996 21.3727 40.2017C20.6255 40.4942 19.7955 40.4942 19.0484 40.2017C18.532 39.9996 18.0574 39.5853 17.108 38.7568L14.9416 36.8661C14.5576 36.531 14.3657 36.3634 14.1549 36.2308C13.8503 36.0391 13.5154 35.9004 13.1645 35.8206C12.9217 35.7653 12.6674 35.748 12.159 35.7135L9.29016 35.5185C8.03302 35.4331 7.40445 35.3904 6.8964 35.1682C6.16126 34.8467 5.57438 34.2598 5.25288 33.5247C5.03069 33.0166 4.98797 32.388 4.90254 31.1309L4.70759 28.2621C4.67304 27.7536 4.65576 27.4994 4.60049 27.2566C4.52063 26.9056 4.38193 26.5708 4.19028 26.2662C4.05764 26.0554 3.89009 25.8634 3.555 25.4795L1.66428 23.313C0.83576 22.3637 0.421499 21.889 0.219363 21.3727C-0.073121 20.6255 -0.0731209 19.7955 0.219363 19.0484C0.421499 18.532 0.83576 18.0574 1.66428 17.108L3.555 14.9416C3.89009 14.5576 4.05764 14.3657 4.19027 14.1549C4.38193 13.8503 4.52063 13.5154 4.60049 13.1645C4.65576 12.9217 4.67304 12.6674 4.70759 12.159L4.90254 9.29016C4.98797 8.03302 5.03069 7.40445 5.25288 6.8964C5.57438 6.16126 6.16126 5.57438 6.8964 5.25288C7.40445 5.03069 8.03302 4.98797 9.29016 4.90254L12.159 4.70759C12.6674 4.67304 12.9217 4.65577 13.1645 4.6005C13.5154 4.52063 13.8503 4.38193 14.1549 4.19028C14.3657 4.05764 14.5576 3.89009 14.9416 3.555L17.108 1.66428C18.0574 0.83576 18.532 0.421499 19.0484 0.219363C19.7955 -0.073121 20.6255 -0.073121 21.3727 0.219363C21.889 0.421499 22.3637 0.83576 23.313 1.66428L25.4795 3.555C25.8634 3.89009 26.0554 4.05764 26.2662 4.19028C26.5708 4.38193 26.9056 4.52063 27.2566 4.6005C27.4994 4.65577 27.7536 4.67304 28.2621 4.70759L31.1309 4.90254Z"
4401
+ fill="${shapeColor}"
4402
+ />
4403
+ </svg>
4404
+ <svg xmlns="http://www.w3.org/2000/svg" width="${Math.round((size * 16) / 41)}" height="${Math.round((size * 12) / 41)}" viewBox="0 0 16 12" fill="none" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
4405
+ <path
4406
+ d="M5.472 11.544L0 6.072L1.368 4.704L5.472 8.808L14.28 0L15.648 1.368L5.472 11.544Z"
4407
+ fill="${checkColor}"
4408
+ />
4409
+ </svg>
4410
+ </div>
4411
+ `,
4412
+ phone: (size = 20) => `
4413
+ <svg
4414
+ xmlns="http://www.w3.org/2000/svg"
4415
+ width="${size}"
4416
+ height="${size}"
4417
+ viewBox="0 0 24 24"
4418
+ fill="none"
4419
+ stroke="currentColor"
4420
+ stroke-width="2"
4421
+ stroke-linecap="round"
4422
+ stroke-linejoin="round"
4423
+ class="medos-icon medos-icon-phone"
4424
+ >
4425
+ <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>
4426
+ </svg>
4427
+ `,
4428
+ mail: (size = 20) => `
4429
+ <svg
4430
+ xmlns="http://www.w3.org/2000/svg"
4431
+ width="${size}"
4432
+ height="${size}"
4433
+ viewBox="0 0 24 24"
4434
+ fill="none"
4435
+ stroke="currentColor"
4436
+ stroke-width="2"
4437
+ stroke-linecap="round"
4438
+ stroke-linejoin="round"
4439
+ class="medos-icon medos-icon-mail"
4440
+ >
4441
+ <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
4442
+ <polyline points="22,6 12,13 2,6"></polyline>
4443
+ </svg>
4444
+ `,
4445
+ clock: (size = 20) => `
4446
+ <svg
4447
+ xmlns="http://www.w3.org/2000/svg"
4448
+ width="${size}"
4449
+ height="${size}"
4450
+ viewBox="0 0 24 24"
4451
+ fill="none"
4452
+ stroke="currentColor"
4453
+ stroke-width="2"
4454
+ stroke-linecap="round"
4455
+ stroke-linejoin="round"
4456
+ class="medos-icon medos-icon-clock"
4457
+ >
4458
+ <circle cx="12" cy="12" r="10"></circle>
4459
+ <polyline points="12 6 12 12 16 14"></polyline>
4460
+ </svg>
4461
+ `,
4462
+ medosLogo: (width = 120, height = 114) => `
4463
+ <svg
4464
+ width="${width}"
4465
+ height="${height}"
4466
+ viewBox="0 0 250 236"
4467
+ fill="none"
4468
+ xmlns="http://www.w3.org/2000/svg"
4469
+ class="medos-icon medos-logo"
4470
+ >
4471
+ <g filter="url(#filter0_d_4215_30142)">
4472
+ <path
4473
+ d="M14.2067 123.859L21.2068 123.862L38.2027 67.687L55.7021 152.687L77.707 60.6836L93.7021 123.863L239.202 123.863"
4474
+ stroke="#27903F"
4475
+ stroke-width="4"
4476
+ stroke-linecap="round"
4477
+ />
4478
+ </g>
4479
+ <path
4480
+ d="M111.695 118.797C108.857 118.797 106.408 118.171 104.35 116.918C102.305 115.652 100.726 113.888 99.6136 111.625C98.5142 109.35 97.9645 106.703 97.9645 103.686C97.9645 100.669 98.5142 98.0103 99.6136 95.7092C100.726 93.3952 102.273 91.5927 104.254 90.3015C106.249 88.9975 108.575 88.3455 111.234 88.3455C112.768 88.3455 114.283 88.6012 115.779 89.1126C117.275 89.6239 118.636 90.4549 119.864 91.6055C121.091 92.7433 122.069 94.2518 122.798 96.131C123.526 98.0103 123.891 100.324 123.891 103.073V104.99H101.186V101.078H119.288C119.288 99.4165 118.956 97.9336 118.291 96.6296C117.639 95.3256 116.706 94.2965 115.491 93.5423C114.29 92.788 112.871 92.4109 111.234 92.4109C109.432 92.4109 107.872 92.8583 106.555 93.7532C105.251 94.6353 104.248 95.7859 103.545 97.2049C102.842 98.6239 102.49 100.145 102.49 101.769V104.377C102.49 106.601 102.874 108.487 103.641 110.034C104.42 111.568 105.501 112.738 106.881 113.543C108.262 114.336 109.866 114.732 111.695 114.732C112.884 114.732 113.957 114.566 114.916 114.233C115.888 113.888 116.725 113.377 117.428 112.699C118.131 112.009 118.675 111.152 119.058 110.13L123.43 111.357C122.97 112.84 122.197 114.144 121.11 115.269C120.023 116.381 118.681 117.25 117.083 117.877C115.485 118.49 113.689 118.797 111.695 118.797ZM141.897 118.797C139.442 118.797 137.276 118.177 135.396 116.937C133.517 115.684 132.047 113.92 130.986 111.645C129.925 109.356 129.394 106.652 129.394 103.533C129.394 100.439 129.925 97.7546 130.986 95.479C132.047 93.2035 133.523 91.4457 135.415 90.2056C137.308 88.9656 139.494 88.3455 141.974 88.3455C143.891 88.3455 145.406 88.6651 146.518 89.3043C147.643 89.9308 148.5 90.6467 149.088 91.4521C149.689 92.2447 150.156 92.8967 150.488 93.408H150.871V78.9109H155.397V118.184H151.025V113.658H150.488C150.156 114.195 149.683 114.873 149.069 115.691C148.455 116.496 147.58 117.218 146.442 117.858C145.304 118.484 143.789 118.797 141.897 118.797ZM142.511 114.732C144.326 114.732 145.86 114.259 147.113 113.313C148.366 112.354 149.318 111.031 149.97 109.343C150.622 107.643 150.948 105.681 150.948 103.456C150.948 101.257 150.629 99.3335 149.989 97.6843C149.35 96.0224 148.404 94.7312 147.151 93.8107C145.898 92.8775 144.352 92.4109 142.511 92.4109C140.593 92.4109 138.995 92.9031 137.717 93.8874C136.451 94.859 135.499 96.1822 134.859 97.8569C134.233 99.5188 133.92 101.385 133.92 103.456C133.92 105.553 134.239 107.458 134.879 109.171C135.531 110.871 136.489 112.226 137.755 113.236C139.033 114.233 140.619 114.732 142.511 114.732ZM199.138 98.5472C199.138 102.779 198.345 106.403 196.76 109.42C195.188 112.424 193.04 114.725 190.317 116.324C187.607 117.922 184.532 118.721 181.093 118.721C177.654 118.721 174.573 117.922 171.85 116.324C169.14 114.713 166.992 112.405 165.407 109.401C163.835 106.384 163.048 102.766 163.048 98.5472C163.048 94.3157 163.835 90.6978 165.407 87.6935C166.992 84.6765 169.14 82.369 171.85 80.7709C174.573 79.1729 177.654 78.3739 181.093 78.3739C184.532 78.3739 187.607 79.1729 190.317 80.7709C193.04 82.369 195.188 84.6765 196.76 87.6935C198.345 90.6978 199.138 94.3157 199.138 98.5472ZM191.985 98.5472C191.985 95.5685 191.518 93.0565 190.585 91.011C189.665 88.9528 188.386 87.3995 186.75 86.3512C185.114 85.2901 183.228 84.7596 181.093 84.7596C178.958 84.7596 177.072 85.2901 175.436 86.3512C173.8 87.3995 172.515 88.9528 171.582 91.011C170.661 93.0565 170.201 95.5685 170.201 98.5472C170.201 101.526 170.661 104.044 171.582 106.103C172.515 108.148 173.8 109.701 175.436 110.762C177.072 111.811 178.958 112.335 181.093 112.335C183.228 112.335 185.114 111.811 186.75 110.762C188.386 109.701 189.665 108.148 190.585 106.103C191.518 104.044 191.985 101.526 191.985 98.5472ZM227.207 89.707C227.028 88.0323 226.274 86.7283 224.944 85.7951C223.627 84.8619 221.914 84.3952 219.805 84.3952C218.322 84.3952 217.05 84.619 215.989 85.0664C214.928 85.5138 214.116 86.1211 213.553 86.8881C212.991 87.6552 212.703 88.5309 212.691 89.5153C212.691 90.3335 212.876 91.043 213.247 91.6438C213.63 92.2447 214.148 92.756 214.8 93.1779C215.452 93.587 216.174 93.9322 216.967 94.2134C217.759 94.4947 218.558 94.7312 219.364 94.9229L223.046 95.8434C224.529 96.1886 225.954 96.6552 227.322 97.2433C228.703 97.8313 229.936 98.5728 231.023 99.4677C232.122 100.363 232.992 101.443 233.631 102.708C234.27 103.974 234.59 105.457 234.59 107.157C234.59 109.458 234.002 111.485 232.825 113.236C231.649 114.975 229.949 116.336 227.725 117.321C225.513 118.292 222.835 118.778 219.69 118.778C216.634 118.778 213.982 118.305 211.732 117.359C209.494 116.413 207.743 115.032 206.477 113.217C205.225 111.402 204.547 109.19 204.445 106.582H211.444C211.546 107.95 211.968 109.088 212.71 109.995C213.451 110.903 214.416 111.581 215.605 112.028C216.807 112.475 218.149 112.699 219.632 112.699C221.179 112.699 222.534 112.469 223.698 112.009C224.874 111.536 225.794 110.884 226.459 110.053C227.124 109.209 227.463 108.225 227.475 107.1C227.463 106.077 227.162 105.233 226.574 104.569C225.986 103.891 225.161 103.328 224.1 102.881C223.052 102.421 221.825 102.012 220.419 101.654L215.95 100.503C212.716 99.6722 210.159 98.413 208.28 96.7255C206.414 95.0252 205.48 92.7688 205.48 89.9563C205.48 87.6424 206.107 85.6161 207.36 83.8775C208.625 82.1388 210.345 80.7901 212.518 79.8313C214.691 78.8597 217.152 78.3739 219.901 78.3739C222.688 78.3739 225.129 78.8597 227.226 79.8313C229.335 80.7901 230.991 82.1261 232.193 83.8391C233.394 85.5394 234.014 87.4954 234.053 89.707H227.207Z"
4481
+ fill="#27903F"
4482
+ />
4483
+ <defs>
4484
+ <filter
4485
+ id="filter0_d_4215_30142"
4486
+ x="12.2031"
4487
+ y="60.1914"
4488
+ width="237"
4489
+ height="100.961"
4490
+ filterUnits="userSpaceOnUse"
4491
+ color-interpolation-filters="sRGB"
4492
+ >
4493
+ <feFlood flood-opacity="0" result="BackgroundImageFix" />
4494
+ <feColorMatrix
4495
+ in="SourceAlpha"
4496
+ type="matrix"
4497
+ values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
4498
+ result="hardAlpha"
4499
+ />
4500
+ <feOffset dx="4" dy="4" />
4501
+ <feGaussianBlur stdDeviation="2" />
4502
+ <feComposite in2="hardAlpha" operator="out" />
4503
+ <feColorMatrix
4504
+ type="matrix"
4505
+ values="0 0 0 0 0.152941 0 0 0 0 0.564706 0 0 0 0 0.247059 0 0 0 0.12 0"
4506
+ />
4507
+ <feBlend
4508
+ mode="normal"
4509
+ in2="BackgroundImageFix"
4510
+ result="effect1_dropShadow_4215_30142"
4511
+ />
4512
+ <feBlend
4513
+ mode="normal"
4514
+ in="SourceGraphic"
4515
+ in2="effect1_dropShadow_4215_30142"
4516
+ result="shape"
4517
+ />
4518
+ </filter>
4519
+ </defs>
4520
+ </svg>
4521
+ `,
4522
+ };
4523
+
4524
+ function injectSelectStyles() {
4525
+ if (typeof document === "undefined")
4526
+ return;
4527
+ const styleId = "medos-vanilla-select-styles";
4528
+ if (document.getElementById(styleId))
4529
+ return;
4530
+ const styleElement = document.createElement("style");
4531
+ styleElement.id = styleId;
4532
+ styleElement.innerHTML = `
4533
+ /* Container */
4534
+ .medos-select-container {
4535
+ position: relative;
4536
+ display: inline-block;
4537
+ width: 100%;
4538
+ }
4539
+
4540
+ /* Trigger Button */
4541
+ .medos-select-trigger {
4542
+ display: flex;
4543
+ width: 100%;
4544
+ align-items: center;
4545
+ justify-content: space-between;
4546
+ white-space: nowrap;
4547
+ border-radius: var(--medos-radius-md, 8px);
4548
+ border: 1px solid var(--medos-color-border, #e5e7eb);
4549
+ background-color: var(--medos-color-surface, #fff);
4550
+ padding: var(--medos-spacing-sm, 10px) var(--medos-spacing-md, 12px);
4551
+ font-size: var(--medos-typography-font-size-sm, 14px);
4552
+ line-height: 1.5;
4553
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
4554
+ transition: var(--medos-transition-normal, 200ms ease-in-out);
4555
+ cursor: pointer;
4556
+ outline: none;
4557
+ font-family: inherit;
4558
+ text-align: left;
4559
+ box-sizing: border-box;
4560
+ color: var(--medos-color-text, #111827);
4561
+ }
4562
+
4563
+ .medos-select-trigger:hover:not(:disabled) {
4564
+ border-color: var(--medos-color-border-hover, #d1d5db);
4565
+ }
4566
+
4567
+ .medos-select-trigger:focus:not(:disabled) {
4568
+ border-color: var(--medos-color-primary, #27903f);
4569
+ box-shadow: 0 0 0 2px rgba(39, 144, 63, 0.15);
4570
+ }
4571
+
4572
+ .medos-select-trigger:disabled {
4573
+ cursor: not-allowed;
4574
+ opacity: 0.5;
4575
+ background-color: #f9fafb;
4576
+ }
4577
+
4578
+ .medos-select-trigger-error {
4579
+ border-color: #ef4444;
4580
+ }
4581
+
4582
+ .medos-select-trigger-error:focus {
4583
+ border-color: #ef4444;
4584
+ box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2);
4585
+ }
4586
+
4587
+ .medos-select-trigger[aria-expanded="true"] {
4588
+ border-color: var(--medos-color-primary, #27903f);
4589
+ box-shadow: 0 0 0 2px rgba(39, 144, 63, 0.15);
4590
+ }
4591
+
4592
+ /* Select Value */
4593
+ .medos-select-value {
4594
+ flex: 1;
4595
+ overflow: hidden;
4596
+ text-overflow: ellipsis;
4597
+ white-space: nowrap;
4598
+ }
4599
+
4600
+ .medos-select-placeholder {
4601
+ color: #94a3b8;
4602
+ }
4603
+
4604
+ /* Select Icon */
4605
+ .medos-select-icon {
4606
+ height: 16px;
4607
+ width: 16px;
4608
+ opacity: 0.5;
4609
+ flex-shrink: 0;
4610
+ margin-left: 8px;
4611
+ transition: transform 0.2s;
4612
+ display: flex;
4613
+ align-items: center;
4614
+ justify-content: center;
4615
+ }
4616
+
4617
+ .medos-select-trigger[aria-expanded="true"] .medos-select-icon {
4618
+ transform: rotate(180deg);
4619
+ }
4620
+
4621
+ .medos-select-icon-error {
4622
+ color: #ef4444;
4623
+ }
4624
+
4625
+ /* Content Dropdown - Portal */
4626
+ .medos-select-content {
4627
+ position: absolute;
4628
+ z-index: 99999;
4629
+ overflow: hidden;
4630
+ border-radius: 6px;
4631
+ border: 1px solid #e2e8f0;
4632
+ background-color: #ffffff;
4633
+ color: #1e293b;
4634
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
4635
+ animation: medos-select-show 0.15s ease-out;
4636
+ box-sizing: border-box;
4637
+ }
4638
+
4639
+ @keyframes medos-select-show {
4640
+ from {
4641
+ opacity: 0;
4642
+ transform: translateY(-4px);
4643
+ }
4644
+ to {
4645
+ opacity: 1;
4646
+ transform: translateY(0);
4647
+ }
4648
+ }
4649
+
4650
+ /* Viewport */
4651
+ .medos-select-viewport {
4652
+ padding: 4px;
4653
+ max-height: 256px;
4654
+ overflow-y: auto;
4655
+ }
4656
+
4657
+ /* Select Item */
4658
+ .medos-select-item {
4659
+ position: relative;
4660
+ display: flex;
4661
+ width: 100%;
4662
+ cursor: pointer;
4663
+ user-select: none;
4664
+ align-items: center;
4665
+ border-radius: 4px;
4666
+ padding: 8px 8px 8px 32px;
4667
+ font-size: 14px;
4668
+ outline: none;
4669
+ transition: background-color 0.1s ease;
4670
+ box-sizing: border-box;
4671
+ color: #1e293b;
4672
+ }
4673
+
4674
+ .medos-select-item:hover:not(.medos-select-item-disabled) {
4675
+ background-color: #f1f5f9;
4676
+ }
4677
+
4678
+ .medos-select-item:focus {
4679
+ background-color: #f1f5f9;
4680
+ }
4681
+
4682
+ .medos-select-item-selected {
4683
+ background-color: #f3f4f6;
4684
+ }
4685
+
4686
+ .medos-select-item-disabled {
4687
+ pointer-events: none;
4688
+ opacity: 0.5;
4689
+ cursor: not-allowed;
4690
+ }
4691
+
4692
+ /* Item Indicator */
4693
+ .medos-select-item-indicator {
4694
+ position: absolute;
4695
+ left: 8px;
4696
+ display: flex;
4697
+ height: 14px;
4698
+ width: 14px;
4699
+ align-items: center;
4700
+ justify-content: center;
4701
+ color: var(--medos-color-primary, #27903f);
4702
+ }
4703
+
4704
+ /* Item Text */
4705
+ .medos-select-item-text {
4706
+ flex: 1;
4707
+ }
4708
+
4709
+ /* Scrollbar styling */
4710
+ .medos-select-viewport::-webkit-scrollbar {
4711
+ width: 8px;
4712
+ }
4713
+
4714
+ .medos-select-viewport::-webkit-scrollbar-track {
4715
+ background: #f1f5f9;
4716
+ border-radius: 4px;
4717
+ }
4718
+
4719
+ .medos-select-viewport::-webkit-scrollbar-thumb {
4720
+ background: #cbd5e1;
4721
+ border-radius: 4px;
4722
+ }
4723
+
4724
+ .medos-select-viewport::-webkit-scrollbar-thumb:hover {
4725
+ background: #94a3b8;
4726
+ }
4727
+ `;
4728
+ document.head.appendChild(styleElement);
4729
+ }
4730
+ class VanillaSelect {
4731
+ constructor(container, options, config = {}) {
4732
+ this.selectedValue = "";
4733
+ this.selectedLabel = "";
4734
+ this.isOpen = false;
4735
+ this.triggerElement = null;
4736
+ this.contentElement = null;
4737
+ this.handleDocumentClick = null;
4738
+ this.handleWindowResize = null;
4739
+ this.handleWindowScroll = null;
4740
+ if (typeof container === "string") {
4741
+ const el = document.getElementById(container);
4742
+ if (!el) {
4743
+ throw new Error(`Container element with id "${container}" not found`);
4744
+ }
4745
+ this.container = el;
4746
+ }
4747
+ else {
4748
+ this.container = container;
4749
+ }
4750
+ this.options = options;
4751
+ this.config = {
4752
+ placeholder: "Select...",
4753
+ disabled: false,
4754
+ error: false,
4755
+ ...config,
4756
+ };
4757
+ injectSelectStyles();
4758
+ this.renderTrigger();
4759
+ }
4760
+ renderTrigger() {
4761
+ const displayValue = this.selectedLabel || this.config.placeholder;
4762
+ const isPlaceholder = !this.selectedLabel;
4763
+ this.container.innerHTML = "";
4764
+ this.container.classList.add("medos-select-container");
4765
+ const button = document.createElement("button");
4766
+ button.type = "button";
4767
+ button.className = `medos-select-trigger ${this.config.error ? "medos-select-trigger-error" : ""}`;
4768
+ button.setAttribute("aria-expanded", this.isOpen.toString());
4769
+ button.setAttribute("aria-haspopup", "listbox");
4770
+ if (this.config.disabled) {
4771
+ button.disabled = true;
4772
+ }
4773
+ button.innerHTML = `
4774
+ <span class="medos-select-value ${isPlaceholder ? "medos-select-placeholder" : ""}">
4775
+ ${this.escapeHtml(displayValue || "")}
4776
+ </span>
4777
+ <span class="medos-select-icon ${this.config.error ? "medos-select-icon-error" : ""}">
4778
+ ${VanillaIcons.chevronDown(16)}
4779
+ </span>
4780
+ `;
4781
+ this.container.appendChild(button);
4782
+ this.triggerElement = button;
4783
+ this.attachTriggerEvents();
4784
+ }
4785
+ attachTriggerEvents() {
4786
+ if (!this.triggerElement)
4787
+ return;
4788
+ this.triggerElement.addEventListener("click", (e) => {
4789
+ e.preventDefault();
4790
+ if (!this.config.disabled) {
4791
+ this.toggleOpen();
4792
+ }
4793
+ });
4794
+ this.triggerElement.addEventListener("keydown", (e) => {
4795
+ if (this.config.disabled)
4796
+ return;
4797
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
4798
+ e.preventDefault();
4799
+ this.open();
4800
+ }
4801
+ });
4802
+ }
4803
+ toggleOpen() {
4804
+ if (this.isOpen) {
4805
+ this.close();
4806
+ }
4807
+ else {
4808
+ this.open();
4809
+ }
4810
+ }
4811
+ open() {
4812
+ if (this.isOpen || this.config.disabled)
4813
+ return;
4814
+ this.isOpen = true;
4815
+ if (this.triggerElement) {
4816
+ this.triggerElement.setAttribute("aria-expanded", "true");
4817
+ }
4818
+ this.createPortal();
4819
+ this.attachPortalEvents();
4820
+ setTimeout(() => {
4821
+ if (this.contentElement) {
4822
+ const selectedItem = this.contentElement.querySelector(".medos-select-item-selected");
4823
+ const firstItem = this.contentElement.querySelector(".medos-select-item:not(.medos-select-item-disabled)");
4824
+ (selectedItem || firstItem)?.focus();
4825
+ }
4826
+ }, 0);
4827
+ }
4828
+ close() {
4829
+ if (!this.isOpen)
4830
+ return;
4831
+ this.isOpen = false;
4832
+ if (this.triggerElement) {
4833
+ this.triggerElement.setAttribute("aria-expanded", "false");
4834
+ this.triggerElement.focus();
4835
+ }
4836
+ this.removePortal();
4837
+ this.detachPortalEvents();
4838
+ }
4839
+ createPortal() {
4840
+ if (!this.triggerElement)
4841
+ return;
4842
+ const rect = this.triggerElement.getBoundingClientRect();
4843
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
4844
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
4845
+ this.contentElement = document.createElement("div");
4846
+ this.contentElement.className = "medos-select-content";
4847
+ this.contentElement.setAttribute("role", "listbox");
4848
+ this.contentElement.style.top = `${rect.bottom + scrollTop + 4}px`;
4849
+ this.contentElement.style.left = `${rect.left + scrollLeft}px`;
4850
+ this.contentElement.style.width = `${rect.width}px`;
4851
+ this.contentElement.innerHTML = `
4852
+ <div class="medos-select-viewport">
4853
+ ${this.options
4854
+ .map((option) => `
4855
+ <div
4856
+ class="medos-select-item ${this.selectedValue === option.value
4857
+ ? "medos-select-item-selected"
4858
+ : ""} ${option.disabled ? "medos-select-item-disabled" : ""}"
4859
+ role="option"
4860
+ aria-selected="${this.selectedValue === option.value}"
4861
+ data-value="${this.escapeHtml(option.value)}"
4862
+ data-label="${this.escapeHtml(option.label)}"
4863
+ ${option.disabled ? 'data-disabled="true"' : ""}
4864
+ tabindex="${option.disabled ? "-1" : "0"}"
4865
+ >
4866
+ ${this.selectedValue === option.value
4867
+ ? `
4868
+ <span class="medos-select-item-indicator">
4869
+ ${VanillaIcons.check(14)}
4870
+ </span>
4871
+ `
4872
+ : ""}
4873
+ <span class="medos-select-item-text">${this.escapeHtml(option.label)}</span>
4874
+ </div>
4875
+ `)
4876
+ .join("")}
4877
+ </div>
4878
+ `;
4879
+ document.body.appendChild(this.contentElement);
4880
+ }
4881
+ removePortal() {
4882
+ this.contentElement?.remove();
4883
+ this.contentElement = null;
4884
+ }
4885
+ updatePosition() {
4886
+ if (!this.isOpen || !this.triggerElement || !this.contentElement)
4887
+ return;
4888
+ const rect = this.triggerElement.getBoundingClientRect();
4889
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
4890
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
4891
+ this.contentElement.style.top = `${rect.bottom + scrollTop + 4}px`;
4892
+ this.contentElement.style.left = `${rect.left + scrollLeft}px`;
4893
+ this.contentElement.style.width = `${rect.width}px`;
4894
+ }
4895
+ attachPortalEvents() {
4896
+ this.handleDocumentClick = (e) => {
4897
+ const target = e.target;
4898
+ if (this.isOpen &&
4899
+ this.contentElement &&
4900
+ !this.contentElement.contains(target) &&
4901
+ this.triggerElement &&
4902
+ !this.triggerElement.contains(target)) {
4903
+ this.close();
4904
+ }
4905
+ };
4906
+ document.addEventListener("mousedown", this.handleDocumentClick);
4907
+ this.handleWindowResize = () => this.updatePosition();
4908
+ this.handleWindowScroll = () => this.updatePosition();
4909
+ window.addEventListener("resize", this.handleWindowResize);
4910
+ window.addEventListener("scroll", this.handleWindowScroll, true);
4911
+ if (this.contentElement) {
4912
+ this.contentElement.addEventListener("click", (e) => {
4913
+ const target = e.target;
4914
+ const item = target.closest(".medos-select-item");
4915
+ if (item && !item.dataset.disabled) {
4916
+ const value = item.dataset.value || "";
4917
+ const label = item.dataset.label || "";
4918
+ this.selectValue(value, label);
4919
+ }
4920
+ });
4921
+ this.contentElement.addEventListener("keydown", (e) => {
4922
+ if (e.key === "Escape") {
4923
+ this.close();
4924
+ }
4925
+ else if (e.key === "ArrowDown") {
4926
+ e.preventDefault();
4927
+ this.focusNextItem(1);
4928
+ }
4929
+ else if (e.key === "ArrowUp") {
4930
+ e.preventDefault();
4931
+ this.focusNextItem(-1);
4932
+ }
4933
+ else if (e.key === "Enter" || e.key === " ") {
4934
+ e.preventDefault();
4935
+ const focused = document.activeElement;
4936
+ if (focused &&
4937
+ focused.classList.contains("medos-select-item") &&
4938
+ !focused.dataset.disabled) {
4939
+ const value = focused.dataset.value || "";
4940
+ const label = focused.dataset.label || "";
4941
+ this.selectValue(value, label);
4942
+ }
4943
+ }
4944
+ });
4945
+ }
4946
+ }
4947
+ detachPortalEvents() {
4948
+ if (this.handleDocumentClick) {
4949
+ document.removeEventListener("mousedown", this.handleDocumentClick);
4950
+ this.handleDocumentClick = null;
4951
+ }
4952
+ if (this.handleWindowResize) {
4953
+ window.removeEventListener("resize", this.handleWindowResize);
4954
+ this.handleWindowResize = null;
4955
+ }
4956
+ if (this.handleWindowScroll) {
4957
+ window.removeEventListener("scroll", this.handleWindowScroll, true);
4958
+ this.handleWindowScroll = null;
4959
+ }
4960
+ }
4961
+ focusNextItem(direction) {
4962
+ if (!this.contentElement)
4963
+ return;
4964
+ const items = Array.from(this.contentElement.querySelectorAll(".medos-select-item:not(.medos-select-item-disabled)"));
4965
+ if (items.length === 0)
4966
+ return;
4967
+ const currentFocused = document.activeElement;
4968
+ let currentIndex = items.indexOf(currentFocused);
4969
+ let nextIndex = currentIndex + direction;
4970
+ if (nextIndex < 0)
4971
+ nextIndex = items.length - 1;
4972
+ if (nextIndex >= items.length)
4973
+ nextIndex = 0;
4974
+ items[nextIndex]?.focus();
4975
+ }
4976
+ selectValue(value, label) {
4977
+ this.selectedValue = value;
4978
+ this.selectedLabel = label;
4979
+ this.close();
4980
+ this.renderTrigger();
4981
+ this.config.onValueChange?.(value);
4982
+ }
4983
+ setValue(value) {
4984
+ const option = this.options.find((o) => o.value === value);
4985
+ if (option) {
4986
+ this.selectedValue = option.value;
4987
+ this.selectedLabel = option.label;
4988
+ this.renderTrigger();
4989
+ }
4990
+ }
4991
+ getValue() {
4992
+ return this.selectedValue;
4993
+ }
4994
+ setOptions(options) {
4995
+ this.options = options;
4996
+ if (!options.some((o) => o.value === this.selectedValue)) {
4997
+ this.selectedValue = "";
4998
+ this.selectedLabel = "";
4999
+ }
5000
+ this.renderTrigger();
5001
+ }
5002
+ setDisabled(disabled) {
5003
+ this.config.disabled = disabled;
5004
+ this.renderTrigger();
5005
+ this.attachTriggerEvents();
5006
+ }
5007
+ setError(error) {
5008
+ this.config.error = error;
5009
+ this.renderTrigger();
5010
+ }
5011
+ destroy() {
5012
+ this.close();
5013
+ this.container.innerHTML = "";
5014
+ }
5015
+ escapeHtml(text) {
5016
+ const div = document.createElement("div");
5017
+ div.textContent = text;
5018
+ return div.innerHTML;
5019
+ }
5020
+ }
5021
+
5022
+ function injectCalendarStyles() {
5023
+ if (typeof document === "undefined")
5024
+ return;
5025
+ const styleId = "medos-vanilla-calendar-styles";
5026
+ if (document.getElementById(styleId))
5027
+ return;
5028
+ const styleElement = document.createElement("style");
5029
+ styleElement.id = styleId;
5030
+ styleElement.innerHTML = `
5031
+ .medos-calendar {
5032
+ width: 340px;
5033
+ background-color: var(--medos-color-background, #ffffff);
5034
+ border-radius: var(--medos-radius-md, 8px);
5035
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
5036
+ padding: 16px;
5037
+ font-family: var(--medos-typography-font-family, 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial);
5038
+ border: 1px solid var(--medos-color-border, #e5e7eb);
5039
+ box-sizing: border-box;
5040
+ }
5041
+
5042
+ .medos-calendar-header {
5043
+ display: flex;
5044
+ justify-content: space-between;
5045
+ align-items: center;
5046
+ margin-bottom: 12px;
5047
+ }
5048
+
5049
+ .medos-calendar-month {
5050
+ font-size: 14px;
5051
+ font-weight: 600;
5052
+ color: var(--medos-color-text, #111827);
5053
+ margin: 0;
5054
+ }
5055
+
5056
+ .medos-calendar-nav {
5057
+ width: 28px;
5058
+ height: 28px;
5059
+ display: flex;
5060
+ align-items: center;
5061
+ justify-content: center;
5062
+ color: var(--medos-color-secondary, #6b7280);
5063
+ cursor: pointer;
5064
+ border-radius: var(--medos-radius-sm, 4px);
5065
+ transition: background-color 0.2s;
5066
+ border: none;
5067
+ background: transparent;
5068
+ padding: 0;
5069
+ }
5070
+
5071
+ .medos-calendar-nav:hover {
5072
+ background-color: var(--medos-color-background-secondary, #f3f4f6);
5073
+ }
5074
+
5075
+ .medos-calendar-days-header {
5076
+ display: grid;
5077
+ grid-template-columns: repeat(7, 1fr);
5078
+ text-align: center;
5079
+ margin-bottom: 6px;
5080
+ font-size: 13px;
5081
+ font-weight: 500;
5082
+ color: var(--medos-color-text, #111827);
5083
+ }
5084
+
5085
+ .medos-calendar-day-name {
5086
+ padding: 4px 0;
5087
+ }
5088
+
5089
+ .medos-calendar-grid {
5090
+ display: grid;
5091
+ grid-template-columns: repeat(7, 1fr);
5092
+ gap: 4px;
5093
+ text-align: center;
5094
+ }
5095
+
5096
+ .medos-calendar-day {
5097
+ width: 38px;
5098
+ height: 38px;
5099
+ border: 1px solid transparent;
5100
+ border-radius: var(--medos-radius-md, 8px);
5101
+ color: var(--medos-color-secondary, #6b7280);
5102
+ background-color: transparent;
5103
+ font-size: 14px;
5104
+ transition: all 0.2s;
5105
+ display: flex;
5106
+ align-items: center;
5107
+ justify-content: center;
5108
+ flex-direction: column;
5109
+ cursor: pointer;
5110
+ padding: 0;
5111
+ font-family: inherit;
5112
+ }
5113
+
5114
+ .medos-calendar-day span {
5115
+ line-height: 1;
5116
+ }
5117
+
5118
+ .medos-calendar-day:hover:not(.medos-calendar-day-disabled):not(.medos-calendar-day-selected) {
5119
+ background-color: var(--medos-color-secondary, #6b7280);
5120
+ color: var(--medos-color-text-on-secondary, #ffffff);
5121
+ }
5122
+
5123
+ .medos-calendar-day-selected {
5124
+ border: 1px solid var(--medos-color-secondary, #6b7280);
5125
+ color: var(--medos-color-secondary, #6b7280);
5126
+ background-color: transparent;
5127
+ font-weight: 600;
5128
+ }
5129
+
5130
+ .medos-calendar-day-today {
5131
+ background-color: var(--medos-color-primary, #27903f);
5132
+ color: white;
5133
+ }
5134
+
5135
+ .medos-calendar-day-today:hover:not(.medos-calendar-day-selected) {
5136
+ background-color: var(--medos-color-primary-hover, #218838);
5137
+ }
5138
+
5139
+ .medos-calendar-day-disabled {
5140
+ color: var(--medos-color-text-secondary, #9ca3af);
5141
+ opacity: 0.4;
5142
+ cursor: not-allowed;
5143
+ }
5144
+
5145
+ .medos-calendar-day-disabled:hover {
5146
+ background-color: transparent;
5147
+ color: var(--medos-color-text-secondary, #9ca3af);
5148
+ }
5149
+
5150
+ .medos-calendar-dot {
5151
+ font-size: 10px;
5152
+ margin-top: -2px;
5153
+ line-height: 1;
5154
+ }
5155
+
5156
+ .medos-calendar-empty {
5157
+ visibility: hidden;
5158
+ width: 38px;
5159
+ height: 38px;
5160
+ }
5161
+ `;
5162
+ document.head.appendChild(styleElement);
5163
+ }
5164
+ class VanillaCalendar {
5165
+ constructor(container, config = {}) {
5166
+ this.selectedDate = null;
5167
+ if (typeof container === "string") {
5168
+ const el = document.getElementById(container);
5169
+ if (!el) {
5170
+ throw new Error(`Container element with id "${container}" not found`);
5171
+ }
5172
+ this.container = el;
5173
+ }
5174
+ else {
5175
+ this.container = container;
5176
+ }
5177
+ this.config = {
5178
+ pastDisabled: false,
5179
+ ...config,
5180
+ };
5181
+ this.today = new Date();
5182
+ this.today.setHours(0, 0, 0, 0);
5183
+ if (config.selectedDate) {
5184
+ this.selectedDate = new Date(config.selectedDate);
5185
+ this.selectedDate.setHours(0, 0, 0, 0);
5186
+ this.currentMonth = this.selectedDate.getMonth();
5187
+ this.currentYear = this.selectedDate.getFullYear();
5188
+ }
5189
+ else {
5190
+ this.currentMonth = this.today.getMonth();
5191
+ this.currentYear = this.today.getFullYear();
5192
+ }
5193
+ injectCalendarStyles();
5194
+ this.render();
5195
+ this.attachEventListeners();
5196
+ }
5197
+ getDaysInMonth(year, month) {
5198
+ return new Date(year, month + 1, 0).getDate();
5199
+ }
5200
+ getFirstDayOfMonth(year, month) {
5201
+ return new Date(year, month, 1).getDay();
5202
+ }
5203
+ isSameDate(d1, d2) {
5204
+ return (d1.getFullYear() === d2.getFullYear() &&
5205
+ d1.getMonth() === d2.getMonth() &&
5206
+ d1.getDate() === d2.getDate());
5207
+ }
5208
+ isBeforeToday(date) {
5209
+ const todayStart = new Date(this.today);
5210
+ todayStart.setHours(0, 0, 0, 0);
5211
+ return date < todayStart;
5212
+ }
5213
+ render() {
5214
+ const daysInMonth = this.getDaysInMonth(this.currentYear, this.currentMonth);
5215
+ const firstDayOfMonth = this.getFirstDayOfMonth(this.currentYear, this.currentMonth);
5216
+ const startOffset = (firstDayOfMonth + 6) % 7;
5217
+ const emptyCells = Array.from({ length: startOffset })
5218
+ .map((_, idx) => `<div class="medos-calendar-empty" key="empty-${idx}"></div>`)
5219
+ .join("");
5220
+ const dayCells = Array.from({ length: daysInMonth })
5221
+ .map((_, i) => {
5222
+ const dayNum = i + 1;
5223
+ const date = new Date(this.currentYear, this.currentMonth, dayNum);
5224
+ const disabled = this.config.pastDisabled && this.isBeforeToday(date);
5225
+ const isSelected = this.selectedDate && this.isSameDate(this.selectedDate, date);
5226
+ const isToday = this.isSameDate(this.today, date);
5227
+ const classes = [
5228
+ "medos-calendar-day",
5229
+ isSelected ? "medos-calendar-day-selected" : "",
5230
+ isToday && !isSelected ? "medos-calendar-day-today" : "",
5231
+ disabled ? "medos-calendar-day-disabled" : "",
5232
+ ]
5233
+ .filter(Boolean)
5234
+ .join(" ");
5235
+ return `
5236
+ <button
5237
+ class="${classes}"
5238
+ ${disabled ? "disabled" : ""}
5239
+ data-day="${dayNum}"
5240
+ data-date="${this.currentYear}-${String(this.currentMonth + 1).padStart(2, "0")}-${String(dayNum).padStart(2, "0")}"
5241
+ >
5242
+ <span>${dayNum}</span>
5243
+ ${isSelected ? '<span class="medos-calendar-dot">•</span>' : ""}
5244
+ </button>
5245
+ `;
5246
+ })
5247
+ .join("");
5248
+ this.container.innerHTML = `
5249
+ <div class="medos-calendar">
5250
+ <div class="medos-calendar-header">
5251
+ <button class="medos-calendar-nav" data-action="prev" type="button">
5252
+ ${VanillaIcons.chevronLeft(20)}
5253
+ </button>
5254
+ <p class="medos-calendar-month">
5255
+ ${VanillaCalendar.MONTHS[this.currentMonth]} ${this.currentYear}
5256
+ </p>
5257
+ <button class="medos-calendar-nav" data-action="next" type="button">
5258
+ ${VanillaIcons.chevronRight(20)}
5259
+ </button>
5260
+ </div>
5261
+
5262
+ <div class="medos-calendar-days-header">
5263
+ ${VanillaCalendar.DAYS_OF_WEEK.map((d) => `<div class="medos-calendar-day-name">${d}</div>`).join("")}
5264
+ </div>
5265
+
5266
+ <div class="medos-calendar-grid">
5267
+ ${emptyCells}
5268
+ ${dayCells}
5269
+ </div>
5270
+ </div>
5271
+ `;
5272
+ }
5273
+ attachEventListeners() {
5274
+ this.container.addEventListener("click", (e) => {
5275
+ const target = e.target;
5276
+ const navButton = target.closest(".medos-calendar-nav");
5277
+ if (navButton) {
5278
+ const action = navButton.getAttribute("data-action");
5279
+ if (action === "prev") {
5280
+ this.prevMonth();
5281
+ }
5282
+ else if (action === "next") {
5283
+ this.nextMonth();
5284
+ }
5285
+ return;
5286
+ }
5287
+ const dayButton = target.closest(".medos-calendar-day");
5288
+ if (dayButton && !dayButton.disabled) {
5289
+ const dateStr = dayButton.getAttribute("data-date");
5290
+ if (dateStr) {
5291
+ const [year, month, day] = dateStr.split("-").map(Number);
5292
+ const selectedDate = new Date(year, month - 1, day);
5293
+ this.selectDate(selectedDate);
5294
+ }
5295
+ }
5296
+ });
5297
+ }
5298
+ prevMonth() {
5299
+ if (this.currentMonth === 0) {
5300
+ this.currentMonth = 11;
5301
+ this.currentYear -= 1;
5302
+ }
5303
+ else {
5304
+ this.currentMonth -= 1;
5305
+ }
5306
+ this.render();
5307
+ this.attachEventListeners();
5308
+ }
5309
+ nextMonth() {
5310
+ if (this.currentMonth === 11) {
5311
+ this.currentMonth = 0;
5312
+ this.currentYear += 1;
5313
+ }
5314
+ else {
5315
+ this.currentMonth += 1;
5316
+ }
5317
+ this.render();
5318
+ this.attachEventListeners();
5319
+ }
5320
+ selectDate(date) {
5321
+ this.selectedDate = date;
5322
+ this.render();
5323
+ this.attachEventListeners();
5324
+ this.config.onSelect?.(date);
5325
+ }
5326
+ setSelectedDate(date) {
5327
+ if (date) {
5328
+ this.selectedDate = new Date(date);
5329
+ this.selectedDate.setHours(0, 0, 0, 0);
5330
+ this.currentMonth = this.selectedDate.getMonth();
5331
+ this.currentYear = this.selectedDate.getFullYear();
5332
+ }
5333
+ else {
5334
+ this.selectedDate = null;
5335
+ }
5336
+ this.render();
5337
+ this.attachEventListeners();
5338
+ }
5339
+ getSelectedDate() {
5340
+ return this.selectedDate;
5341
+ }
5342
+ goToDate(date) {
5343
+ this.currentMonth = date.getMonth();
5344
+ this.currentYear = date.getFullYear();
5345
+ this.render();
5346
+ this.attachEventListeners();
5347
+ }
5348
+ goToToday() {
5349
+ this.currentMonth = this.today.getMonth();
5350
+ this.currentYear = this.today.getFullYear();
5351
+ this.render();
5352
+ this.attachEventListeners();
5353
+ }
5354
+ setPastDisabled(disabled) {
5355
+ this.config.pastDisabled = disabled;
5356
+ this.render();
5357
+ this.attachEventListeners();
5358
+ }
5359
+ destroy() {
5360
+ this.container.innerHTML = "";
5361
+ }
5362
+ }
5363
+ VanillaCalendar.DAYS_OF_WEEK = [
5364
+ "Mo",
5365
+ "Tu",
5366
+ "We",
5367
+ "Th",
5368
+ "Fr",
5369
+ "Sa",
5370
+ "Su",
5371
+ ];
5372
+ VanillaCalendar.MONTHS = [
5373
+ "January",
5374
+ "February",
5375
+ "March",
5376
+ "April",
5377
+ "May",
5378
+ "June",
5379
+ "July",
5380
+ "August",
5381
+ "September",
5382
+ "October",
5383
+ "November",
5384
+ "December",
5385
+ ];
5386
+
5387
+ function injectThemedStyles() {
5388
+ if (typeof document === "undefined")
5389
+ return;
5390
+ const styleId = "medos-themed-styles";
5391
+ if (document.getElementById(styleId))
5392
+ return;
5393
+ const styleElement = document.createElement("style");
5394
+ styleElement.id = styleId;
5395
+ styleElement.innerHTML = `
5396
+ /* Default Theme Variables */
5397
+ :root {
5398
+ /* Colors */
5399
+ --medos-color-primary: #27903f;
5400
+ --medos-color-primary-dark: #1e7032;
5401
+ --medos-color-background: #ffffff;
5402
+ --medos-color-background-secondary: #f9fafb;
5403
+ --medos-color-surface: #ffffff;
5404
+ --medos-color-surface-hover: #f9fafb;
5405
+ --medos-color-text: #111827;
5406
+ --medos-color-text-secondary: #374151;
5407
+ --medos-color-text-muted: #9ca3af;
5408
+ --medos-color-text-on-primary: #ffffff;
5409
+ --medos-color-border: #e5e7eb;
5410
+ --medos-color-border-hover: #d1d5db;
5411
+ --medos-color-border-focus: #27903f;
5412
+ --medos-color-error: #ef4444;
5413
+ --medos-color-error-background: #fee2e2;
5414
+ --medos-color-error-border: #fca5a5;
5415
+ --medos-color-success: #10b981;
5416
+ --medos-color-success-background: #ecfdf5;
5417
+
5418
+ /* Typography */
5419
+ --medos-typography-font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
5420
+ --medos-typography-font-size-xs: 12px;
5421
+ --medos-typography-font-size-sm: 14px;
5422
+ --medos-typography-font-size-md: 16px;
5423
+ --medos-typography-font-size-lg: 18px;
5424
+ --medos-typography-font-size-xl: 20px;
5425
+ --medos-typography-font-weight-normal: 400;
5426
+ --medos-typography-font-weight-medium: 500;
5427
+ --medos-typography-font-weight-semibold: 600;
5428
+
5429
+ /* Spacing */
5430
+ --medos-spacing-xs: 4px;
5431
+ --medos-spacing-sm: 8px;
5432
+ --medos-spacing-md: 12px;
5433
+ --medos-spacing-lg: 16px;
5434
+ --medos-spacing-xl: 20px;
5435
+ --medos-spacing-2xl: 24px;
5436
+
5437
+ /* Radius */
5438
+ --medos-radius-sm: 4px;
5439
+ --medos-radius-md: 8px;
5440
+ --medos-radius-lg: 12px;
5441
+ --medos-radius-full: 999px;
5442
+
5443
+ /* Shadows */
5444
+ --medos-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
5445
+ --medos-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
5446
+ --medos-shadow-lg: 0 8px 24px rgba(16, 24, 40, 0.08);
5447
+
5448
+ /* Transitions */
5449
+ --medos-transition-normal: 200ms ease-in-out;
5450
+ }
5451
+
5452
+ /* Container & Card */
5453
+ .medos-appointment-container {
5454
+ display: flex;
5455
+ justify-content: center;
5456
+ padding: var(--medos-spacing-xl, 20px);
5457
+ font-family: var(--medos-typography-font-family);
5458
+ background: var(--medos-color-background, #f6f8fa);
5459
+ }
5460
+
5461
+ .medos-appointment-card {
5462
+ width: 100%;
5463
+ max-width: 720px;
5464
+ background: var(--medos-color-surface, #fff);
5465
+ border-radius: var(--medos-radius-lg, 12px);
5466
+ box-shadow: var(--medos-shadow-lg);
5467
+ padding: var(--medos-spacing-2xl, 24px);
5468
+ box-sizing: border-box;
5469
+ }
5470
+
5471
+ /* Section Cards */
5472
+ .medos-section-card {
5473
+ background: var(--medos-color-surface, #fff);
5474
+ border: 1px solid var(--medos-color-border, #e5e7eb);
5475
+ border-radius: var(--medos-radius-lg, 12px);
5476
+ margin-bottom: var(--medos-spacing-lg, 16px);
5477
+ overflow: visible;
5478
+ }
5479
+
5480
+ .medos-section-header {
5481
+ display: flex;
5482
+ align-items: center;
5483
+ gap: var(--medos-spacing-sm, 8px);
5484
+ padding: var(--medos-spacing-md, 12px) var(--medos-spacing-lg, 16px);
5485
+ background: var(--medos-color-background-secondary, #f9fafb);
5486
+ border-bottom: 1px solid var(--medos-color-border, #e5e7eb);
5487
+ border-radius: var(--medos-radius-lg, 12px) var(--medos-radius-lg, 12px) 0 0;
5488
+ }
5489
+
5490
+ .medos-section-header svg {
5491
+ color: var(--medos-color-primary, #27903f);
5492
+ flex-shrink: 0;
5493
+ }
5494
+
5495
+ .medos-section-title {
5496
+ font-size: var(--medos-typography-font-size-sm, 14px);
5497
+ font-weight: var(--medos-typography-font-weight-semibold, 600);
5498
+ color: var(--medos-color-text, #111827);
5499
+ margin: 0;
5500
+ }
5501
+
5502
+ .medos-section-body {
5503
+ padding: var(--medos-spacing-lg, 16px);
5504
+ }
5505
+
5506
+ .medos-section-description {
5507
+ margin: 0 0 var(--medos-spacing-md, 12px) 0;
5508
+ font-size: var(--medos-typography-font-size-sm, 14px);
5509
+ color: var(--medos-color-text-secondary, #6b7280);
5510
+ }
5511
+
5512
+ /* Form Groups */
5513
+ .medos-form-group {
5514
+ margin-bottom: var(--medos-spacing-md, 12px);
5515
+ }
5516
+
5517
+ .medos-form-row {
5518
+ display: flex;
5519
+ gap: var(--medos-spacing-md, 12px);
5520
+ }
5521
+
5522
+ .medos-form-row .medos-form-group {
5523
+ flex: 1;
5524
+ }
5525
+
5526
+ .medos-label {
5527
+ display: block;
5528
+ font-size: var(--medos-typography-font-size-xs, 13px);
5529
+ font-weight: var(--medos-typography-font-weight-medium, 500);
5530
+ color: var(--medos-color-text-secondary, #374151);
5531
+ margin-bottom: var(--medos-spacing-xs, 6px);
5532
+ }
5533
+
5534
+ .medos-required {
5535
+ color: var(--medos-color-error, #ef4444);
5536
+ }
5537
+
5538
+ /* Inputs */
5539
+ .medos-input,
5540
+ .medos-textarea {
5541
+ width: 100%;
5542
+ padding: var(--medos-spacing-sm, 10px) var(--medos-spacing-md, 12px);
5543
+ border-radius: var(--medos-radius-md, 8px);
5544
+ border: 1px solid var(--medos-color-border, #e5e7eb);
5545
+ outline: none;
5546
+ font-size: var(--medos-typography-font-size-sm, 14px);
5547
+ box-sizing: border-box;
5548
+ font-family: inherit;
5549
+ color: var(--medos-color-text, #111827);
5550
+ background: var(--medos-color-surface, #fff);
5551
+ transition: var(--medos-transition-normal);
5552
+ }
5553
+
5554
+ .medos-input:focus,
5555
+ .medos-textarea:focus {
5556
+ border-color: var(--medos-color-primary, #27903f);
5557
+ box-shadow: 0 0 0 2px rgba(39, 144, 63, 0.15);
5558
+ }
5559
+
5560
+ /* Buttons */
5561
+ .medos-btn {
5562
+ display: inline-flex;
5563
+ align-items: center;
5564
+ justify-content: center;
5565
+ gap: var(--medos-spacing-xs, 6px);
5566
+ padding: var(--medos-spacing-sm, 10px) var(--medos-spacing-lg, 16px);
5567
+ border-radius: var(--medos-radius-md, 8px);
5568
+ font-size: var(--medos-typography-font-size-sm, 14px);
5569
+ font-weight: var(--medos-typography-font-weight-semibold, 600);
5570
+ cursor: pointer;
5571
+ border: none;
5572
+ transition: var(--medos-transition-normal);
5573
+ font-family: inherit;
5574
+ }
5575
+
5576
+ .medos-btn-primary {
5577
+ background: var(--medos-color-primary, #27903f);
5578
+ color: var(--medos-color-text-on-primary, #fff);
5579
+ }
5580
+
5581
+ .medos-btn-primary:hover:not(:disabled) {
5582
+ background: var(--medos-color-primary-dark, #1e7032);
5583
+ }
5584
+
5585
+ .medos-btn:disabled {
5586
+ opacity: 0.5;
5587
+ cursor: not-allowed;
5588
+ pointer-events: none;
5589
+ }
5590
+
5591
+ .medos-btn-secondary {
5592
+ background: var(--medos-color-surface, #fff);
5593
+ color: var(--medos-color-text, #111827);
5594
+ border: 1px solid var(--medos-color-border, #e5e7eb);
5595
+ }
5596
+
5597
+ .medos-actions {
5598
+ display: flex;
5599
+ justify-content: flex-end;
5600
+ gap: var(--medos-spacing-md, 12px);
5601
+ margin-top: var(--medos-spacing-lg, 16px);
5602
+ }
5603
+
5604
+ /* Radio Options */
5605
+ .medos-radio-option {
5606
+ display: flex;
5607
+ align-items: center;
5608
+ gap: var(--medos-spacing-sm, 8px);
5609
+ padding: var(--medos-spacing-sm, 10px) var(--medos-spacing-md, 12px);
5610
+ border: 1px solid var(--medos-color-border, #e5e7eb);
5611
+ border-radius: var(--medos-radius-md, 8px);
5612
+ cursor: pointer;
5613
+ transition: var(--medos-transition-normal);
5614
+ margin-bottom: var(--medos-spacing-xs, 4px);
5615
+ }
5616
+
5617
+ .medos-radio-option:hover {
5618
+ border-color: var(--medos-color-primary, #27903f);
5619
+ background: var(--medos-color-surface-hover, #f9fafb);
5620
+ }
5621
+
5622
+ .medos-radio-option.selected {
5623
+ border-color: var(--medos-color-primary, #27903f);
5624
+ background: rgba(39, 144, 63, 0.05);
5625
+ }
5626
+
5627
+ /* Time Slots */
5628
+ .medos-slots-grid {
5629
+ display: grid;
5630
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
5631
+ gap: var(--medos-spacing-sm, 8px);
5632
+ }
5633
+
5634
+ .medos-slot-card {
5635
+ display: flex;
5636
+ align-items: center;
5637
+ justify-content: center;
5638
+ gap: var(--medos-spacing-xs, 4px);
5639
+ padding: var(--medos-spacing-sm, 10px) var(--medos-spacing-md, 12px);
5640
+ border: 1px solid var(--medos-color-border, #e5e7eb);
5641
+ border-radius: var(--medos-radius-md, 8px);
5642
+ cursor: pointer;
5643
+ transition: var(--medos-transition-normal);
5644
+ position: relative;
5645
+ }
5646
+
5647
+ .medos-slot-card:hover {
5648
+ border-color: var(--medos-color-primary, #27903f);
5649
+ background: var(--medos-color-surface-hover, #f9fafb);
5650
+ }
5651
+
5652
+ .medos-slot-card.selected {
5653
+ border-color: var(--medos-color-primary, #27903f);
5654
+ background: rgba(39, 144, 63, 0.1);
5655
+ }
5656
+
5657
+ /* Phone Input */
5658
+ .medos-phone-input-row {
5659
+ display: flex;
5660
+ gap: var(--medos-spacing-sm, 8px);
5661
+ align-items: flex-start;
5662
+ }
5663
+
5664
+ .medos-country-code-wrapper {
5665
+ width: 140px;
5666
+ flex-shrink: 0;
5667
+ }
5668
+
5669
+ .medos-phone-wrapper {
5670
+ flex: 1;
5671
+ }
5672
+
5673
+ /* VanillaSelect Styles */
5674
+ .vanilla-select-container {
5675
+ position: relative;
5676
+ width: 100%;
5677
+ z-index: 1;
5678
+ }
5679
+
5680
+ .vanilla-select-container.open {
5681
+ z-index: 10000;
5682
+ }
5683
+
5684
+ .vanilla-select-display {
5685
+ width: 100%;
5686
+ padding: var(--medos-spacing-sm, 10px) var(--medos-spacing-md, 12px);
5687
+ border-radius: var(--medos-radius-md, 8px);
5688
+ border: 1px solid var(--medos-color-border, #e5e7eb);
5689
+ background: var(--medos-color-surface, #fff);
5690
+ cursor: pointer;
5691
+ display: flex;
5692
+ justify-content: space-between;
5693
+ align-items: center;
5694
+ font-size: var(--medos-typography-font-size-sm, 14px);
5695
+ color: var(--medos-color-text, #111827);
5696
+ box-sizing: border-box;
5697
+ transition: var(--medos-transition-normal);
5698
+ }
5699
+
5700
+ .vanilla-select-display:hover {
5701
+ border-color: var(--medos-color-border-hover, #d1d5db);
5702
+ }
5703
+
5704
+ .vanilla-select-display.open {
5705
+ border-color: var(--medos-color-primary, #27903f);
5706
+ box-shadow: 0 0 0 2px rgba(39, 144, 63, 0.15);
5707
+ }
5708
+
5709
+ .vanilla-select-dropdown {
5710
+ position: absolute;
5711
+ top: 100%;
5712
+ left: 0;
5713
+ right: 0;
5714
+ background: var(--medos-color-surface, #fff);
5715
+ border: 1px solid var(--medos-color-border, #e5e7eb);
5716
+ border-radius: var(--medos-radius-md, 8px);
5717
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
5718
+ z-index: 9999;
5719
+ max-height: 200px;
5720
+ overflow-y: auto;
5721
+ margin-top: 4px;
5722
+ }
5723
+
5724
+ .vanilla-select-option {
5725
+ padding: var(--medos-spacing-sm, 10px) var(--medos-spacing-md, 12px);
5726
+ cursor: pointer;
5727
+ font-size: var(--medos-typography-font-size-sm, 14px);
5728
+ color: var(--medos-color-text, #111827);
5729
+ display: flex;
5730
+ justify-content: space-between;
5731
+ align-items: center;
5732
+ transition: var(--medos-transition-normal);
5733
+ }
5734
+
5735
+ .vanilla-select-option:hover {
5736
+ background: var(--medos-color-surface-hover, #f9fafb);
5737
+ }
5738
+
5739
+ .vanilla-select-option.selected {
5740
+ background: rgba(39, 144, 63, 0.1);
5741
+ color: var(--medos-color-primary, #27903f);
5742
+ }
5743
+
5744
+ /* VanillaCalendar Styles */
5745
+ .vanilla-calendar-container {
5746
+ width: 100%;
5747
+ background: var(--medos-color-surface, #fff);
5748
+ border: 1px solid var(--medos-color-border, #e5e7eb);
5749
+ border-radius: var(--medos-radius-md, 8px);
5750
+ padding: var(--medos-spacing-lg, 16px);
5751
+ }
5752
+
5753
+ .vanilla-calendar-header {
5754
+ display: flex;
5755
+ justify-content: space-between;
5756
+ align-items: center;
5757
+ margin-bottom: var(--medos-spacing-lg, 16px);
5758
+ }
5759
+
5760
+ .vanilla-calendar-nav-btn {
5761
+ background: none;
5762
+ border: none;
5763
+ padding: var(--medos-spacing-xs, 4px);
5764
+ cursor: pointer;
5765
+ border-radius: var(--medos-radius-sm, 4px);
5766
+ display: flex;
5767
+ align-items: center;
5768
+ justify-content: center;
5769
+ transition: var(--medos-transition-normal);
5770
+ }
5771
+
5772
+ .vanilla-calendar-nav-btn:hover {
5773
+ background: var(--medos-color-surface-hover, #f9fafb);
5774
+ }
5775
+
5776
+ .vanilla-calendar-month-year {
5777
+ font-size: var(--medos-typography-font-size-md, 16px);
5778
+ font-weight: var(--medos-typography-font-weight-semibold, 600);
5779
+ color: var(--medos-color-text, #111827);
5780
+ }
5781
+
5782
+ .vanilla-calendar-grid {
5783
+ display: grid;
5784
+ grid-template-columns: repeat(7, 1fr);
5785
+ gap: 2px;
5786
+ }
5787
+
5788
+ .vanilla-calendar-day-header {
5789
+ text-align: center;
5790
+ font-size: var(--medos-typography-font-size-xs, 12px);
5791
+ font-weight: var(--medos-typography-font-weight-medium, 500);
5792
+ color: var(--medos-color-text-secondary, #6b7280);
5793
+ padding: var(--medos-spacing-sm, 8px);
5794
+ }
5795
+
5796
+ .vanilla-calendar-day {
5797
+ text-align: center;
5798
+ padding: var(--medos-spacing-sm, 8px);
5799
+ cursor: pointer;
5800
+ border-radius: var(--medos-radius-sm, 4px);
5801
+ font-size: var(--medos-typography-font-size-sm, 14px);
5802
+ transition: var(--medos-transition-normal);
5803
+ min-height: 32px;
5804
+ display: flex;
5805
+ align-items: center;
5806
+ justify-content: center;
5807
+ }
5808
+
5809
+ .vanilla-calendar-day:hover:not(.disabled):not(.other-month) {
5810
+ background: var(--medos-color-surface-hover, #f9fafb);
5811
+ }
5812
+
5813
+ .vanilla-calendar-day.selected {
5814
+ background: var(--medos-color-primary, #27903f);
5815
+ color: var(--medos-color-text-on-primary, #fff);
5816
+ }
5817
+
5818
+ .vanilla-calendar-day.disabled {
5819
+ color: var(--medos-color-text-muted, #9ca3af);
5820
+ cursor: not-allowed;
5821
+ }
5822
+
5823
+ .vanilla-calendar-day.other-month {
5824
+ color: var(--medos-color-text-muted, #9ca3af);
5825
+ }
5826
+
5827
+ .vanilla-calendar-day.today {
5828
+ background: rgba(39, 144, 63, 0.1);
5829
+ font-weight: var(--medos-typography-font-weight-semibold, 600);
5830
+ }
5831
+ `;
5832
+ document.head.appendChild(styleElement);
5833
+ }
5834
+
4234
5835
  class AppointmentCalendarWidget {
4235
5836
  constructor(container, options) {
4236
5837
  this.mounted = true;
4237
5838
  this.doctors = [];
5839
+ this.addressSelect = null;
5840
+ this.doctorSelect = null;
5841
+ this.calendar = null;
5842
+ this.countryCodeSelect = null;
5843
+ this.genderSelect = null;
5844
+ this.bloodGroupSelect = null;
5845
+ injectThemedStyles();
4238
5846
  if (typeof container === "string") {
4239
5847
  const el = document.getElementById(container);
4240
5848
  if (!el) {
@@ -4422,8 +6030,27 @@
4422
6030
  return false;
4423
6031
  return true;
4424
6032
  }
6033
+ updateSubmitButtonState() {
6034
+ const submitBtn = this.container.querySelector("#medos-btn-submit");
6035
+ if (submitBtn) {
6036
+ const canSubmit = this.state.patientName &&
6037
+ this.state.patientAddress &&
6038
+ this.state.patientCity &&
6039
+ this.state.patientState &&
6040
+ this.state.patientCountry &&
6041
+ this.state.patientZipcode &&
6042
+ this.state.patientEmail &&
6043
+ this.state.patientAge &&
6044
+ this.state.otpVerified;
6045
+ submitBtn.disabled = !(canSubmit && !this.state.loading);
6046
+ }
6047
+ }
4425
6048
  async sendOtp() {
4426
6049
  this.setState({ error: null });
6050
+ console.log("sendOtp called - Current state:", {
6051
+ countryCode: this.state.countryCode,
6052
+ patientPhone: this.state.patientPhone,
6053
+ });
4427
6054
  if (!this.state.countryCode) {
4428
6055
  this.setState({ error: "Please enter country code." });
4429
6056
  return;
@@ -4447,6 +6074,10 @@
4447
6074
  this.setState({ otpSending: true });
4448
6075
  this.render();
4449
6076
  try {
6077
+ console.log("Sending OTP to:", {
6078
+ countryCode: this.state.countryCode,
6079
+ phoneNumber: this.state.patientPhone,
6080
+ });
4450
6081
  await PatientService.sendPhoneVerificationOtp({
4451
6082
  countryCode: this.state.countryCode,
4452
6083
  phoneNumber: this.state.patientPhone,
@@ -4454,7 +6085,10 @@
4454
6085
  this.setState({ otpSent: true, error: null });
4455
6086
  }
4456
6087
  catch (e) {
4457
- const msg = e.message || "Failed to send OTP";
6088
+ console.error("Send OTP error:", e);
6089
+ const msg = e?.response?.data?.message ||
6090
+ e?.message ||
6091
+ "Failed to send OTP. Please try again.";
4458
6092
  this.setState({ error: msg });
4459
6093
  this.options.onError?.(e);
4460
6094
  }
@@ -4478,6 +6112,11 @@
4478
6112
  this.setState({ otpVerifying: true });
4479
6113
  this.render();
4480
6114
  try {
6115
+ console.log("Verifying OTP with:", {
6116
+ countryCode: this.state.countryCode,
6117
+ phoneNumber: this.state.patientPhone,
6118
+ otpCode: this.state.otpCode,
6119
+ });
4481
6120
  await PatientService.verifyPhoneVerificationOtp({
4482
6121
  countryCode: this.state.countryCode,
4483
6122
  phoneNumber: this.state.patientPhone,
@@ -4486,7 +6125,10 @@
4486
6125
  this.setState({ otpVerified: true, error: null });
4487
6126
  }
4488
6127
  catch (e) {
4489
- const msg = e.message || "Invalid OTP code";
6128
+ console.error("OTP verification error:", e);
6129
+ const msg = e?.response?.data?.message ||
6130
+ e?.message ||
6131
+ "Invalid OTP code. Please try again.";
4490
6132
  this.setState({ error: msg });
4491
6133
  this.options.onError?.(e);
4492
6134
  }
@@ -4647,6 +6289,112 @@
4647
6289
  </div>
4648
6290
  `;
4649
6291
  this.attachEventListeners();
6292
+ this.initializeCustomComponents();
6293
+ }
6294
+ initializeCustomComponents() {
6295
+ if (this.state.step === 0) {
6296
+ const addressContainer = this.container.querySelector("#medos-address-select-container");
6297
+ if (addressContainer && this.state.addresses.length > 0) {
6298
+ const addressOptions = this.state.addresses.map((a) => ({
6299
+ value: a.id.toString(),
6300
+ label: a.label || `Address ${a.id}`,
6301
+ }));
6302
+ this.addressSelect = new VanillaSelect(addressContainer, addressOptions, {
6303
+ placeholder: "Select a location",
6304
+ onValueChange: (value) => {
6305
+ this.handleAddressChange(Number(value) || null);
6306
+ },
6307
+ });
6308
+ if (this.state.selectedAddress) {
6309
+ this.addressSelect.setValue(this.state.selectedAddress.toString());
6310
+ }
6311
+ }
6312
+ const doctorContainer = this.container.querySelector("#medos-doctor-select-container");
6313
+ if (doctorContainer && this.doctors.length > 0) {
6314
+ const doctorOptions = this.doctors.map((d) => ({
6315
+ value: d.id.toString(),
6316
+ label: d.name + (d.specialty ? ` • ${d.specialty}` : ""),
6317
+ }));
6318
+ this.doctorSelect = new VanillaSelect(doctorContainer, doctorOptions, {
6319
+ placeholder: "Select a doctor",
6320
+ onValueChange: (value) => {
6321
+ this.state.selectedDoctor = Number(value) || null;
6322
+ const selectedDoc = this.doctors.find((d) => d.id === this.state.selectedDoctor);
6323
+ if (selectedDoc && selectedDoc.consultationCharge) {
6324
+ this.state.consultationCharge = selectedDoc.consultationCharge;
6325
+ }
6326
+ this.render();
6327
+ },
6328
+ });
6329
+ if (this.state.selectedDoctor) {
6330
+ this.doctorSelect.setValue(this.state.selectedDoctor.toString());
6331
+ }
6332
+ }
6333
+ }
6334
+ if (this.state.step === 1) {
6335
+ const calendarContainer = this.container.querySelector("#medos-calendar-container");
6336
+ if (calendarContainer) {
6337
+ this.calendar = new VanillaCalendar(calendarContainer, {
6338
+ selectedDate: this.state.selectedDate || undefined,
6339
+ pastDisabled: true,
6340
+ onSelect: (date) => {
6341
+ this.state.selectedDate = date;
6342
+ this.render();
6343
+ },
6344
+ });
6345
+ }
6346
+ }
6347
+ if (this.state.step === 3) {
6348
+ const countryCodeContainer = this.container.querySelector("#medos-country-code-container");
6349
+ if (countryCodeContainer) {
6350
+ const countryOptions = COUNTRY_CODES.map((c) => ({
6351
+ value: c.code,
6352
+ label: c.label,
6353
+ }));
6354
+ this.countryCodeSelect = new VanillaSelect(countryCodeContainer, countryOptions, {
6355
+ placeholder: "Country",
6356
+ onValueChange: (value) => {
6357
+ this.state.countryCode = value;
6358
+ const sendOtpBtn = this.container.querySelector("#medos-btn-send-otp");
6359
+ if (sendOtpBtn) {
6360
+ const canSendOtp = this.state.countryCode &&
6361
+ this.state.patientPhone.length >= 10;
6362
+ sendOtpBtn.disabled = !canSendOtp;
6363
+ }
6364
+ },
6365
+ });
6366
+ if (this.state.countryCode) {
6367
+ this.countryCodeSelect.setValue(this.state.countryCode);
6368
+ }
6369
+ }
6370
+ }
6371
+ if (this.state.step === 4) {
6372
+ const genderContainer = this.container.querySelector("#medos-gender-container");
6373
+ if (genderContainer) {
6374
+ this.genderSelect = new VanillaSelect(genderContainer, GENDER_OPTIONS, {
6375
+ placeholder: "Select gender",
6376
+ onValueChange: (value) => {
6377
+ this.state.patientGender = value;
6378
+ this.updateSubmitButtonState();
6379
+ },
6380
+ });
6381
+ if (this.state.patientGender) {
6382
+ this.genderSelect.setValue(this.state.patientGender);
6383
+ }
6384
+ }
6385
+ const bloodGroupContainer = this.container.querySelector("#medos-blood-group-container");
6386
+ if (bloodGroupContainer) {
6387
+ this.bloodGroupSelect = new VanillaSelect(bloodGroupContainer, BLOOD_GROUP_OPTIONS, {
6388
+ placeholder: "Select blood group (optional)",
6389
+ onValueChange: (value) => {
6390
+ this.state.bloodGroup = value;
6391
+ },
6392
+ });
6393
+ if (this.state.bloodGroup) {
6394
+ this.bloodGroupSelect.setValue(this.state.bloodGroup);
6395
+ }
6396
+ }
6397
+ }
4650
6398
  }
4651
6399
  renderStep() {
4652
6400
  switch (this.state.step) {
@@ -4669,72 +6417,122 @@
4669
6417
  renderStep0() {
4670
6418
  const canProceed = this.canProceedFromMergedStep();
4671
6419
  return `
4672
- <div class="medos-appointment-section">
4673
- <div class="medos-appointment-form-grid-2col">
4674
- <div>
4675
- <label class="medos-appointment-label">Address</label>
4676
- ${this.state.addresses.length === 0
4677
- ? '<div class="medos-appointment-small-muted">No addresses available</div>'
4678
- : this.state.addresses.length === 1
4679
- ? `<div class="medos-appointment-small-muted" style="font-weight: 600">${this.escapeHtml(this.state.addresses[0].label || "")}</div>`
4680
- : `
4681
- <select class="medos-appointment-select" id="medos-address-select">
4682
- <option value="">-- choose address --</option>
4683
- ${this.state.addresses
4684
- .map((a) => `<option value="${this.escapeHtml(a.id.toString())}" ${this.state.selectedAddress === a.id ? "selected" : ""}>${this.escapeHtml(a.label || "")}</option>`)
4685
- .join("")}
4686
- </select>
4687
- `}
6420
+ <div class="medos-section-card">
6421
+ <div class="medos-section-header">
6422
+ ${VanillaIcons.mapPin(14)}
6423
+ <span class="medos-section-title">Location & Doctor</span>
6424
+ </div>
6425
+ <div class="medos-section-body">
6426
+ <div class="medos-form-group">
6427
+ <label class="medos-label">Preferred Location <span class="medos-required">*</span></label>
6428
+ <div id="medos-address-select-container"></div>
4688
6429
  </div>
4689
- <div>
4690
- <label class="medos-appointment-label">Doctor</label>
4691
- ${this.doctors.length === 0
4692
- ? '<div class="medos-appointment-small-muted">No doctors available</div>'
4693
- : this.doctors.length === 1
4694
- ? `<div class="medos-appointment-small-muted" style="font-weight: 600">${this.escapeHtml(this.doctors[0].name)}${this.doctors[0].specialty
4695
- ? ` • ${this.escapeHtml(this.doctors[0].specialty)}`
4696
- : ""}</div>`
4697
- : `
4698
- <select class="medos-appointment-select" id="medos-doctor-select">
4699
- <option value="">-- choose doctor --</option>
4700
- ${this.doctors
4701
- .map((d) => `<option value="${this.escapeHtml(d.id.toString())}" ${this.state.selectedDoctor === d.id ? "selected" : ""}>${this.escapeHtml(d.name)}${d.specialty
4702
- ? ` (${this.escapeHtml(d.specialty)})`
4703
- : ""}</option>`)
4704
- .join("")}
4705
- </select>
4706
- `}
6430
+ <div class="medos-form-group">
6431
+ <label class="medos-label">Preferred Doctor <span class="medos-required">*</span></label>
6432
+ <div id="medos-doctor-select-container"></div>
6433
+ </div>
6434
+ <div class="medos-form-group">
6435
+ <label class="medos-label">Chief Complaint <span class="medos-optional">(optional)</span></label>
6436
+ <textarea
6437
+ class="medos-textarea"
6438
+ id="medos-chief-complaint"
6439
+ placeholder="Enter Chief Complaint or Appointment Notes"
6440
+ ></textarea>
4707
6441
  </div>
4708
6442
  </div>
4709
- <div class="medos-appointment-actions">
4710
- <button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-cancel">Cancel</button>
4711
- <button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-next" ${!canProceed ? "disabled" : ""} style="opacity: ${canProceed ? 1 : 0.6}">Next</button>
4712
- </div>
6443
+ </div>
6444
+ <div class="medos-actions">
6445
+ <button class="medos-btn medos-btn-primary" id="medos-btn-next" ${!canProceed ? "disabled" : ""}>Next</button>
4713
6446
  </div>
4714
6447
  `;
4715
6448
  }
4716
6449
  renderStep1() {
4717
6450
  const dateStr = formatDateToISO(this.state.selectedDate);
6451
+ const selectedDoctor = this.doctors.find((d) => d.id === this.state.selectedDoctor);
6452
+ const selectedDoctorData = this.doctors.find((d) => d.id === this.state.selectedDoctor);
6453
+ const consultationCharge = selectedDoctorData?.consultationCharge ||
6454
+ selectedDoctor?.consultationCharge ||
6455
+ this.state.consultationCharge ||
6456
+ "N/A";
4718
6457
  return `
4719
- <div class="medos-appointment-section">
4720
- <label class="medos-appointment-label">Select Date</label>
4721
- <input type="date" class="medos-appointment-input" id="medos-date-input" value="${this.escapeHtml(dateStr)}" />
4722
- <div class="medos-appointment-actions">
4723
- <button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-back">Back</button>
4724
- <button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-next" ${!dateStr ? "disabled" : ""} style="opacity: ${dateStr ? 1 : 0.6}">Next</button>
6458
+ <div class="medos-section-card">
6459
+ <div class="medos-section-header">
6460
+ ${VanillaIcons.consultationType(14)}
6461
+ <span class="medos-section-title">Consultation Type</span>
6462
+ </div>
6463
+ <div class="medos-section-body">
6464
+ <div class="medos-consultation-options">
6465
+ <label class="medos-radio-option ${this.state.consultationMode === "OFFLINE" ? "selected" : ""}">
6466
+ <input
6467
+ type="radio"
6468
+ name="consultationMode"
6469
+ value="OFFLINE"
6470
+ ${this.state.consultationMode === "OFFLINE" ? "checked" : ""}
6471
+ class="medos-radio-input"
6472
+ />
6473
+ <span class="medos-radio-label">In-Person Visit</span>
6474
+ </label>
6475
+ <label class="medos-radio-option ${this.state.consultationMode === "ONLINE" ? "selected" : ""}">
6476
+ <input
6477
+ type="radio"
6478
+ name="consultationMode"
6479
+ value="ONLINE"
6480
+ ${this.state.consultationMode === "ONLINE" ? "checked" : ""}
6481
+ class="medos-radio-input"
6482
+ />
6483
+ <span class="medos-radio-label">Online Consultation</span>
6484
+ </label>
6485
+ </div>
6486
+ <div class="medos-consultation-charge">
6487
+ <span class="medos-charge-label">Consultation Charge:</span>
6488
+ <span class="medos-charge-value">${consultationCharge !== "N/A"
6489
+ ? "₹" + consultationCharge
6490
+ : consultationCharge}</span>
6491
+ </div>
6492
+ </div>
6493
+ </div>
6494
+
6495
+ <div class="medos-section-card">
6496
+ <div class="medos-section-header">
6497
+ ${VanillaIcons.dateTime(14)}
6498
+ <span class="medos-section-title">Select Date</span>
6499
+ </div>
6500
+ <div class="medos-section-body">
6501
+ <div id="medos-calendar-container"></div>
4725
6502
  </div>
4726
6503
  </div>
6504
+
6505
+ <div class="medos-actions">
6506
+ <button class="medos-btn medos-btn-secondary" id="medos-btn-back">Back</button>
6507
+ <button class="medos-btn medos-btn-primary" id="medos-btn-next" ${dateStr ? "" : "disabled"}>Next</button>
6508
+ </div>
4727
6509
  `;
4728
6510
  }
4729
6511
  renderStep2() {
6512
+ const dateDisplay = this.state.selectedDate
6513
+ ? this.state.selectedDate.toLocaleDateString("en-US", {
6514
+ weekday: "long",
6515
+ year: "numeric",
6516
+ month: "long",
6517
+ day: "numeric",
6518
+ })
6519
+ : "";
4730
6520
  return `
4731
- <div class="medos-appointment-section">
4732
- <label class="medos-appointment-label">Choose Time Slot</label>
4733
- ${this.state.slots.length === 0
4734
- ? '<div class="medos-appointment-small-muted">No slots available for selected date</div>'
6521
+ <div class="medos-section-card">
6522
+ <div class="medos-section-header">
6523
+ ${VanillaIcons.clock(14)}
6524
+ <span class="medos-section-title">Select Time Slot</span>
6525
+ </div>
6526
+ <div class="medos-section-body">
6527
+ <div class="medos-selected-date-display">
6528
+ ${VanillaIcons.dateTime(16)}
6529
+ <span>${dateDisplay}</span>
6530
+ </div>
6531
+ ${this.state.slots.length === 0
6532
+ ? '<div class="medos-empty-slots">No slots available for selected date</div>'
4735
6533
  : `
4736
- <div class="medos-appointment-slot-grid">
4737
- ${this.state.slots
6534
+ <div class="medos-slots-grid">
6535
+ ${this.state.slots
4738
6536
  .map((s) => {
4739
6537
  const start = new Date(s.start).toLocaleTimeString([], {
4740
6538
  hour: "2-digit",
@@ -4747,19 +6545,28 @@
4747
6545
  const selected = this.state.selectedSlot?.start === s.start &&
4748
6546
  this.state.selectedSlot?.end === s.end;
4749
6547
  return `
4750
- <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)}">
4751
- <div class="medos-appointment-slot-time">${start} ${end}</div>
4752
- </div>
4753
- `;
6548
+ <div class="medos-slot-card ${selected ? "selected" : ""}"
6549
+ data-slot-id="${this.escapeHtml(s.id || `${s.start}-${s.end}`)}"
6550
+ data-slot-start="${this.escapeHtml(s.start)}"
6551
+ data-slot-end="${this.escapeHtml(s.end)}">
6552
+ <span class="medos-slot-time">${start}</span>
6553
+ <span class="medos-slot-separator">-</span>
6554
+ <span class="medos-slot-time">${end}</span>
6555
+ ${selected
6556
+ ? `<span class="medos-slot-check">${VanillaIcons.check(14)}</span>`
6557
+ : ""}
6558
+ </div>
6559
+ `;
4754
6560
  })
4755
6561
  .join("")}
4756
- </div>
4757
- `}
4758
- <div class="medos-appointment-actions">
4759
- <button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-back">Back</button>
4760
- <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>
6562
+ </div>
6563
+ `}
4761
6564
  </div>
4762
6565
  </div>
6566
+ <div class="medos-actions">
6567
+ <button class="medos-btn medos-btn-secondary" id="medos-btn-back">Back</button>
6568
+ <button class="medos-btn medos-btn-primary" id="medos-btn-next" ${this.state.selectedSlot ? "" : "disabled"} style="opacity: ${this.state.selectedSlot ? 1 : 0.6}">Next</button>
6569
+ </div>
4763
6570
  `;
4764
6571
  }
4765
6572
  renderStep3() {
@@ -4768,47 +6575,87 @@
4768
6575
  const canSendOtp = countryCodeValid && phoneValid && !this.state.otpSending;
4769
6576
  if (!this.state.otpSent) {
4770
6577
  return `
4771
- <div class="medos-appointment-section">
4772
- <label class="medos-appointment-label">Country Code</label>
4773
- <input type="text" class="medos-appointment-input" id="medos-country-code" placeholder="+91" value="${this.escapeHtml(this.state.countryCode)}" />
4774
- ${this.state.countryCode && !countryCodeValid
4775
- ? '<div class="medos-appointment-validation-error">Please enter a valid country code (e.g., +91, +1)</div>'
4776
- : ""}
4777
- <label class="medos-appointment-label" style="margin-top: 12px">Phone Number</label>
4778
- <input type="tel" class="medos-appointment-input" id="medos-phone" placeholder="9311840587" value="${this.escapeHtml(this.state.patientPhone)}" maxlength="15" />
4779
- ${this.state.patientPhone && !phoneValid
4780
- ? '<div class="medos-appointment-validation-error">Phone number should be 7-15 digits</div>'
6578
+ <div class="medos-section-card">
6579
+ <div class="medos-section-header">
6580
+ ${VanillaIcons.phone(14)}
6581
+ <span class="medos-section-title">Phone Verification</span>
6582
+ </div>
6583
+ <div class="medos-section-body">
6584
+ <p class="medos-section-description">Please enter your phone number for verification</p>
6585
+ <div class="medos-phone-input-row">
6586
+ <div class="medos-country-code-wrapper">
6587
+ <div id="medos-country-code-container"></div>
6588
+ </div>
6589
+ <div class="medos-phone-wrapper">
6590
+ <input
6591
+ type="tel"
6592
+ class="medos-input"
6593
+ id="medos-phone"
6594
+ placeholder="Enter phone number"
6595
+ value="${this.escapeHtml(this.state.patientPhone)}"
6596
+ maxlength="15"
6597
+ />
6598
+ </div>
6599
+ </div>
6600
+ ${this.state.patientPhone && !phoneValid
6601
+ ? '<div class="medos-validation-error">Phone number should be 7-15 digits</div>'
4781
6602
  : ""}
4782
- <div class="medos-appointment-actions">
4783
- <button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-back">Back</button>
4784
- <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>
4785
6603
  </div>
4786
6604
  </div>
6605
+ <div class="medos-actions">
6606
+ <button class="medos-btn medos-btn-secondary" id="medos-btn-back">Back</button>
6607
+ <button class="medos-btn medos-btn-primary" id="medos-btn-send-otp" ${canSendOtp ? "" : "disabled"}>${this.state.otpSending ? "Sending..." : "Send OTP"}</button>
6608
+ </div>
4787
6609
  `;
4788
6610
  }
4789
6611
  if (this.state.otpVerified) {
4790
6612
  return `
4791
- <div class="medos-appointment-section">
4792
- <div class="medos-appointment-verified">✓ Phone verified successfully</div>
4793
- <div class="medos-appointment-actions">
4794
- <button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-back">Back</button>
4795
- <button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-next">Continue to Details</button>
6613
+ <div class="medos-section-card">
6614
+ <div class="medos-section-header">
6615
+ ${VanillaIcons.phone(14)}
6616
+ <span class="medos-section-title">Phone Verification</span>
6617
+ </div>
6618
+ <div class="medos-section-body">
6619
+ <div class="medos-verified-badge">
6620
+ ${VanillaIcons.successBadge(20)}
6621
+ <span>Phone verified successfully</span>
6622
+ </div>
6623
+ <div class="medos-verified-number">${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</div>
4796
6624
  </div>
4797
6625
  </div>
6626
+ <div class="medos-actions">
6627
+ <button class="medos-btn medos-btn-secondary" id="medos-btn-back">Back</button>
6628
+ <button class="medos-btn medos-btn-primary" id="medos-btn-next">Continue</button>
6629
+ </div>
4798
6630
  `;
4799
6631
  }
4800
6632
  return `
4801
- <div class="medos-appointment-section">
4802
- <label class="medos-appointment-label">Enter OTP</label>
4803
- <input type="text" class="medos-appointment-input" id="medos-otp" placeholder="Enter 6-digit OTP" value="${this.escapeHtml(this.state.otpCode)}" maxlength="6" />
4804
- <div class="medos-appointment-otp-info">OTP sent to ${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</div>
4805
- <div class="medos-appointment-actions">
4806
- <button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-change-number">Change Number</button>
4807
- <button class="medos-appointment-btn medos-appointment-btn-primary" id="medos-btn-verify-otp" ${this.state.otpCode.length !== 6 || this.state.otpVerifying
4808
- ? "disabled"
4809
- : ""} style="opacity: ${this.state.otpCode.length === 6 && !this.state.otpVerifying ? 1 : 0.6}">${this.state.otpVerifying ? "Verifying..." : "Verify OTP"}</button>
6633
+ <div class="medos-section-card">
6634
+ <div class="medos-section-header">
6635
+ ${VanillaIcons.phone(14)}
6636
+ <span class="medos-section-title">Enter OTP</span>
6637
+ </div>
6638
+ <div class="medos-section-body">
6639
+ <p class="medos-section-description">Enter the 6-digit code sent to ${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</p>
6640
+ <div class="medos-otp-input-wrapper">
6641
+ <input
6642
+ type="text"
6643
+ class="medos-input medos-otp-input"
6644
+ id="medos-otp"
6645
+ placeholder="Enter 6-digit OTP"
6646
+ value="${this.escapeHtml(this.state.otpCode)}"
6647
+ maxlength="6"
6648
+ />
6649
+ </div>
6650
+ <button class="medos-link-btn" id="medos-btn-change-number">Change phone number</button>
4810
6651
  </div>
4811
6652
  </div>
6653
+ <div class="medos-actions">
6654
+ <button class="medos-btn medos-btn-secondary" id="medos-btn-resend-otp">Resend OTP</button>
6655
+ <button class="medos-btn medos-btn-primary" id="medos-btn-verify-otp" ${this.state.otpCode.length === 6 && !this.state.otpVerifying
6656
+ ? ""
6657
+ : "disabled"}>${this.state.otpVerifying ? "Verifying..." : "Verify OTP"}</button>
6658
+ </div>
4812
6659
  `;
4813
6660
  }
4814
6661
  renderStep4() {
@@ -4820,50 +6667,79 @@
4820
6667
  this.state.patientZipcode &&
4821
6668
  this.state.otpVerified;
4822
6669
  return `
4823
- <div class="medos-appointment-section">
4824
- <label class="medos-appointment-label">Patient Name</label>
4825
- <input type="text" class="medos-appointment-input" id="medos-patient-name" placeholder="Full name" value="${this.escapeHtml(this.state.patientName)}" />
4826
- <label class="medos-appointment-label" style="margin-top: 12px">Age</label>
4827
- <input type="number" class="medos-appointment-input" id="medos-patient-age" placeholder="Age" value="${this.escapeHtml(this.state.patientAge)}" />
4828
- <label class="medos-appointment-label" style="margin-top: 12px">Email (Optional)</label>
4829
- <input type="email" class="medos-appointment-input" id="medos-patient-email" placeholder="patient@example.com" value="${this.escapeHtml(this.state.patientEmail)}" />
4830
- <label class="medos-appointment-label" style="margin-top: 12px">Gender (Optional)</label>
4831
- <select class="medos-appointment-select" id="medos-patient-gender">
4832
- <option value="">-- Select Gender --</option>
4833
- <option value="MALE" ${this.state.patientGender === "MALE" ? "selected" : ""}>Male</option>
4834
- <option value="FEMALE" ${this.state.patientGender === "FEMALE" ? "selected" : ""}>Female</option>
4835
- <option value="OTHER" ${this.state.patientGender === "OTHER" ? "selected" : ""}>Other</option>
4836
- </select>
4837
- <label class="medos-appointment-label" style="margin-top: 12px">Address Line 1 *</label>
4838
- <input type="text" class="medos-appointment-input" id="medos-patient-address" placeholder="Street address, building name, etc." value="${this.escapeHtml(this.state.patientAddress)}" />
4839
- <div class="medos-appointment-form-grid">
4840
- <div>
4841
- <label class="medos-appointment-label">City *</label>
4842
- <input type="text" class="medos-appointment-input" id="medos-patient-city" placeholder="City" value="${this.escapeHtml(this.state.patientCity)}" />
6670
+ <div class="medos-section-card">
6671
+ <div class="medos-section-header">
6672
+ ${VanillaIcons.user(14)}
6673
+ <span class="medos-section-title">Patient Information</span>
6674
+ </div>
6675
+ <div class="medos-section-body">
6676
+ <div class="medos-form-row">
6677
+ <div class="medos-form-group medos-form-group-flex">
6678
+ <label class="medos-label">Full Name <span class="medos-required">*</span></label>
6679
+ <input type="text" class="medos-input" id="medos-patient-name" placeholder="Enter full name" value="${this.escapeHtml(this.state.patientName)}" />
6680
+ </div>
6681
+ <div class="medos-form-group medos-form-group-small">
6682
+ <label class="medos-label">Age</label>
6683
+ <input type="number" class="medos-input" id="medos-patient-age" placeholder="Age" value="${this.escapeHtml(this.state.patientAge)}" />
6684
+ </div>
6685
+ </div>
6686
+ <div class="medos-form-row">
6687
+ <div class="medos-form-group medos-form-group-flex">
6688
+ <label class="medos-label">Email</label>
6689
+ <input type="email" class="medos-input" id="medos-patient-email" placeholder="patient@example.com" value="${this.escapeHtml(this.state.patientEmail)}" />
6690
+ </div>
6691
+ <div class="medos-form-group medos-form-group-small">
6692
+ <label class="medos-label">Gender</label>
6693
+ <div id="medos-gender-container"></div>
6694
+ </div>
4843
6695
  </div>
4844
- <div>
4845
- <label class="medos-appointment-label">State *</label>
4846
- <input type="text" class="medos-appointment-input" id="medos-patient-state" placeholder="State" value="${this.escapeHtml(this.state.patientState)}" />
6696
+ <div class="medos-form-group">
6697
+ <label class="medos-label">Blood Group <span class="medos-optional">(optional)</span></label>
6698
+ <div id="medos-blood-group-container"></div>
4847
6699
  </div>
4848
6700
  </div>
4849
- <div class="medos-appointment-form-grid">
4850
- <div>
4851
- <label class="medos-appointment-label">Country *</label>
4852
- <input type="text" class="medos-appointment-input" id="medos-patient-country" placeholder="Country" value="${this.escapeHtml(this.state.patientCountry)}" />
6701
+ </div>
6702
+
6703
+ <div class="medos-section-card">
6704
+ <div class="medos-section-header">
6705
+ ${VanillaIcons.mapPin(14)}
6706
+ <span class="medos-section-title">Address Details</span>
6707
+ </div>
6708
+ <div class="medos-section-body">
6709
+ <div class="medos-form-group">
6710
+ <label class="medos-label">Address Line 1 <span class="medos-required">*</span></label>
6711
+ <input type="text" class="medos-input" id="medos-patient-address" placeholder="Street address, building name, etc." value="${this.escapeHtml(this.state.patientAddress)}" />
4853
6712
  </div>
4854
- <div>
4855
- <label class="medos-appointment-label">Zipcode *</label>
4856
- <input type="text" class="medos-appointment-input" id="medos-patient-zipcode" placeholder="Zipcode" value="${this.escapeHtml(this.state.patientZipcode)}" />
6713
+ <div class="medos-form-row">
6714
+ <div class="medos-form-group">
6715
+ <label class="medos-label">City <span class="medos-required">*</span></label>
6716
+ <input type="text" class="medos-input" id="medos-patient-city" placeholder="City" value="${this.escapeHtml(this.state.patientCity)}" />
6717
+ </div>
6718
+ <div class="medos-form-group">
6719
+ <label class="medos-label">State <span class="medos-required">*</span></label>
6720
+ <input type="text" class="medos-input" id="medos-patient-state" placeholder="State" value="${this.escapeHtml(this.state.patientState)}" />
6721
+ </div>
6722
+ </div>
6723
+ <div class="medos-form-row">
6724
+ <div class="medos-form-group">
6725
+ <label class="medos-label">Country <span class="medos-required">*</span></label>
6726
+ <input type="text" class="medos-input" id="medos-patient-country" placeholder="Country" value="${this.escapeHtml(this.state.patientCountry)}" />
6727
+ </div>
6728
+ <div class="medos-form-group">
6729
+ <label class="medos-label">Zipcode <span class="medos-required">*</span></label>
6730
+ <input type="text" class="medos-input" id="medos-patient-zipcode" placeholder="Zipcode" value="${this.escapeHtml(this.state.patientZipcode)}" />
6731
+ </div>
6732
+ </div>
6733
+ <div class="medos-form-group">
6734
+ <label class="medos-label">Landmark <span class="medos-optional">(optional)</span></label>
6735
+ <input type="text" class="medos-input" id="medos-patient-landmark" placeholder="Nearby landmark" value="${this.escapeHtml(this.state.patientLandmark)}" />
4857
6736
  </div>
4858
6737
  </div>
4859
- <label class="medos-appointment-label" style="margin-top: 12px">Landmark (Optional)</label>
4860
- <input type="text" class="medos-appointment-input" id="medos-patient-landmark" placeholder="Nearby landmark" value="${this.escapeHtml(this.state.patientLandmark)}" />
4861
- <label class="medos-appointment-label" style="margin-top: 12px">Problem Facing</label>
4862
- <textarea class="medos-appointment-textarea" id="medos-problem-facing" placeholder="Describe the problem you're facing">${this.escapeHtml(this.state.patientName)}</textarea>
4863
- <div class="medos-appointment-actions">
4864
- <button class="medos-appointment-btn medos-appointment-btn-secondary" id="medos-btn-back">Back</button>
4865
- <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>
4866
- </div>
6738
+ </div>
6739
+
6740
+ <div class="medos-actions">
6741
+ <button class="medos-btn medos-btn-secondary" id="medos-btn-back">Back</button>
6742
+ <button class="medos-btn medos-btn-primary" id="medos-btn-submit" ${canSubmit && !this.state.loading ? "" : "disabled"}>${this.state.loading ? "Booking..." : "Book Appointment"}</button>
4867
6743
  </div>
4868
6744
  `;
4869
6745
  }
@@ -4982,35 +6858,20 @@
4982
6858
  `;
4983
6859
  }
4984
6860
  attachEventListeners() {
4985
- const addressSelect = this.container.querySelector("#medos-address-select");
4986
- if (addressSelect) {
4987
- addressSelect.addEventListener("change", (e) => {
4988
- const target = e.target;
4989
- this.handleAddressChange(Number(target.value) || null);
4990
- });
4991
- }
4992
- const doctorSelect = this.container.querySelector("#medos-doctor-select");
4993
- if (doctorSelect) {
4994
- doctorSelect.addEventListener("change", (e) => {
4995
- const target = e.target;
4996
- this.state.selectedDoctor = Number(target.value) || null;
4997
- this.render();
4998
- });
4999
- }
5000
- const dateInput = this.container.querySelector("#medos-date-input");
5001
- if (dateInput) {
5002
- dateInput.addEventListener("change", (e) => {
6861
+ const consultationRadios = this.container.querySelectorAll('input[name="consultationMode"]');
6862
+ consultationRadios.forEach((radio) => {
6863
+ radio.addEventListener("change", (e) => {
5003
6864
  const target = e.target;
5004
- this.state.selectedDate = new Date(target.value);
6865
+ this.state.consultationMode = target.value;
5005
6866
  this.render();
5006
6867
  });
5007
- }
5008
- const slotCards = this.container.querySelectorAll(".medos-appointment-slot-card");
6868
+ });
6869
+ const slotCards = this.container.querySelectorAll(".medos-slot-card");
5009
6870
  slotCards.forEach((card) => {
5010
6871
  card.addEventListener("click", () => {
5011
- const slotId = card.getAttribute("data-slot-id");
5012
- const slotStart = card.getAttribute("data-slot-start");
5013
- const slotEnd = card.getAttribute("data-slot-end");
6872
+ const slotId = card.dataset.slotId;
6873
+ const slotStart = card.dataset.slotStart;
6874
+ const slotEnd = card.dataset.slotEnd;
5014
6875
  if (slotStart && slotEnd) {
5015
6876
  this.state.selectedSlot = {
5016
6877
  start: slotStart,
@@ -5032,7 +6893,11 @@
5032
6893
  value = value.replace(/[^\d+]/g, "");
5033
6894
  this.state.countryCode = value;
5034
6895
  target.value = value;
5035
- this.render();
6896
+ const sendOtpBtn = this.container.querySelector("#medos-btn-send-otp");
6897
+ if (sendOtpBtn) {
6898
+ const canSendOtp = this.state.countryCode && this.state.patientPhone.length >= 10;
6899
+ sendOtpBtn.disabled = !canSendOtp;
6900
+ }
5036
6901
  });
5037
6902
  }
5038
6903
  const phoneInput = this.container.querySelector("#medos-phone");
@@ -5041,7 +6906,11 @@
5041
6906
  const target = e.target;
5042
6907
  this.state.patientPhone = target.value.replace(/\D/g, "");
5043
6908
  target.value = this.state.patientPhone;
5044
- this.render();
6909
+ const sendOtpBtn = this.container.querySelector("#medos-btn-send-otp");
6910
+ if (sendOtpBtn) {
6911
+ const canSendOtp = this.state.countryCode && this.state.patientPhone.length >= 10;
6912
+ sendOtpBtn.disabled = !canSendOtp;
6913
+ }
5045
6914
  });
5046
6915
  }
5047
6916
  const otpInput = this.container.querySelector("#medos-otp");
@@ -5049,7 +6918,10 @@
5049
6918
  otpInput.addEventListener("input", (e) => {
5050
6919
  const target = e.target;
5051
6920
  this.state.otpCode = target.value;
5052
- this.render();
6921
+ const verifyBtn = this.container.querySelector("#medos-btn-verify-otp");
6922
+ if (verifyBtn) {
6923
+ verifyBtn.disabled = !(this.state.otpCode.length === 6 && !this.state.otpVerifying);
6924
+ }
5053
6925
  });
5054
6926
  }
5055
6927
  const patientNameInput = this.container.querySelector("#medos-patient-name");
@@ -5057,6 +6929,7 @@
5057
6929
  patientNameInput.addEventListener("input", (e) => {
5058
6930
  const target = e.target;
5059
6931
  this.state.patientName = target.value;
6932
+ this.updateSubmitButtonState();
5060
6933
  });
5061
6934
  }
5062
6935
  const patientAgeInput = this.container.querySelector("#medos-patient-age");
@@ -5064,6 +6937,7 @@
5064
6937
  patientAgeInput.addEventListener("input", (e) => {
5065
6938
  const target = e.target;
5066
6939
  this.state.patientAge = target.value;
6940
+ this.updateSubmitButtonState();
5067
6941
  });
5068
6942
  }
5069
6943
  const patientEmailInput = this.container.querySelector("#medos-patient-email");
@@ -5071,6 +6945,7 @@
5071
6945
  patientEmailInput.addEventListener("input", (e) => {
5072
6946
  const target = e.target;
5073
6947
  this.state.patientEmail = target.value;
6948
+ this.updateSubmitButtonState();
5074
6949
  });
5075
6950
  }
5076
6951
  const patientGenderSelect = this.container.querySelector("#medos-patient-gender");
@@ -5085,6 +6960,7 @@
5085
6960
  patientAddressInput.addEventListener("input", (e) => {
5086
6961
  const target = e.target;
5087
6962
  this.state.patientAddress = target.value;
6963
+ this.updateSubmitButtonState();
5088
6964
  });
5089
6965
  }
5090
6966
  const patientCityInput = this.container.querySelector("#medos-patient-city");
@@ -5092,6 +6968,7 @@
5092
6968
  patientCityInput.addEventListener("input", (e) => {
5093
6969
  const target = e.target;
5094
6970
  this.state.patientCity = target.value;
6971
+ this.updateSubmitButtonState();
5095
6972
  });
5096
6973
  }
5097
6974
  const patientStateInput = this.container.querySelector("#medos-patient-state");
@@ -5099,6 +6976,7 @@
5099
6976
  patientStateInput.addEventListener("input", (e) => {
5100
6977
  const target = e.target;
5101
6978
  this.state.patientState = target.value;
6979
+ this.updateSubmitButtonState();
5102
6980
  });
5103
6981
  }
5104
6982
  const patientCountryInput = this.container.querySelector("#medos-patient-country");
@@ -5106,6 +6984,7 @@
5106
6984
  patientCountryInput.addEventListener("input", (e) => {
5107
6985
  const target = e.target;
5108
6986
  this.state.patientCountry = target.value;
6987
+ this.updateSubmitButtonState();
5109
6988
  });
5110
6989
  }
5111
6990
  const patientZipcodeInput = this.container.querySelector("#medos-patient-zipcode");
@@ -5113,6 +6992,7 @@
5113
6992
  patientZipcodeInput.addEventListener("input", (e) => {
5114
6993
  const target = e.target;
5115
6994
  this.state.patientZipcode = target.value;
6995
+ this.updateSubmitButtonState();
5116
6996
  });
5117
6997
  }
5118
6998
  const patientLandmarkInput = this.container.querySelector("#medos-patient-landmark");
@@ -5124,7 +7004,11 @@
5124
7004
  }
5125
7005
  const nextBtn = this.container.querySelector("#medos-btn-next");
5126
7006
  if (nextBtn) {
5127
- nextBtn.addEventListener("click", () => this.goToNext());
7007
+ nextBtn.addEventListener("click", () => {
7008
+ if (!nextBtn.disabled) {
7009
+ this.goToNext();
7010
+ }
7011
+ });
5128
7012
  }
5129
7013
  const backBtn = this.container.querySelector("#medos-btn-back");
5130
7014
  if (backBtn) {
@@ -5132,11 +7016,19 @@
5132
7016
  }
5133
7017
  const sendOtpBtn = this.container.querySelector("#medos-btn-send-otp");
5134
7018
  if (sendOtpBtn) {
5135
- sendOtpBtn.addEventListener("click", () => this.sendOtp());
7019
+ sendOtpBtn.addEventListener("click", () => {
7020
+ if (!sendOtpBtn.disabled) {
7021
+ this.sendOtp();
7022
+ }
7023
+ });
5136
7024
  }
5137
7025
  const verifyOtpBtn = this.container.querySelector("#medos-btn-verify-otp");
5138
7026
  if (verifyOtpBtn) {
5139
- verifyOtpBtn.addEventListener("click", () => this.verifyOtp());
7027
+ verifyOtpBtn.addEventListener("click", () => {
7028
+ if (!verifyOtpBtn.disabled) {
7029
+ this.verifyOtp();
7030
+ }
7031
+ });
5140
7032
  }
5141
7033
  const changeNumberBtn = this.container.querySelector("#medos-btn-change-number");
5142
7034
  if (changeNumberBtn) {
@@ -5145,9 +7037,19 @@
5145
7037
  this.render();
5146
7038
  });
5147
7039
  }
7040
+ const resendOtpBtn = this.container.querySelector("#medos-btn-resend-otp");
7041
+ if (resendOtpBtn) {
7042
+ resendOtpBtn.addEventListener("click", () => {
7043
+ this.sendOtp();
7044
+ });
7045
+ }
5148
7046
  const submitBtn = this.container.querySelector("#medos-btn-submit");
5149
7047
  if (submitBtn) {
5150
- submitBtn.addEventListener("click", () => this.submitAppointment());
7048
+ submitBtn.addEventListener("click", () => {
7049
+ if (!submitBtn.disabled) {
7050
+ this.submitAppointment();
7051
+ }
7052
+ });
5151
7053
  }
5152
7054
  const bookAnotherBtn = this.container.querySelector("#medos-btn-book-another");
5153
7055
  if (bookAnotherBtn) {
@@ -5223,9 +7125,18 @@
5223
7125
  return /^\+[1-9]\d{0,3}$/.test(code);
5224
7126
  };
5225
7127
 
7128
+ const COUNTRY_CODES_ENQUIRY = [
7129
+ { value: "+91", label: "🇮🇳 +91" },
7130
+ { value: "+1", label: "🇺🇸 +1" },
7131
+ { value: "+44", label: "🇬🇧 +44" },
7132
+ { value: "+86", label: "🇨🇳 +86" },
7133
+ { value: "+81", label: "🇯🇵 +81" },
7134
+ ];
5226
7135
  class EnquiryFormWidget {
5227
7136
  constructor(container, options) {
5228
7137
  this.mounted = true;
7138
+ this.countryCodeSelect = null;
7139
+ injectThemedStyles();
5229
7140
  if (typeof container === "string") {
5230
7141
  const el = document.getElementById(container);
5231
7142
  if (!el) {
@@ -5407,6 +7318,23 @@
5407
7318
  </div>
5408
7319
  `;
5409
7320
  this.attachEventListeners();
7321
+ this.initializeCustomComponents();
7322
+ }
7323
+ initializeCustomComponents() {
7324
+ if (this.state.step === 0) {
7325
+ const countryCodeContainer = this.container.querySelector("#medos-enquiry-country-code-container");
7326
+ if (countryCodeContainer) {
7327
+ this.countryCodeSelect = new VanillaSelect(countryCodeContainer, COUNTRY_CODES_ENQUIRY, {
7328
+ placeholder: "Country",
7329
+ onValueChange: (value) => {
7330
+ this.state.countryCode = value;
7331
+ },
7332
+ });
7333
+ if (this.state.countryCode) {
7334
+ this.countryCodeSelect.setValue(this.state.countryCode);
7335
+ }
7336
+ }
7337
+ }
5410
7338
  }
5411
7339
  renderStep() {
5412
7340
  switch (this.state.step) {
@@ -5424,121 +7352,147 @@
5424
7352
  }
5425
7353
  renderStep0() {
5426
7354
  return `
5427
- <div class="medos-enquiry-section">
5428
- <label class="medos-enquiry-label">Full Name *</label>
5429
- <input
5430
- type="text"
5431
- class="medos-enquiry-input"
5432
- id="medos-enquiry-name"
5433
- placeholder="Enter your full name"
5434
- value="${this.escapeHtml(this.state.patientName)}"
5435
- />
5436
-
5437
- <label class="medos-enquiry-label" style="margin-top: 12px">Email Address *</label>
5438
- <input
5439
- type="email"
5440
- class="medos-enquiry-input"
5441
- id="medos-enquiry-email"
5442
- placeholder="your.email@example.com"
5443
- value="${this.escapeHtml(this.state.patientEmail)}"
5444
- />
5445
-
5446
- <label class="medos-enquiry-label" style="margin-top: 12px">Country Code *</label>
5447
- <input
5448
- type="text"
5449
- class="medos-enquiry-input"
5450
- id="medos-enquiry-country-code"
5451
- placeholder="+91"
5452
- value="${this.escapeHtml(this.state.countryCode)}"
5453
- />
5454
-
5455
- <label class="medos-enquiry-label" style="margin-top: 12px">Phone Number *</label>
5456
- <input
5457
- type="tel"
5458
- class="medos-enquiry-input"
5459
- id="medos-enquiry-phone"
5460
- placeholder="9876543210"
5461
- value="${this.escapeHtml(this.state.patientPhone)}"
5462
- maxlength="15"
5463
- />
5464
-
5465
- <div class="medos-enquiry-actions">
5466
- <button class="medos-enquiry-btn medos-enquiry-btn-secondary" id="medos-enquiry-btn-cancel">Cancel</button>
5467
- <button class="medos-enquiry-btn medos-enquiry-btn-primary" id="medos-enquiry-btn-next">Next</button>
7355
+ <div class="medos-section-card">
7356
+ <div class="medos-section-header">
7357
+ ${VanillaIcons.user(14)}
7358
+ <span class="medos-section-title">Contact Information</span>
7359
+ </div>
7360
+ <div class="medos-section-body">
7361
+ <div class="medos-form-group">
7362
+ <label class="medos-label">Full Name <span class="medos-required">*</span></label>
7363
+ <input
7364
+ type="text"
7365
+ class="medos-input"
7366
+ id="medos-enquiry-name"
7367
+ placeholder="Enter your full name"
7368
+ value="${this.escapeHtml(this.state.patientName)}"
7369
+ />
7370
+ </div>
7371
+
7372
+ <div class="medos-form-group">
7373
+ <label class="medos-label">Email Address <span class="medos-required">*</span></label>
7374
+ <input
7375
+ type="email"
7376
+ class="medos-input"
7377
+ id="medos-enquiry-email"
7378
+ placeholder="your.email@example.com"
7379
+ value="${this.escapeHtml(this.state.patientEmail)}"
7380
+ />
7381
+ </div>
7382
+
7383
+ <div class="medos-form-group">
7384
+ <label class="medos-label">Phone Number <span class="medos-required">*</span></label>
7385
+ <div class="medos-phone-input-row">
7386
+ <div class="medos-country-code-wrapper">
7387
+ <div id="medos-enquiry-country-code-container"></div>
7388
+ </div>
7389
+ <div class="medos-phone-wrapper">
7390
+ <input
7391
+ type="tel"
7392
+ class="medos-input"
7393
+ id="medos-enquiry-phone"
7394
+ placeholder="Enter phone number"
7395
+ value="${this.escapeHtml(this.state.patientPhone)}"
7396
+ maxlength="15"
7397
+ />
7398
+ </div>
7399
+ </div>
7400
+ </div>
5468
7401
  </div>
5469
7402
  </div>
7403
+
7404
+ <div class="medos-actions">
7405
+ <button class="medos-btn medos-btn-secondary" id="medos-enquiry-btn-cancel">Cancel</button>
7406
+ <button class="medos-btn medos-btn-primary" id="medos-enquiry-btn-next">Next</button>
7407
+ </div>
5470
7408
  `;
5471
7409
  }
5472
7410
  renderStep1() {
5473
7411
  return `
5474
- <div class="medos-enquiry-section">
5475
- <label class="medos-enquiry-label">Subject *</label>
5476
- <input
5477
- type="text"
5478
- class="medos-enquiry-input"
5479
- id="medos-enquiry-subject"
5480
- placeholder="What is your inquiry about?"
5481
- value="${this.escapeHtml(this.state.inquirySubject)}"
5482
- />
5483
-
5484
- <label class="medos-enquiry-label" style="margin-top: 12px">Message *</label>
5485
- <textarea
5486
- class="medos-enquiry-textarea"
5487
- id="medos-enquiry-message"
5488
- placeholder="Please describe your inquiry in detail (max 1000 characters)"
5489
- maxlength="1000"
5490
- >${this.escapeHtml(this.state.inquiryMessage)}</textarea>
5491
- <div class="medos-enquiry-char-count">${this.state.inquiryMessage.length}/1000</div>
5492
-
5493
- <div class="medos-enquiry-actions">
5494
- <button class="medos-enquiry-btn medos-enquiry-btn-secondary" id="medos-enquiry-btn-back">Back</button>
5495
- <button class="medos-enquiry-btn medos-enquiry-btn-primary" id="medos-enquiry-btn-next">Next</button>
7412
+ <div class="medos-section-card">
7413
+ <div class="medos-section-header">
7414
+ ${VanillaIcons.mail(14)}
7415
+ <span class="medos-section-title">Inquiry Details</span>
5496
7416
  </div>
7417
+ <div class="medos-section-body">
7418
+ <div class="medos-form-group">
7419
+ <label class="medos-label">Subject <span class="medos-required">*</span></label>
7420
+ <input
7421
+ type="text"
7422
+ class="medos-input"
7423
+ id="medos-enquiry-subject"
7424
+ placeholder="What is your inquiry about?"
7425
+ value="${this.escapeHtml(this.state.inquirySubject)}"
7426
+ />
7427
+ </div>
7428
+
7429
+ <div class="medos-form-group">
7430
+ <label class="medos-label">Message <span class="medos-required">*</span></label>
7431
+ <textarea
7432
+ class="medos-textarea"
7433
+ id="medos-enquiry-message"
7434
+ placeholder="Please describe your inquiry in detail (max 1000 characters)"
7435
+ maxlength="1000"
7436
+ >${this.escapeHtml(this.state.inquiryMessage)}</textarea>
7437
+ <div class="medos-char-count">${this.state.inquiryMessage.length}/1000</div>
7438
+ </div>
7439
+ </div>
7440
+ </div>
7441
+
7442
+ <div class="medos-actions">
7443
+ <button class="medos-btn medos-btn-secondary" id="medos-enquiry-btn-back">Back</button>
7444
+ <button class="medos-btn medos-btn-primary" id="medos-enquiry-btn-next">Next</button>
5497
7445
  </div>
5498
7446
  `;
5499
7447
  }
5500
7448
  renderStep2() {
5501
7449
  return `
5502
- <div class="medos-enquiry-section">
5503
- <label class="medos-enquiry-label">Preferred Contact Method *</label>
5504
- <div class="medos-enquiry-radio-group">
5505
- <label class="medos-enquiry-radio-label">
5506
- <input
5507
- type="radio"
5508
- name="contact-method"
5509
- value="PHONE"
5510
- ${this.state.preferredContactMethod === "PHONE" ? "checked" : ""}
5511
- id="medos-enquiry-contact-phone"
5512
- />
5513
- <span>Phone</span>
5514
- </label>
5515
- <label class="medos-enquiry-radio-label">
5516
- <input
5517
- type="radio"
5518
- name="contact-method"
5519
- value="EMAIL"
5520
- ${this.state.preferredContactMethod === "EMAIL" ? "checked" : ""}
5521
- id="medos-enquiry-contact-email"
5522
- />
5523
- <span>Email</span>
5524
- </label>
5525
- <label class="medos-enquiry-radio-label">
5526
- <input
5527
- type="radio"
5528
- name="contact-method"
5529
- value="BOTH"
5530
- ${this.state.preferredContactMethod === "BOTH" ? "checked" : ""}
5531
- id="medos-enquiry-contact-both"
5532
- />
5533
- <span>Both</span>
5534
- </label>
7450
+ <div class="medos-section-card">
7451
+ <div class="medos-section-header">
7452
+ ${VanillaIcons.phone(14)}
7453
+ <span class="medos-section-title">Contact Preference</span>
5535
7454
  </div>
5536
-
5537
- <div class="medos-enquiry-actions">
5538
- <button class="medos-enquiry-btn medos-enquiry-btn-secondary" id="medos-enquiry-btn-back">Back</button>
5539
- <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>
7455
+ <div class="medos-section-body">
7456
+ <p class="medos-section-description">How would you prefer to be contacted?</p>
7457
+ <div class="medos-contact-options">
7458
+ <label class="medos-radio-option ${this.state.preferredContactMethod === "PHONE" ? "selected" : ""}">
7459
+ <input
7460
+ type="radio"
7461
+ name="contact-method"
7462
+ value="PHONE"
7463
+ ${this.state.preferredContactMethod === "PHONE" ? "checked" : ""}
7464
+ class="medos-radio-input"
7465
+ />
7466
+ <span class="medos-radio-label">Phone</span>
7467
+ </label>
7468
+ <label class="medos-radio-option ${this.state.preferredContactMethod === "EMAIL" ? "selected" : ""}">
7469
+ <input
7470
+ type="radio"
7471
+ name="contact-method"
7472
+ value="EMAIL"
7473
+ ${this.state.preferredContactMethod === "EMAIL" ? "checked" : ""}
7474
+ class="medos-radio-input"
7475
+ />
7476
+ <span class="medos-radio-label">Email</span>
7477
+ </label>
7478
+ <label class="medos-radio-option ${this.state.preferredContactMethod === "BOTH" ? "selected" : ""}">
7479
+ <input
7480
+ type="radio"
7481
+ name="contact-method"
7482
+ value="BOTH"
7483
+ ${this.state.preferredContactMethod === "BOTH" ? "checked" : ""}
7484
+ class="medos-radio-input"
7485
+ />
7486
+ <span class="medos-radio-label">Both</span>
7487
+ </label>
7488
+ </div>
5540
7489
  </div>
5541
7490
  </div>
7491
+
7492
+ <div class="medos-actions">
7493
+ <button class="medos-btn medos-btn-secondary" id="medos-enquiry-btn-back">Back</button>
7494
+ <button class="medos-btn medos-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>
7495
+ </div>
5542
7496
  `;
5543
7497
  }
5544
7498
  renderStep3() {
@@ -5708,6 +7662,8 @@
5708
7662
  init: initEnquiryForm,
5709
7663
  Widget: EnquiryFormWidget,
5710
7664
  };
7665
+ window.MedosAppointmentWidget = AppointmentCalendarWidget;
7666
+ window.MedosEnquiryWidget = EnquiryFormWidget;
5711
7667
  }
5712
7668
 
5713
7669
  exports.AppointmentCalendarWidget = AppointmentCalendarWidget;