medos-sdk 1.1.13 → 1.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +831 -32
- package/dist/components/appointment-booking/types.d.ts +1 -0
- package/dist/components/appointment-booking/types.js +1 -0
- package/dist/components/constants/index.d.ts +1 -1
- package/dist/components/constants/index.js +1 -1
- package/dist/services/AuthService.js +1 -1
- package/dist/vanilla/AppointmentCalendarWidget.d.ts +76 -0
- package/dist/vanilla/AppointmentCalendarWidget.js +819 -563
- package/dist/vanilla/components/appointment-booking/types.d.ts +1 -0
- package/dist/vanilla/components/constants/index.d.ts +1 -1
- package/dist/vanilla/components/theme-injector.js +527 -0
- package/dist/vanilla/enquiry-widget.js +1124 -3802
- package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +76 -0
- package/dist/vanilla/widget-themed.css +1291 -0
- package/dist/vanilla/widget.css +157 -0
- package/dist/vanilla/widget.js +7667 -10020
- package/package.json +2 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { AppointmentService, } from "../services/AppointmentService";
|
|
2
2
|
import { PatientService } from "../services/PatientService";
|
|
3
|
+
import { WorkspaceService } from "../services/WorkspaceService";
|
|
3
4
|
import { MedosClient } from "../client/MedosClient";
|
|
4
5
|
import { INITIAL_STATE, } from "../components/appointment-booking/types";
|
|
5
6
|
import { COUNTRY_CODES, GENDER_OPTIONS, BLOOD_GROUP_OPTIONS, mapBloodGroupToApi, } from "../components/constants/options";
|
|
6
7
|
import { validatePhoneNumber, validateCountryCode, validateDateOfBirth, validateBloodGroup, } from "../components/validation";
|
|
7
8
|
import { formatDateToISO, parsePatientName } from "../components/utils";
|
|
9
|
+
import { formatDate, formatTime, calculateDuration, } from "../components/utils/date";
|
|
8
10
|
import { VanillaIcons } from "./components/VanillaIcons";
|
|
9
11
|
import { VanillaSelect } from "./components/VanillaSelect";
|
|
10
12
|
import { VanillaCalendar } from "./components/VanillaCalendar";
|
|
@@ -48,9 +50,25 @@ class AppointmentCalendarWidget {
|
|
|
48
50
|
else {
|
|
49
51
|
throw new Error("Either apiKey or sessionToken must be provided");
|
|
50
52
|
}
|
|
53
|
+
await this.loadWorkspaceConfiguration();
|
|
51
54
|
await this.loadAddresses();
|
|
52
55
|
this.render();
|
|
53
56
|
}
|
|
57
|
+
async loadWorkspaceConfiguration() {
|
|
58
|
+
this.setState({ loading: true, error: null });
|
|
59
|
+
try {
|
|
60
|
+
const workspaceResponse = await WorkspaceService.fetchWorkspace();
|
|
61
|
+
console.log("Workspace configuration loaded:", {
|
|
62
|
+
workspaceId: workspaceResponse.workspaceId,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
console.error("Failed to load workspace configuration:", e);
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
this.setState({ loading: false });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
54
72
|
async loadAddresses() {
|
|
55
73
|
this.setState({ loading: true, error: null });
|
|
56
74
|
try {
|
|
@@ -82,10 +100,6 @@ class AppointmentCalendarWidget {
|
|
|
82
100
|
this.doctors = docsForAddr;
|
|
83
101
|
if (docsForAddr.length === 1) {
|
|
84
102
|
this.state.selectedDoctor = docsForAddr[0].id;
|
|
85
|
-
this.state.step = 1;
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
this.state.step = 0;
|
|
89
103
|
}
|
|
90
104
|
}
|
|
91
105
|
else {
|
|
@@ -94,20 +108,16 @@ class AppointmentCalendarWidget {
|
|
|
94
108
|
error: "No doctors at this address. Please choose a different address.",
|
|
95
109
|
});
|
|
96
110
|
this.doctors = [];
|
|
97
|
-
this.state.step = 0;
|
|
98
111
|
}
|
|
99
112
|
else {
|
|
100
113
|
this.setState({
|
|
101
114
|
error: "No doctors available for the selected location(s).",
|
|
102
115
|
});
|
|
103
116
|
this.doctors = [];
|
|
104
|
-
this.state.step = 0;
|
|
105
117
|
}
|
|
106
118
|
}
|
|
107
119
|
}
|
|
108
|
-
|
|
109
|
-
this.state.step = 0;
|
|
110
|
-
}
|
|
120
|
+
this.state.step = 0;
|
|
111
121
|
}
|
|
112
122
|
else {
|
|
113
123
|
this.setState({ error: "No addresses or doctors available." });
|
|
@@ -142,7 +152,6 @@ class AppointmentCalendarWidget {
|
|
|
142
152
|
this.doctors = docsForAddr;
|
|
143
153
|
if (docsForAddr.length === 1) {
|
|
144
154
|
this.state.selectedDoctor = docsForAddr[0].id;
|
|
145
|
-
this.state.step = 1;
|
|
146
155
|
}
|
|
147
156
|
else {
|
|
148
157
|
this.state.selectedDoctor = null;
|
|
@@ -189,6 +198,13 @@ class AppointmentCalendarWidget {
|
|
|
189
198
|
try {
|
|
190
199
|
const s = await AppointmentService.fetchSlots(this.state.workspaceId, this.state.selectedAddress, this.state.selectedDoctor, dateStr);
|
|
191
200
|
this.state.slots = s || [];
|
|
201
|
+
if (this.state.selectedSlot) {
|
|
202
|
+
const isSlotStillValid = this.state.slots.some((slot) => slot.start === this.state.selectedSlot?.start &&
|
|
203
|
+
slot.end === this.state.selectedSlot?.end);
|
|
204
|
+
if (!isSlotStillValid) {
|
|
205
|
+
this.state.selectedSlot = null;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
192
208
|
}
|
|
193
209
|
catch (e) {
|
|
194
210
|
this.setState({ error: e.message || "Failed to load slots" });
|
|
@@ -220,8 +236,6 @@ class AppointmentCalendarWidget {
|
|
|
220
236
|
this.state.patientAge &&
|
|
221
237
|
this.state.patientGender &&
|
|
222
238
|
this.state.otpVerified &&
|
|
223
|
-
(!(this.state.patientDob && this.state.patientDob.trim() !== "") ||
|
|
224
|
-
this.isValidDateOfBirth(this.state.patientDob)) &&
|
|
225
239
|
(!(this.state.bloodGroup && this.state.bloodGroup.trim() !== "") ||
|
|
226
240
|
this.isValidBloodGroup(this.state.bloodGroup));
|
|
227
241
|
submitBtn.disabled = !(canSubmit && !this.state.loading);
|
|
@@ -247,8 +261,6 @@ class AppointmentCalendarWidget {
|
|
|
247
261
|
this.state.patientState &&
|
|
248
262
|
this.state.patientCountry &&
|
|
249
263
|
this.state.patientZipcode &&
|
|
250
|
-
(!(this.state.patientDob && this.state.patientDob.trim() !== "") ||
|
|
251
|
-
this.isValidDateOfBirth(this.state.patientDob)) &&
|
|
252
264
|
(!(this.state.bloodGroup && this.state.bloodGroup.trim() !== "") ||
|
|
253
265
|
this.isValidBloodGroup(this.state.bloodGroup));
|
|
254
266
|
continueBtn.disabled = !isFormValid;
|
|
@@ -334,12 +346,14 @@ class AppointmentCalendarWidget {
|
|
|
334
346
|
phoneNumber: this.state.patientPhone,
|
|
335
347
|
otpCode: this.state.otpCode,
|
|
336
348
|
});
|
|
337
|
-
await PatientService.verifyPhoneVerificationOtp({
|
|
349
|
+
const response = await PatientService.verifyPhoneVerificationOtp({
|
|
338
350
|
countryCode: this.state.countryCode,
|
|
339
351
|
phoneNumber: this.state.patientPhone,
|
|
340
352
|
otpCode: this.state.otpCode,
|
|
341
353
|
});
|
|
354
|
+
this.processOtpVerificationResponse(response);
|
|
342
355
|
this.setState({ otpVerified: true, error: null });
|
|
356
|
+
this.goToNext();
|
|
343
357
|
}
|
|
344
358
|
catch (e) {
|
|
345
359
|
console.error("OTP verification error:", e);
|
|
@@ -354,6 +368,77 @@ class AppointmentCalendarWidget {
|
|
|
354
368
|
this.render();
|
|
355
369
|
}
|
|
356
370
|
}
|
|
371
|
+
processOtpVerificationResponse(response) {
|
|
372
|
+
try {
|
|
373
|
+
this.state.userSessionPacks = [];
|
|
374
|
+
this.state.availablePackages = [];
|
|
375
|
+
this.state.verifiedPatients = [];
|
|
376
|
+
const sessionPacksDetails = response?.sessionPacksDetails;
|
|
377
|
+
if (sessionPacksDetails?.associatedPatients &&
|
|
378
|
+
Array.isArray(sessionPacksDetails.associatedPatients) &&
|
|
379
|
+
sessionPacksDetails.associatedPatients.length > 0) {
|
|
380
|
+
this.state.verifiedPatients = sessionPacksDetails.associatedPatients;
|
|
381
|
+
}
|
|
382
|
+
else if (response.associatedPatients &&
|
|
383
|
+
Array.isArray(response.associatedPatients)) {
|
|
384
|
+
this.state.verifiedPatients = response.associatedPatients;
|
|
385
|
+
}
|
|
386
|
+
else if (response.patients && Array.isArray(response.patients)) {
|
|
387
|
+
this.state.verifiedPatients = response.patients;
|
|
388
|
+
}
|
|
389
|
+
if (sessionPacksDetails?.activeSessionPackResponses &&
|
|
390
|
+
Array.isArray(sessionPacksDetails.activeSessionPackResponses) &&
|
|
391
|
+
sessionPacksDetails.activeSessionPackResponses.length > 0) {
|
|
392
|
+
this.state.userSessionPacks =
|
|
393
|
+
sessionPacksDetails.activeSessionPackResponses.map((pack) => ({
|
|
394
|
+
id: pack.id || 0,
|
|
395
|
+
name: pack.packageName || pack.name || "Unknown Package",
|
|
396
|
+
description: pack.description,
|
|
397
|
+
totalSessions: pack.totalSessions || 0,
|
|
398
|
+
remainingSessions: pack.remainingSessions || 0,
|
|
399
|
+
expiryDate: pack.expiryDate || "",
|
|
400
|
+
purchaseDate: pack.purchaseDate,
|
|
401
|
+
doctorId: pack.doctorId,
|
|
402
|
+
doctorName: pack.doctorName,
|
|
403
|
+
allowedConsultationModes: pack.allowedConsultationModes || [],
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
406
|
+
if (sessionPacksDetails?.allSessionPackResponses &&
|
|
407
|
+
Array.isArray(sessionPacksDetails.allSessionPackResponses) &&
|
|
408
|
+
sessionPacksDetails.allSessionPackResponses.length > 0) {
|
|
409
|
+
this.state.availablePackages =
|
|
410
|
+
sessionPacksDetails.allSessionPackResponses.map((pack) => ({
|
|
411
|
+
id: pack.id || 0,
|
|
412
|
+
name: pack.packageName || pack.name || "Unknown Package",
|
|
413
|
+
description: pack.description,
|
|
414
|
+
totalSessions: pack.totalSessions || 0,
|
|
415
|
+
price: pack.packagePrice || pack.price || 0,
|
|
416
|
+
discountedPrice: pack.discountedPrice,
|
|
417
|
+
discount: pack.discount,
|
|
418
|
+
discountType: pack.discountType,
|
|
419
|
+
validityDays: pack.validityDays || 0,
|
|
420
|
+
allowedConsultationModes: pack.allowedConsultationModes || [],
|
|
421
|
+
allowedDoctors: pack.allowedDoctors || [],
|
|
422
|
+
doctorIds: pack.doctorIds || [],
|
|
423
|
+
applicableOnline: pack.allowedConsultationModes?.includes("ONLINE") || false,
|
|
424
|
+
applicableOffline: pack.allowedConsultationModes?.includes("OFFLINE") || false,
|
|
425
|
+
}));
|
|
426
|
+
}
|
|
427
|
+
console.log("Processed OTP verification response:", {
|
|
428
|
+
verifiedPatients: this.state.verifiedPatients.length,
|
|
429
|
+
userSessionPacks: this.state.userSessionPacks.length,
|
|
430
|
+
availablePackages: this.state.availablePackages.length,
|
|
431
|
+
allSessionPackResponsesExists: sessionPacksDetails?.allSessionPackResponses?.length > 0,
|
|
432
|
+
sessionPacksDetailsExists: !!sessionPacksDetails,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
catch (error) {
|
|
436
|
+
console.error("Error processing OTP verification response:", error);
|
|
437
|
+
this.state.verifiedPatients = [];
|
|
438
|
+
this.state.userSessionPacks = [];
|
|
439
|
+
this.state.availablePackages = [];
|
|
440
|
+
}
|
|
441
|
+
}
|
|
357
442
|
async submitAppointment() {
|
|
358
443
|
this.setState({ error: null });
|
|
359
444
|
if (!this.state.selectedDoctor ||
|
|
@@ -377,23 +462,6 @@ class AppointmentCalendarWidget {
|
|
|
377
462
|
this.setState({ error: "Please verify your phone number first." });
|
|
378
463
|
return;
|
|
379
464
|
}
|
|
380
|
-
if (this.state.patientDob && this.state.patientDob.trim() !== "") {
|
|
381
|
-
if (!this.isValidDateOfBirth(this.state.patientDob)) {
|
|
382
|
-
const dobValue = this.state.patientDob;
|
|
383
|
-
const today = new Date();
|
|
384
|
-
const inputDate = new Date(dobValue);
|
|
385
|
-
if (inputDate > today) {
|
|
386
|
-
this.displayFieldValidationError("dateOfBirth", "future");
|
|
387
|
-
}
|
|
388
|
-
else if (!/^\d{4}-\d{2}-\d{2}$/.test(dobValue)) {
|
|
389
|
-
this.displayFieldValidationError("dateOfBirth", "format");
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
this.displayFieldValidationError("dateOfBirth", "invalid");
|
|
393
|
-
}
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
465
|
if (this.state.bloodGroup && this.state.bloodGroup.trim() !== "") {
|
|
398
466
|
if (!this.isValidBloodGroup(this.state.bloodGroup)) {
|
|
399
467
|
this.displayFieldValidationError("bloodGroup", "invalid");
|
|
@@ -415,53 +483,64 @@ class AppointmentCalendarWidget {
|
|
|
415
483
|
this.render();
|
|
416
484
|
try {
|
|
417
485
|
const { firstName, lastName } = parsePatientName(this.state.patientName || "Patient");
|
|
418
|
-
const
|
|
419
|
-
const
|
|
420
|
-
const
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const patientAddressPayload = {
|
|
429
|
-
addressLine1: this.state.patientAddress,
|
|
430
|
-
city: this.state.patientCity,
|
|
431
|
-
state: this.state.patientState,
|
|
432
|
-
country: this.state.patientCountry,
|
|
433
|
-
zipcode: this.state.patientZipcode,
|
|
434
|
-
landmark: this.state.patientLandmark || undefined,
|
|
486
|
+
const appointmentDate = formatDateToISO(this.state.selectedDate);
|
|
487
|
+
const fromDateTimeTs = this.state.selectedSlot.start;
|
|
488
|
+
const toDateTimeTs = this.state.selectedSlot.end;
|
|
489
|
+
const patientPayload = {
|
|
490
|
+
firstName,
|
|
491
|
+
lastName,
|
|
492
|
+
countryCode: this.state.countryCode,
|
|
493
|
+
phoneNumber: this.state.patientPhone,
|
|
494
|
+
age: parseInt(this.state.patientAge, 10),
|
|
495
|
+
gender: this.state.patientGender.toUpperCase(),
|
|
435
496
|
};
|
|
436
|
-
|
|
497
|
+
if (this.state.patientEmail) {
|
|
498
|
+
patientPayload.email = this.state.patientEmail;
|
|
499
|
+
}
|
|
500
|
+
if (this.state.bloodGroup) {
|
|
501
|
+
patientPayload.bloodGroup = this.safeMapBloodGroupToApi(this.state.bloodGroup);
|
|
502
|
+
}
|
|
503
|
+
if (this.state.useExistingPatient && this.state.selectedPatient) {
|
|
504
|
+
patientPayload.id = this.state.selectedPatient.id;
|
|
505
|
+
}
|
|
506
|
+
const appointmentPayload = {
|
|
437
507
|
workspaceId: this.state.workspaceId,
|
|
438
508
|
workspaceAddressId: this.state.selectedAddress,
|
|
439
509
|
doctorId: this.state.selectedDoctor,
|
|
440
510
|
mode: this.state.consultationMode || "OFFLINE",
|
|
441
|
-
appointmentDate,
|
|
442
|
-
fromDateTimeTs,
|
|
443
|
-
toDateTimeTs,
|
|
444
|
-
consultationCharge: this.state.
|
|
511
|
+
appointmentDate: appointmentDate,
|
|
512
|
+
fromDateTimeTs: fromDateTimeTs,
|
|
513
|
+
toDateTimeTs: toDateTimeTs,
|
|
514
|
+
consultationCharge: this.state.consultationCharge || "0",
|
|
445
515
|
type: "CONSULTATION",
|
|
446
516
|
source: "SDK_POWERED_WEBSITE",
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
517
|
+
bookingType: this.state.bookingType || "ONE_TIME_APPOINTMENT",
|
|
518
|
+
paymentMode: this.state.paymentMode || "CASH",
|
|
519
|
+
patientPayload,
|
|
520
|
+
patientAddress: {
|
|
521
|
+
addressLine1: this.state.patientAddress,
|
|
522
|
+
addressLine2: "",
|
|
523
|
+
city: this.state.patientCity,
|
|
524
|
+
state: this.state.patientState,
|
|
525
|
+
country: this.state.patientCountry,
|
|
526
|
+
zipcode: this.state.patientZipcode,
|
|
527
|
+
landmark: this.state.patientLandmark || undefined,
|
|
451
528
|
countryCode: this.state.countryCode,
|
|
452
529
|
phoneNumber: this.state.patientPhone,
|
|
453
|
-
|
|
454
|
-
? parseInt(this.state.patientAge, 10)
|
|
455
|
-
: undefined,
|
|
456
|
-
gender: this.state.patientGender
|
|
457
|
-
? this.state.patientGender.toUpperCase()
|
|
458
|
-
: undefined,
|
|
459
|
-
dob: this.safeFormatDateOfBirth(this.state.patientDob),
|
|
460
|
-
bloodGroup: this.safeMapBloodGroupToApi(this.state.bloodGroup),
|
|
530
|
+
patientId: this.state.selectedPatient?.id || 0,
|
|
461
531
|
},
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
532
|
+
};
|
|
533
|
+
if (this.state.packageConfigId) {
|
|
534
|
+
appointmentPayload.packageConfigId = this.state.packageConfigId;
|
|
535
|
+
}
|
|
536
|
+
if (this.state.patientPackageId) {
|
|
537
|
+
appointmentPayload.patientPackageId = this.state.patientPackageId;
|
|
538
|
+
}
|
|
539
|
+
if (this.state.packageAmount) {
|
|
540
|
+
appointmentPayload.packageAmount = this.state.packageAmount;
|
|
541
|
+
}
|
|
542
|
+
await AppointmentService.createAppointment(appointmentPayload);
|
|
543
|
+
this.setState({ step: 7 });
|
|
465
544
|
this.options.onSuccess?.();
|
|
466
545
|
}
|
|
467
546
|
catch (e) {
|
|
@@ -478,19 +557,34 @@ class AppointmentCalendarWidget {
|
|
|
478
557
|
if (this.state.step === 0) {
|
|
479
558
|
if (!this.state.otpVerified)
|
|
480
559
|
return;
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
560
|
+
console.log("Step 0 transition - Debug info:", {
|
|
561
|
+
allSessionPackResponses: this.state.availablePackages?.length || 0,
|
|
562
|
+
userSessionPacks: this.state.userSessionPacks?.length || 0,
|
|
563
|
+
availablePackages: this.state.availablePackages?.length || 0,
|
|
564
|
+
});
|
|
565
|
+
if (this.state.availablePackages &&
|
|
566
|
+
Array.isArray(this.state.availablePackages) &&
|
|
567
|
+
this.state.availablePackages.length > 0) {
|
|
568
|
+
this.state.step = 1;
|
|
569
|
+
console.log("Showing Booking Option Step - allSessionPackResponses is not empty");
|
|
570
|
+
this.render();
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
this.state.bookingOptionType = "new-appointment";
|
|
575
|
+
this.state.step = 2;
|
|
576
|
+
console.log("Auto-skipping Booking Option Step - allSessionPackResponses is empty");
|
|
577
|
+
this.render();
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
484
580
|
}
|
|
485
581
|
if (this.state.step === 1) {
|
|
486
582
|
if (!this.state.bookingOptionType)
|
|
487
583
|
return;
|
|
488
|
-
if (this.state.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
this.render();
|
|
493
|
-
}
|
|
584
|
+
if (this.state.bookingOptionType === "explore-packages") {
|
|
585
|
+
this.state.showPackageExplorer = true;
|
|
586
|
+
this.state.step = 2;
|
|
587
|
+
this.render();
|
|
494
588
|
return;
|
|
495
589
|
}
|
|
496
590
|
this.state.step = 2;
|
|
@@ -498,6 +592,13 @@ class AppointmentCalendarWidget {
|
|
|
498
592
|
return;
|
|
499
593
|
}
|
|
500
594
|
if (this.state.step === 2) {
|
|
595
|
+
if (this.state.showPackageExplorer) {
|
|
596
|
+
if (this.state.selectedNewPackage) {
|
|
597
|
+
this.state.showPackageExplorer = false;
|
|
598
|
+
this.render();
|
|
599
|
+
}
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
501
602
|
if (this.state.addresses.length > 1 && !this.state.selectedAddress)
|
|
502
603
|
return;
|
|
503
604
|
if (this.doctors.length > 1 && !this.state.selectedDoctor)
|
|
@@ -521,10 +622,16 @@ class AppointmentCalendarWidget {
|
|
|
521
622
|
return;
|
|
522
623
|
}
|
|
523
624
|
if (this.state.step === 4) {
|
|
524
|
-
if (
|
|
625
|
+
if (this.state.selectedPatient && this.state.useExistingPatient) {
|
|
626
|
+
this.state.step = 6;
|
|
627
|
+
this.render();
|
|
525
628
|
return;
|
|
526
|
-
|
|
527
|
-
this.
|
|
629
|
+
}
|
|
630
|
+
if (!this.state.useExistingPatient) {
|
|
631
|
+
this.state.step = 5;
|
|
632
|
+
this.render();
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
528
635
|
return;
|
|
529
636
|
}
|
|
530
637
|
if (this.state.step === 5) {
|
|
@@ -546,44 +653,40 @@ class AppointmentCalendarWidget {
|
|
|
546
653
|
this.render();
|
|
547
654
|
}
|
|
548
655
|
goBack() {
|
|
549
|
-
if (this.state.
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
this.render();
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
this.state.step = 0;
|
|
557
|
-
this.render();
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
if (this.state.step === 2) {
|
|
656
|
+
if (this.state.showPackageExplorer) {
|
|
657
|
+
this.state.showPackageExplorer = false;
|
|
658
|
+
this.state.selectedNewPackage = null;
|
|
659
|
+
this.state.bookingOptionType = null;
|
|
561
660
|
this.state.step = 1;
|
|
562
661
|
this.render();
|
|
563
662
|
return;
|
|
564
663
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
this.
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
664
|
+
const currentStep = this.state.step;
|
|
665
|
+
if (currentStep > 0) {
|
|
666
|
+
if (currentStep === 6 && this.state.useExistingPatient) {
|
|
667
|
+
this.state.selectedPatient = null;
|
|
668
|
+
this.state.useExistingPatient = false;
|
|
669
|
+
this.state.step = 4;
|
|
670
|
+
this.render();
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
if (currentStep === 2) {
|
|
674
|
+
if (this.state.availablePackages &&
|
|
675
|
+
Array.isArray(this.state.availablePackages) &&
|
|
676
|
+
this.state.availablePackages.length > 0) {
|
|
677
|
+
this.state.step = 1;
|
|
678
|
+
console.log("Going back to Booking Option Step - allSessionPackResponses is not empty");
|
|
679
|
+
}
|
|
680
|
+
else {
|
|
681
|
+
this.state.step = 0;
|
|
682
|
+
console.log("Auto-skipping Booking Option Step on back - allSessionPackResponses is empty");
|
|
683
|
+
}
|
|
684
|
+
this.render();
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
this.state.step = currentStep - 1;
|
|
582
688
|
this.render();
|
|
583
|
-
return;
|
|
584
689
|
}
|
|
585
|
-
this.state.step = Math.max(0, this.state.step - 1);
|
|
586
|
-
this.render();
|
|
587
690
|
}
|
|
588
691
|
async reset() {
|
|
589
692
|
this.state = { ...INITIAL_STATE };
|
|
@@ -597,12 +700,8 @@ class AppointmentCalendarWidget {
|
|
|
597
700
|
if ("bloodGroup" in safeUpdates && safeUpdates.bloodGroup === undefined) {
|
|
598
701
|
safeUpdates.bloodGroup = "";
|
|
599
702
|
}
|
|
600
|
-
if ("patientDob" in safeUpdates && safeUpdates.patientDob === undefined) {
|
|
601
|
-
safeUpdates.patientDob = "";
|
|
602
|
-
}
|
|
603
703
|
this.state = { ...this.state, ...safeUpdates };
|
|
604
|
-
if (safeUpdates.bloodGroup !== undefined
|
|
605
|
-
safeUpdates.patientDob !== undefined) {
|
|
704
|
+
if (safeUpdates.bloodGroup !== undefined) {
|
|
606
705
|
this.updatePatientDetailsButtonState();
|
|
607
706
|
this.updateSubmitButtonState();
|
|
608
707
|
}
|
|
@@ -827,30 +926,8 @@ class AppointmentCalendarWidget {
|
|
|
827
926
|
</div>
|
|
828
927
|
</div>
|
|
829
928
|
<div class="medos-actions">
|
|
830
|
-
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
831
929
|
<button class="medos-btn medos-btn-primary" id="medos-btn-send-otp" ${canSendOtp ? "" : "disabled"}>${this.state.otpSending ? "Sending..." : "Continue"}</button>
|
|
832
930
|
</div>
|
|
833
|
-
`;
|
|
834
|
-
}
|
|
835
|
-
if (this.state.otpVerified) {
|
|
836
|
-
return `
|
|
837
|
-
<div class="medos-section-card">
|
|
838
|
-
<div class="medos-section-header">
|
|
839
|
-
${VanillaIcons.phone(14)}
|
|
840
|
-
<span class="medos-section-title">Search Patient</span>
|
|
841
|
-
</div>
|
|
842
|
-
<div class="medos-section-body">
|
|
843
|
-
<div class="medos-verified-badge">
|
|
844
|
-
${VanillaIcons.successBadge(20)}
|
|
845
|
-
<span>Phone verified successfully</span>
|
|
846
|
-
</div>
|
|
847
|
-
<div class="medos-verified-number">${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</div>
|
|
848
|
-
</div>
|
|
849
|
-
</div>
|
|
850
|
-
<div class="medos-actions">
|
|
851
|
-
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
852
|
-
<button class="medos-btn medos-btn-primary" id="medos-btn-next">Continue</button>
|
|
853
|
-
</div>
|
|
854
931
|
`;
|
|
855
932
|
}
|
|
856
933
|
return `
|
|
@@ -885,65 +962,98 @@ class AppointmentCalendarWidget {
|
|
|
885
962
|
renderBookingOptionStep() {
|
|
886
963
|
const hasActivePacks = this.state.userSessionPacks.length > 0;
|
|
887
964
|
const activePack = this.state.userSessionPacks.find((p) => p.remainingSessions > 0);
|
|
965
|
+
const hasAvailablePackages = this.state.availablePackages.length > 0;
|
|
966
|
+
const multipleActivePacks = this.state.userSessionPacks.filter((p) => p.remainingSessions > 0)
|
|
967
|
+
.length > 1;
|
|
888
968
|
return `
|
|
889
969
|
<div class="medos-section-card">
|
|
890
970
|
<div class="medos-section-header">
|
|
891
|
-
|
|
892
|
-
<span class="medos-section-title">Choose Booking Option</span>
|
|
971
|
+
<h3 class="medos-section-title" style="font-size: var(--medos-typography-font-size-xl, 20px);">Choose Booking Option</h3>
|
|
893
972
|
</div>
|
|
894
973
|
<div class="medos-section-body">
|
|
895
|
-
<p class="medos-section-description">
|
|
974
|
+
<p class="medos-section-description">
|
|
975
|
+
How would you like to book your appointment?
|
|
976
|
+
</p>
|
|
896
977
|
|
|
897
|
-
${
|
|
978
|
+
${multipleActivePacks
|
|
898
979
|
? `
|
|
899
|
-
<div class="medos-
|
|
900
|
-
<
|
|
901
|
-
<div class="medos-session-
|
|
980
|
+
<div class="medos-session-packs-section">
|
|
981
|
+
<h4 class="medos-session-packs-title">Your Active Session Packs</h4>
|
|
982
|
+
<div class="medos-session-packs-list">
|
|
983
|
+
${this.state.userSessionPacks
|
|
984
|
+
.filter((pack) => pack.remainingSessions > 0)
|
|
985
|
+
.map((pack) => `
|
|
986
|
+
<div class="medos-session-pack-card ${this.state.bookingOptionType === "session-pack" &&
|
|
987
|
+
this.state.selectedSessionPack?.id === pack.id
|
|
902
988
|
? "selected"
|
|
903
|
-
: ""}" data-pack-id="${
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
989
|
+
: ""}" data-pack-id="${pack.id}">
|
|
990
|
+
<div class="medos-session-pack-info">
|
|
991
|
+
<span class="medos-session-pack-name">${this.escapeHtml(pack.name)}</span>
|
|
992
|
+
<span class="medos-session-pack-remaining">${pack.remainingSessions}/${pack.totalSessions} sessions</span>
|
|
993
|
+
${pack.doctorName
|
|
994
|
+
? `<span class="medos-session-pack-doctor">${this.escapeHtml(pack.doctorName)}</span>`
|
|
995
|
+
: ""}
|
|
996
|
+
</div>
|
|
997
|
+
<div class="medos-session-pack-expiry">
|
|
998
|
+
Expires: ${new Date(pack.expiryDate).toLocaleDateString()}
|
|
999
|
+
</div>
|
|
1000
|
+
</div>
|
|
1001
|
+
`)
|
|
1002
|
+
.join("")}
|
|
911
1003
|
</div>
|
|
912
1004
|
</div>
|
|
1005
|
+
${hasActivePacks ? '<hr style="margin: 6px 0;" />' : ""}
|
|
913
1006
|
`
|
|
914
1007
|
: ""}
|
|
915
1008
|
|
|
916
|
-
<div class="medos-
|
|
917
|
-
|
|
1009
|
+
<div class="medos-options-grid">
|
|
1010
|
+
${activePack && !multipleActivePacks
|
|
1011
|
+
? `
|
|
1012
|
+
<div class="medos-option-card ${this.state.bookingOptionType === "session-pack" &&
|
|
1013
|
+
this.state.selectedSessionPack?.id === activePack.id
|
|
1014
|
+
? "selected"
|
|
1015
|
+
: ""}" data-option="session-pack" data-pack-id="${activePack.id}">
|
|
1016
|
+
<div class="medos-option-icon">📋</div>
|
|
1017
|
+
<h4 class="medos-option-title">Use Session Pack</h4>
|
|
1018
|
+
<p class="medos-option-description">
|
|
1019
|
+
You have ${activePack.remainingSessions} session${activePack.remainingSessions > 1 ? "s" : ""} remaining
|
|
1020
|
+
</p>
|
|
1021
|
+
<div class="medos-session-pack-badge">
|
|
1022
|
+
${this.escapeHtml(activePack.name)}
|
|
1023
|
+
</div>
|
|
1024
|
+
</div>
|
|
1025
|
+
`
|
|
1026
|
+
: ""}
|
|
918
1027
|
|
|
919
|
-
<div class="medos-option-
|
|
920
|
-
<div class="medos-option-card ${this.state.bookingOptionType === "new-appointment"
|
|
1028
|
+
<div class="medos-option-card ${this.state.bookingOptionType === "new-appointment"
|
|
921
1029
|
? "selected"
|
|
922
1030
|
: ""}" data-option="new-appointment">
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1031
|
+
<div class="medos-option-icon">📅</div>
|
|
1032
|
+
<h4 class="medos-option-title">Book New Appointment</h4>
|
|
1033
|
+
<p class="medos-option-description">
|
|
1034
|
+
Schedule a single consultation visit
|
|
1035
|
+
</p>
|
|
1036
|
+
</div>
|
|
1037
|
+
|
|
1038
|
+
${hasAvailablePackages
|
|
1039
|
+
? `
|
|
930
1040
|
<div class="medos-option-card ${this.state.bookingOptionType === "explore-packages"
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
<div class="medos-option-icon"
|
|
934
|
-
<
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
</
|
|
1041
|
+
? "selected"
|
|
1042
|
+
: ""}" data-option="explore-packages">
|
|
1043
|
+
<div class="medos-option-icon">🎁</div>
|
|
1044
|
+
<h4 class="medos-option-title">Explore Packages</h4>
|
|
1045
|
+
<p class="medos-option-description">
|
|
1046
|
+
View and purchase consultation packages
|
|
1047
|
+
</p>
|
|
938
1048
|
</div>
|
|
939
|
-
|
|
1049
|
+
`
|
|
1050
|
+
: ""}
|
|
940
1051
|
</div>
|
|
941
1052
|
</div>
|
|
942
1053
|
</div>
|
|
943
1054
|
<div class="medos-actions">
|
|
944
|
-
<button class="medos-btn medos-btn-
|
|
945
|
-
<button class="medos-btn medos-btn-
|
|
946
|
-
<button class="medos-btn medos-btn-primary" id="medos-btn-continue">Continue</button>
|
|
1055
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1056
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${this.state.bookingOptionType ? "" : "disabled"}>Next</button>
|
|
947
1057
|
</div>
|
|
948
1058
|
`;
|
|
949
1059
|
}
|
|
@@ -975,70 +1085,137 @@ class AppointmentCalendarWidget {
|
|
|
975
1085
|
return `
|
|
976
1086
|
<div class="medos-section-card">
|
|
977
1087
|
<div class="medos-section-header">
|
|
978
|
-
|
|
979
|
-
<span class="medos-section-title">Explore Session Packs</span>
|
|
1088
|
+
<h3 class="medos-section-title" style="font-size: var(--medos-typography-font-size-xl, 20px);">Explore Packages</h3>
|
|
980
1089
|
</div>
|
|
981
1090
|
<div class="medos-section-body">
|
|
982
|
-
<p class="medos-section-description">
|
|
1091
|
+
<p class="medos-section-description">
|
|
1092
|
+
Choose a package that suits your needs
|
|
1093
|
+
</p>
|
|
983
1094
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
<
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1095
|
+
${packages.length > 0
|
|
1096
|
+
? `
|
|
1097
|
+
<div class="medos-packages-grid">
|
|
1098
|
+
${packages
|
|
1099
|
+
.map((pkg) => `
|
|
1100
|
+
<div class="medos-package-card ${this.state.selectedNewPackage?.id === pkg.id ? "selected" : ""}" data-package-id="${pkg.id}">
|
|
1101
|
+
<h4 class="medos-package-name">${this.escapeHtml(pkg.name)}</h4>
|
|
1102
|
+
<p class="medos-package-description">
|
|
1103
|
+
${this.escapeHtml(pkg.description || "").replace(/\n/g, "<br>")}
|
|
1104
|
+
</p>
|
|
1105
|
+
|
|
1106
|
+
${pkg.allowedDoctors && pkg.allowedDoctors.length > 0
|
|
1107
|
+
? `
|
|
1108
|
+
<div class="medos-package-doctors">
|
|
1109
|
+
${pkg.allowedDoctors
|
|
1110
|
+
.map((doc) => `
|
|
1111
|
+
<span class="medos-doctor-badge">
|
|
1112
|
+
${this.escapeHtml(doc.fullName)}
|
|
1113
|
+
</span>
|
|
1114
|
+
`)
|
|
1115
|
+
.join("")}
|
|
1116
|
+
</div>
|
|
1117
|
+
`
|
|
1118
|
+
: ""}
|
|
1119
|
+
|
|
1120
|
+
${pkg.allowedConsultationModes &&
|
|
1121
|
+
pkg.allowedConsultationModes.length > 0
|
|
1122
|
+
? `
|
|
1123
|
+
<div class="medos-consultation-modes">
|
|
1124
|
+
${pkg.allowedConsultationModes
|
|
1125
|
+
.map((mode) => `
|
|
1126
|
+
<span class="medos-mode-badge">
|
|
1127
|
+
${mode === "ONLINE" ? "🌐 Online" : "🏥 In-Person"}
|
|
1128
|
+
</span>
|
|
1129
|
+
`)
|
|
1130
|
+
.join("")}
|
|
1131
|
+
</div>
|
|
1132
|
+
`
|
|
1133
|
+
: ""}
|
|
1134
|
+
|
|
1135
|
+
<div class="medos-package-details">
|
|
1136
|
+
<span class="medos-package-sessions">
|
|
1137
|
+
${pkg.totalSessions || pkg.sessions} session${(pkg.totalSessions || pkg.sessions || 1) > 1 ? "s" : ""}
|
|
1138
|
+
</span>
|
|
1139
|
+
<div class="medos-package-price-container">
|
|
1140
|
+
${pkg.discountedPrice && pkg.discountedPrice < pkg.price
|
|
1141
|
+
? `
|
|
1142
|
+
<span class="medos-original-price">
|
|
1143
|
+
₹${pkg.price.toLocaleString()}
|
|
1144
|
+
</span>
|
|
1145
|
+
<span class="medos-package-price">
|
|
1146
|
+
₹${pkg.discountedPrice.toLocaleString()}
|
|
1147
|
+
</span>
|
|
1148
|
+
<span class="medos-per-session-price">
|
|
1149
|
+
₹${Math.round(pkg.discountedPrice /
|
|
1150
|
+
(pkg.totalSessions || pkg.sessions || 1)).toLocaleString()}/session
|
|
1151
|
+
</span>
|
|
1152
|
+
${pkg.discount
|
|
1153
|
+
? `
|
|
1154
|
+
<span class="medos-discount-badge">
|
|
1155
|
+
${pkg.discountType === "PERCENTAGE"
|
|
1156
|
+
? `${pkg.discount}% OFF`
|
|
1157
|
+
: `₹${pkg.discount} OFF`}
|
|
1158
|
+
</span>
|
|
1159
|
+
`
|
|
1160
|
+
: ""}
|
|
1161
|
+
`
|
|
1162
|
+
: `
|
|
1163
|
+
<span class="medos-package-price">
|
|
1164
|
+
₹${pkg.price.toLocaleString()}
|
|
1165
|
+
</span>
|
|
1166
|
+
<span class="medos-per-session-price">
|
|
1167
|
+
₹${Math.round(pkg.price / (pkg.totalSessions || pkg.sessions || 1)).toLocaleString()}/session
|
|
1168
|
+
</span>
|
|
1169
|
+
`}
|
|
1170
|
+
</div>
|
|
1171
|
+
</div>
|
|
1172
|
+
<div class="medos-package-validity">
|
|
1173
|
+
Valid for ${pkg.validityDays} days
|
|
1174
|
+
</div>
|
|
996
1175
|
</div>
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1176
|
+
`)
|
|
1177
|
+
.join("")}
|
|
1178
|
+
</div>
|
|
1179
|
+
`
|
|
1180
|
+
: `
|
|
1181
|
+
<div style="text-align: center; padding: 40px 20px; color: var(--medos-color-text-secondary, #6b7280); font-size: var(--medos-typography-font-size-sm, 14px);">
|
|
1182
|
+
<p>No packages available at the moment.</p>
|
|
1183
|
+
</div>
|
|
1184
|
+
`}
|
|
1006
1185
|
</div>
|
|
1007
1186
|
</div>
|
|
1008
1187
|
<div class="medos-actions">
|
|
1009
|
-
<button class="medos-btn medos-btn-
|
|
1010
|
-
<button class="medos-btn medos-btn-
|
|
1011
|
-
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${this.state.selectedNewPackage ? "" : "disabled"}>Continue</button>
|
|
1188
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-back">Back</button>
|
|
1189
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${this.state.selectedNewPackage ? "" : "disabled"}>Next</button>
|
|
1012
1190
|
</div>
|
|
1013
1191
|
`;
|
|
1014
1192
|
}
|
|
1015
1193
|
renderLocationDoctorStep() {
|
|
1016
1194
|
const canProceed = this.canProceedFromMergedStep();
|
|
1017
1195
|
return `
|
|
1018
|
-
<div
|
|
1019
|
-
<div
|
|
1196
|
+
<div class="medos-section-card">
|
|
1197
|
+
<div class="medos-section-header">
|
|
1020
1198
|
${VanillaIcons.mapPin(18)}
|
|
1021
|
-
<h3
|
|
1199
|
+
<h3 class="medos-section-title">Location & Doctor</h3>
|
|
1022
1200
|
</div>
|
|
1023
|
-
<div
|
|
1024
|
-
<div
|
|
1025
|
-
<label
|
|
1026
|
-
Preferred Location <span
|
|
1201
|
+
<div class="medos-section-body">
|
|
1202
|
+
<div class="medos-form-group">
|
|
1203
|
+
<label class="medos-label">
|
|
1204
|
+
Preferred Location <span class="medos-required">*</span>
|
|
1027
1205
|
</label>
|
|
1028
1206
|
<div id="medos-address-select-container"></div>
|
|
1029
1207
|
</div>
|
|
1030
|
-
<div
|
|
1031
|
-
<label
|
|
1032
|
-
Preferred Doctor <span
|
|
1208
|
+
<div class="medos-form-group">
|
|
1209
|
+
<label class="medos-label">
|
|
1210
|
+
Preferred Doctor <span class="medos-required">*</span>
|
|
1033
1211
|
</label>
|
|
1034
1212
|
<div id="medos-doctor-select-container"></div>
|
|
1035
1213
|
</div>
|
|
1036
|
-
<div
|
|
1037
|
-
<label
|
|
1038
|
-
Chief Complaint <span
|
|
1214
|
+
<div class="medos-form-group">
|
|
1215
|
+
<label class="medos-label">
|
|
1216
|
+
Chief Complaint <span class="medos-optional">(optional)</span>
|
|
1039
1217
|
</label>
|
|
1040
1218
|
<textarea
|
|
1041
|
-
style="width:100%;padding:10px 12px;border-radius:8px;border:1px solid #e6e9ef;font-size:14px;box-sizing:border-box;"
|
|
1042
1219
|
class="medos-textarea"
|
|
1043
1220
|
id="medos-chief-complaint"
|
|
1044
1221
|
placeholder="Enter Chief Complaint or Appointment Notes"
|
|
@@ -1046,9 +1223,9 @@ class AppointmentCalendarWidget {
|
|
|
1046
1223
|
</div>
|
|
1047
1224
|
</div>
|
|
1048
1225
|
</div>
|
|
1049
|
-
<div
|
|
1050
|
-
<button class="medos-btn medos-btn-
|
|
1051
|
-
<button
|
|
1226
|
+
<div class="medos-actions">
|
|
1227
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1228
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-next" ${canProceed ? "" : "disabled"}>Continue</button>
|
|
1052
1229
|
</div>
|
|
1053
1230
|
`;
|
|
1054
1231
|
}
|
|
@@ -1072,6 +1249,7 @@ class AppointmentCalendarWidget {
|
|
|
1072
1249
|
</div>
|
|
1073
1250
|
`
|
|
1074
1251
|
: "";
|
|
1252
|
+
const slotsByPeriod = this.groupSlotsByPeriod(this.state.slots);
|
|
1075
1253
|
return `
|
|
1076
1254
|
<div class="medos-section-card">
|
|
1077
1255
|
<div class="medos-section-header">
|
|
@@ -1089,7 +1267,7 @@ class AppointmentCalendarWidget {
|
|
|
1089
1267
|
${this.state.consultationMode === "OFFLINE" ? "checked" : ""}
|
|
1090
1268
|
class="medos-radio-input"
|
|
1091
1269
|
/>
|
|
1092
|
-
<span class="medos-radio-label">
|
|
1270
|
+
<span class="medos-radio-label">Offline</span>
|
|
1093
1271
|
</label>
|
|
1094
1272
|
<label class="medos-radio-option ${this.state.consultationMode === "ONLINE" ? "selected" : ""}">
|
|
1095
1273
|
<input
|
|
@@ -1099,7 +1277,7 @@ class AppointmentCalendarWidget {
|
|
|
1099
1277
|
${this.state.consultationMode === "ONLINE" ? "checked" : ""}
|
|
1100
1278
|
class="medos-radio-input"
|
|
1101
1279
|
/>
|
|
1102
|
-
<span class="medos-radio-label">
|
|
1280
|
+
<span class="medos-radio-label">Online</span>
|
|
1103
1281
|
</label>
|
|
1104
1282
|
</div>
|
|
1105
1283
|
</div>
|
|
@@ -1120,129 +1298,93 @@ class AppointmentCalendarWidget {
|
|
|
1120
1298
|
<label class="medos-form-label">Available Slots</label>
|
|
1121
1299
|
${this.state.slots.length === 0
|
|
1122
1300
|
? '<div class="medos-empty-slots">Select a date to see available slots</div>'
|
|
1123
|
-
:
|
|
1124
|
-
<div class="medos-slots-grid-compact">
|
|
1125
|
-
${this.state.slots
|
|
1126
|
-
.map((s) => {
|
|
1127
|
-
const start = new Date(s.start).toLocaleTimeString([], {
|
|
1128
|
-
hour: "2-digit",
|
|
1129
|
-
minute: "2-digit",
|
|
1130
|
-
});
|
|
1131
|
-
const end = new Date(s.end).toLocaleTimeString([], {
|
|
1132
|
-
hour: "2-digit",
|
|
1133
|
-
minute: "2-digit",
|
|
1134
|
-
});
|
|
1135
|
-
const selected = this.state.selectedSlot?.start === s.start &&
|
|
1136
|
-
this.state.selectedSlot?.end === s.end;
|
|
1137
|
-
return `
|
|
1138
|
-
<div class="medos-slot-btn ${selected ? "selected" : ""}"
|
|
1139
|
-
data-slot-id="${this.escapeHtml(s.id || `${s.start}-${s.end}`)}"
|
|
1140
|
-
data-slot-start="${this.escapeHtml(s.start)}"
|
|
1141
|
-
data-slot-end="${this.escapeHtml(s.end)}">
|
|
1142
|
-
${start}
|
|
1143
|
-
</div>
|
|
1144
|
-
`;
|
|
1145
|
-
})
|
|
1146
|
-
.join("")}
|
|
1147
|
-
</div>
|
|
1148
|
-
`}
|
|
1301
|
+
: this.renderGroupedSlots(slotsByPeriod)}
|
|
1149
1302
|
</div>
|
|
1150
1303
|
</div>
|
|
1151
1304
|
</div>
|
|
1152
1305
|
|
|
1153
1306
|
<div class="medos-actions">
|
|
1154
|
-
<button class="medos-btn medos-btn-
|
|
1155
|
-
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
1307
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1156
1308
|
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${this.state.selectedSlot ? "" : "disabled"}>Continue</button>
|
|
1157
1309
|
</div>
|
|
1158
1310
|
`;
|
|
1159
1311
|
}
|
|
1312
|
+
groupSlotsByPeriod(slots) {
|
|
1313
|
+
const groups = {
|
|
1314
|
+
Morning: [],
|
|
1315
|
+
Afternoon: [],
|
|
1316
|
+
Evening: [],
|
|
1317
|
+
};
|
|
1318
|
+
slots.forEach((slot) => {
|
|
1319
|
+
const startTime = new Date(slot.start);
|
|
1320
|
+
const hours = startTime.getHours();
|
|
1321
|
+
let period = "Morning";
|
|
1322
|
+
if (hours >= 12 && hours < 17) {
|
|
1323
|
+
period = "Afternoon";
|
|
1324
|
+
}
|
|
1325
|
+
else if (hours >= 17) {
|
|
1326
|
+
period = "Evening";
|
|
1327
|
+
}
|
|
1328
|
+
groups[period].push(slot);
|
|
1329
|
+
});
|
|
1330
|
+
return groups;
|
|
1331
|
+
}
|
|
1332
|
+
renderGroupedSlots(slotsByPeriod) {
|
|
1333
|
+
const periods = ["Morning", "Afternoon", "Evening"];
|
|
1334
|
+
return `
|
|
1335
|
+
<div class="medos-slots-container-grouped">
|
|
1336
|
+
${periods
|
|
1337
|
+
.filter((period) => slotsByPeriod[period].length > 0)
|
|
1338
|
+
.map((period) => `
|
|
1339
|
+
<div class="medos-slot-period">
|
|
1340
|
+
<div class="medos-slot-period-header">
|
|
1341
|
+
<span class="medos-slot-period-title">${period.toUpperCase()}</span>
|
|
1342
|
+
<span class="medos-slot-period-count">${slotsByPeriod[period].length} ${slotsByPeriod[period].length === 1 ? "slot" : "slots"}</span>
|
|
1343
|
+
</div>
|
|
1344
|
+
<div class="medos-slot-period-grid">
|
|
1345
|
+
${slotsByPeriod[period]
|
|
1346
|
+
.map((slot) => {
|
|
1347
|
+
const startDate = new Date(slot.start);
|
|
1348
|
+
const endDate = new Date(slot.end);
|
|
1349
|
+
const startTime = startDate.toLocaleTimeString([], {
|
|
1350
|
+
hour: "2-digit",
|
|
1351
|
+
minute: "2-digit",
|
|
1352
|
+
});
|
|
1353
|
+
const endTime = endDate.toLocaleTimeString([], {
|
|
1354
|
+
hour: "2-digit",
|
|
1355
|
+
minute: "2-digit",
|
|
1356
|
+
});
|
|
1357
|
+
const durationMinutes = Math.round((endDate.getTime() - startDate.getTime()) / (1000 * 60));
|
|
1358
|
+
const selected = this.state.selectedSlot?.start === slot.start &&
|
|
1359
|
+
this.state.selectedSlot?.end === slot.end;
|
|
1360
|
+
return `
|
|
1361
|
+
<button type="button" class="medos-slot-btn ${selected ? "selected" : ""}"
|
|
1362
|
+
data-slot-id="${this.escapeHtml(slot.id || `${slot.start}-${slot.end}`)}"
|
|
1363
|
+
data-slot-start="${this.escapeHtml(slot.start)}"
|
|
1364
|
+
data-slot-end="${this.escapeHtml(slot.end)}"
|
|
1365
|
+
${selected
|
|
1366
|
+
? 'aria-pressed="true"'
|
|
1367
|
+
: 'aria-pressed="false"'}
|
|
1368
|
+
aria-label="Select ${startTime} to ${endTime} time slot">
|
|
1369
|
+
<span class="medos-slot-time-range">
|
|
1370
|
+
<span class="medos-slot-start-time">${startTime}</span>
|
|
1371
|
+
<span class="medos-slot-separator">–</span>
|
|
1372
|
+
<span class="medos-slot-end-time">${endTime}</span>
|
|
1373
|
+
</span>
|
|
1374
|
+
<span class="medos-slot-duration">${durationMinutes}m</span>
|
|
1375
|
+
</button>
|
|
1376
|
+
`;
|
|
1377
|
+
})
|
|
1378
|
+
.join("")}
|
|
1379
|
+
</div>
|
|
1380
|
+
</div>
|
|
1381
|
+
`)
|
|
1382
|
+
.join("")}
|
|
1383
|
+
</div>
|
|
1384
|
+
`;
|
|
1385
|
+
}
|
|
1160
1386
|
renderPatientSelectionStep() {
|
|
1161
|
-
const
|
|
1162
|
-
? this.state.verifiedPatients
|
|
1163
|
-
: [
|
|
1164
|
-
{
|
|
1165
|
-
id: 1,
|
|
1166
|
-
firstName: "Mumma",
|
|
1167
|
-
lastName: "Bear",
|
|
1168
|
-
email: "mumma@example.com",
|
|
1169
|
-
countryCode: "+91",
|
|
1170
|
-
phoneNumber: this.state.patientPhone,
|
|
1171
|
-
dob: "1970-01-01",
|
|
1172
|
-
age: 55,
|
|
1173
|
-
gender: "FEMALE",
|
|
1174
|
-
bloodGroup: "O+",
|
|
1175
|
-
mrn: "MRN001",
|
|
1176
|
-
address: {
|
|
1177
|
-
id: 1,
|
|
1178
|
-
completeAddress: "123 Main St",
|
|
1179
|
-
addressLine1: "123 Main St",
|
|
1180
|
-
addressLine2: "",
|
|
1181
|
-
city: "Mumbai",
|
|
1182
|
-
state: "Maharashtra",
|
|
1183
|
-
country: "India",
|
|
1184
|
-
zipcode: "400001",
|
|
1185
|
-
landmark: "",
|
|
1186
|
-
phoneNumber: this.state.patientPhone,
|
|
1187
|
-
latitude: 0,
|
|
1188
|
-
longitude: 0,
|
|
1189
|
-
},
|
|
1190
|
-
},
|
|
1191
|
-
{
|
|
1192
|
-
id: 2,
|
|
1193
|
-
firstName: "Papa",
|
|
1194
|
-
lastName: "Bear",
|
|
1195
|
-
email: "papa@example.com",
|
|
1196
|
-
countryCode: "+91",
|
|
1197
|
-
phoneNumber: this.state.patientPhone,
|
|
1198
|
-
dob: "1968-01-01",
|
|
1199
|
-
age: 57,
|
|
1200
|
-
gender: "MALE",
|
|
1201
|
-
bloodGroup: "B+",
|
|
1202
|
-
mrn: "MRN002",
|
|
1203
|
-
address: {
|
|
1204
|
-
id: 2,
|
|
1205
|
-
completeAddress: "123 Main St",
|
|
1206
|
-
addressLine1: "123 Main St",
|
|
1207
|
-
addressLine2: "",
|
|
1208
|
-
city: "Mumbai",
|
|
1209
|
-
state: "Maharashtra",
|
|
1210
|
-
country: "India",
|
|
1211
|
-
zipcode: "400001",
|
|
1212
|
-
landmark: "",
|
|
1213
|
-
phoneNumber: this.state.patientPhone,
|
|
1214
|
-
latitude: 0,
|
|
1215
|
-
longitude: 0,
|
|
1216
|
-
},
|
|
1217
|
-
},
|
|
1218
|
-
{
|
|
1219
|
-
id: 3,
|
|
1220
|
-
firstName: "Monty",
|
|
1221
|
-
lastName: "Bear",
|
|
1222
|
-
email: "monty@example.com",
|
|
1223
|
-
countryCode: "+91",
|
|
1224
|
-
phoneNumber: this.state.patientPhone,
|
|
1225
|
-
dob: "1990-01-01",
|
|
1226
|
-
age: 35,
|
|
1227
|
-
gender: "MALE",
|
|
1228
|
-
bloodGroup: "A+",
|
|
1229
|
-
mrn: "MRN003",
|
|
1230
|
-
address: {
|
|
1231
|
-
id: 3,
|
|
1232
|
-
completeAddress: "123 Main St",
|
|
1233
|
-
addressLine1: "123 Main St",
|
|
1234
|
-
addressLine2: "",
|
|
1235
|
-
city: "Mumbai",
|
|
1236
|
-
state: "Maharashtra",
|
|
1237
|
-
country: "India",
|
|
1238
|
-
zipcode: "400001",
|
|
1239
|
-
landmark: "",
|
|
1240
|
-
phoneNumber: this.state.patientPhone,
|
|
1241
|
-
latitude: 0,
|
|
1242
|
-
longitude: 0,
|
|
1243
|
-
},
|
|
1244
|
-
},
|
|
1245
|
-
];
|
|
1387
|
+
const hasVerifiedPatients = this.state.verifiedPatients.length > 0;
|
|
1246
1388
|
return `
|
|
1247
1389
|
<div class="medos-section-card">
|
|
1248
1390
|
<div class="medos-section-header">
|
|
@@ -1250,25 +1392,40 @@ class AppointmentCalendarWidget {
|
|
|
1250
1392
|
<span class="medos-section-title">Select Patient</span>
|
|
1251
1393
|
</div>
|
|
1252
1394
|
<div class="medos-section-body">
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1395
|
+
${hasVerifiedPatients
|
|
1396
|
+
? `
|
|
1397
|
+
<div class="medos-patient-list">
|
|
1398
|
+
${this.state.verifiedPatients
|
|
1399
|
+
.map((patient) => `
|
|
1400
|
+
<div class="medos-patient-card ${this.state.selectedPatient?.id === patient.id
|
|
1401
|
+
? "selected"
|
|
1402
|
+
: ""}" data-patient-id="${patient.id}">
|
|
1403
|
+
<div class="medos-patient-radio">
|
|
1404
|
+
<input type="radio" name="patient" value="${patient.id}" ${this.state.selectedPatient?.id === patient.id
|
|
1405
|
+
? "checked"
|
|
1406
|
+
: ""} />
|
|
1407
|
+
</div>
|
|
1408
|
+
<div class="medos-patient-avatar">
|
|
1409
|
+
${patient.firstName.charAt(0)}${patient.lastName.charAt(0)}
|
|
1410
|
+
</div>
|
|
1411
|
+
<div class="medos-patient-info">
|
|
1412
|
+
<div class="medos-patient-name">${this.escapeHtml(patient.firstName)} ${this.escapeHtml(patient.lastName)}</div>
|
|
1413
|
+
<div class="medos-patient-details">${this.escapeHtml(patient.countryCode)} ${this.escapeHtml(patient.phoneNumber)}</div>
|
|
1414
|
+
${patient.age
|
|
1415
|
+
? `<div class="medos-patient-age">Age: ${patient.age}</div>`
|
|
1416
|
+
: ""}
|
|
1417
|
+
</div>
|
|
1418
|
+
<div class="medos-patient-select">select</div>
|
|
1266
1419
|
</div>
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1420
|
+
`)
|
|
1421
|
+
.join("")}
|
|
1422
|
+
</div>
|
|
1423
|
+
`
|
|
1424
|
+
: `
|
|
1425
|
+
<div class="medos-no-patients">
|
|
1426
|
+
<p>No existing patients found for this phone number.</p>
|
|
1427
|
+
</div>
|
|
1428
|
+
`}
|
|
1272
1429
|
|
|
1273
1430
|
<button class="medos-add-patient-btn" id="medos-btn-add-patient">
|
|
1274
1431
|
${VanillaIcons.plus(16)} New Patient
|
|
@@ -1276,8 +1433,7 @@ class AppointmentCalendarWidget {
|
|
|
1276
1433
|
</div>
|
|
1277
1434
|
</div>
|
|
1278
1435
|
<div class="medos-actions">
|
|
1279
|
-
<button class="medos-btn medos-btn-
|
|
1280
|
-
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
1436
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1281
1437
|
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${this.state.selectedPatient ? "" : "disabled"}>Continue</button>
|
|
1282
1438
|
</div>
|
|
1283
1439
|
`;
|
|
@@ -1302,7 +1458,7 @@ class AppointmentCalendarWidget {
|
|
|
1302
1458
|
<div class="medos-form-row">
|
|
1303
1459
|
<div class="medos-form-field">
|
|
1304
1460
|
<label class="medos-form-label">
|
|
1305
|
-
First Name <span
|
|
1461
|
+
First Name <span class="medos-required">*</span>
|
|
1306
1462
|
</label>
|
|
1307
1463
|
<input
|
|
1308
1464
|
type="text"
|
|
@@ -1314,7 +1470,7 @@ class AppointmentCalendarWidget {
|
|
|
1314
1470
|
</div>
|
|
1315
1471
|
<div class="medos-form-field">
|
|
1316
1472
|
<label class="medos-form-label">
|
|
1317
|
-
Last Name <span
|
|
1473
|
+
Last Name <span class="medos-required">*</span>
|
|
1318
1474
|
</label>
|
|
1319
1475
|
<input
|
|
1320
1476
|
type="text"
|
|
@@ -1329,7 +1485,7 @@ class AppointmentCalendarWidget {
|
|
|
1329
1485
|
<div class="medos-form-row">
|
|
1330
1486
|
<div class="medos-form-field">
|
|
1331
1487
|
<label class="medos-form-label">
|
|
1332
|
-
Age <span
|
|
1488
|
+
Age <span class="medos-required">*</span>
|
|
1333
1489
|
</label>
|
|
1334
1490
|
<input
|
|
1335
1491
|
type="number"
|
|
@@ -1356,7 +1512,7 @@ class AppointmentCalendarWidget {
|
|
|
1356
1512
|
<div class="medos-form-row">
|
|
1357
1513
|
<div class="medos-form-field">
|
|
1358
1514
|
<label class="medos-form-label">
|
|
1359
|
-
Gender <span
|
|
1515
|
+
Gender <span class="medos-required">*</span>
|
|
1360
1516
|
</label>
|
|
1361
1517
|
<div id="medos-gender-select-container"></div>
|
|
1362
1518
|
</div>
|
|
@@ -1366,22 +1522,6 @@ class AppointmentCalendarWidget {
|
|
|
1366
1522
|
</div>
|
|
1367
1523
|
</div>
|
|
1368
1524
|
|
|
1369
|
-
<div class="medos-form-row">
|
|
1370
|
-
<div class="medos-form-field">
|
|
1371
|
-
<label class="medos-form-label">Date of Birth</label>
|
|
1372
|
-
<input
|
|
1373
|
-
type="date"
|
|
1374
|
-
class="medos-appointment-input"
|
|
1375
|
-
id="medos-patient-dob"
|
|
1376
|
-
value="${this.escapeHtml(this.state.patientDob)}"
|
|
1377
|
-
/>
|
|
1378
|
-
${this.state.patientDob &&
|
|
1379
|
-
this.state.patientDob.trim() !== "" &&
|
|
1380
|
-
!this.isValidDateOfBirth(this.state.patientDob)
|
|
1381
|
-
? this.getDateOfBirthErrorMessage(this.state.patientDob)
|
|
1382
|
-
: ""}
|
|
1383
|
-
</div>
|
|
1384
|
-
</div>
|
|
1385
1525
|
</div>
|
|
1386
1526
|
</div>
|
|
1387
1527
|
|
|
@@ -1394,7 +1534,7 @@ class AppointmentCalendarWidget {
|
|
|
1394
1534
|
<div class="medos-section-body">
|
|
1395
1535
|
<div class="medos-form-field">
|
|
1396
1536
|
<label class="medos-form-label">
|
|
1397
|
-
Address <span
|
|
1537
|
+
Address <span class="medos-required">*</span>
|
|
1398
1538
|
</label>
|
|
1399
1539
|
<input
|
|
1400
1540
|
type="text"
|
|
@@ -1408,7 +1548,7 @@ class AppointmentCalendarWidget {
|
|
|
1408
1548
|
<div class="medos-form-row">
|
|
1409
1549
|
<div class="medos-form-field">
|
|
1410
1550
|
<label class="medos-form-label">
|
|
1411
|
-
City <span
|
|
1551
|
+
City <span class="medos-required">*</span>
|
|
1412
1552
|
</label>
|
|
1413
1553
|
<input
|
|
1414
1554
|
type="text"
|
|
@@ -1420,7 +1560,7 @@ class AppointmentCalendarWidget {
|
|
|
1420
1560
|
</div>
|
|
1421
1561
|
<div class="medos-form-field">
|
|
1422
1562
|
<label class="medos-form-label">
|
|
1423
|
-
State <span
|
|
1563
|
+
State <span class="medos-required">*</span>
|
|
1424
1564
|
</label>
|
|
1425
1565
|
<input
|
|
1426
1566
|
type="text"
|
|
@@ -1435,7 +1575,7 @@ class AppointmentCalendarWidget {
|
|
|
1435
1575
|
<div class="medos-form-row">
|
|
1436
1576
|
<div class="medos-form-field">
|
|
1437
1577
|
<label class="medos-form-label">
|
|
1438
|
-
Country <span
|
|
1578
|
+
Country <span class="medos-required">*</span>
|
|
1439
1579
|
</label>
|
|
1440
1580
|
<input
|
|
1441
1581
|
type="text"
|
|
@@ -1447,7 +1587,7 @@ class AppointmentCalendarWidget {
|
|
|
1447
1587
|
</div>
|
|
1448
1588
|
<div class="medos-form-field">
|
|
1449
1589
|
<label class="medos-form-label">
|
|
1450
|
-
Zipcode <span
|
|
1590
|
+
Zipcode <span class="medos-required">*</span>
|
|
1451
1591
|
</label>
|
|
1452
1592
|
<input
|
|
1453
1593
|
type="text"
|
|
@@ -1473,8 +1613,7 @@ class AppointmentCalendarWidget {
|
|
|
1473
1613
|
</div>
|
|
1474
1614
|
|
|
1475
1615
|
<div class="medos-actions">
|
|
1476
|
-
<button class="medos-btn medos-btn-
|
|
1477
|
-
<button class="medos-btn medos-btn-secondary" id="medos-btn-cancel">Cancel</button>
|
|
1616
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-back">${VanillaIcons.arrowLeft(14)} Back</button>
|
|
1478
1617
|
<button class="medos-btn medos-btn-primary" id="medos-btn-continue" ${isFormValid ? "" : "disabled"}>Continue</button>
|
|
1479
1618
|
</div>
|
|
1480
1619
|
`;
|
|
@@ -1482,139 +1621,223 @@ class AppointmentCalendarWidget {
|
|
|
1482
1621
|
renderAppointmentSummaryStep() {
|
|
1483
1622
|
const selectedDoctor = this.doctors.find((d) => d.id === this.state.selectedDoctor);
|
|
1484
1623
|
const selectedAddress = this.state.addresses.find((addr) => addr.id === this.state.selectedAddress);
|
|
1485
|
-
const
|
|
1486
|
-
? this.state.selectedDate.toLocaleDateString("en-US", {
|
|
1487
|
-
weekday: "short",
|
|
1488
|
-
year: "numeric",
|
|
1489
|
-
month: "short",
|
|
1490
|
-
day: "numeric",
|
|
1491
|
-
})
|
|
1492
|
-
: "";
|
|
1493
|
-
const startTime = this.state.selectedSlot?.start
|
|
1494
|
-
? new Date(this.state.selectedSlot.start).toLocaleTimeString([], {
|
|
1495
|
-
hour: "2-digit",
|
|
1496
|
-
minute: "2-digit",
|
|
1497
|
-
})
|
|
1498
|
-
: "";
|
|
1499
|
-
const usingSessionPack = this.state.bookingOptionType === "session-pack" &&
|
|
1624
|
+
const usingSessionPack = this.state.bookingType === "USE_ACTIVE_PACKAGE" &&
|
|
1500
1625
|
this.state.selectedSessionPack;
|
|
1501
|
-
const usingNewPackage = this.state.
|
|
1626
|
+
const usingNewPackage = this.state.bookingType === "PACKAGE_PURCHASE" &&
|
|
1502
1627
|
this.state.selectedNewPackage;
|
|
1503
|
-
const
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1628
|
+
const isPackageBooking = this.state.bookingType === "PACKAGE_PURCHASE" ||
|
|
1629
|
+
this.state.bookingType === "USE_ACTIVE_PACKAGE";
|
|
1630
|
+
const getDuration = () => {
|
|
1631
|
+
if (this.state.selectedSlot) {
|
|
1632
|
+
return calculateDuration(this.state.selectedSlot.start, this.state.selectedSlot.end);
|
|
1633
|
+
}
|
|
1634
|
+
return 60;
|
|
1635
|
+
};
|
|
1636
|
+
const getPaymentInfo = () => {
|
|
1637
|
+
if (usingSessionPack) {
|
|
1638
|
+
return {
|
|
1639
|
+
type: "Session Pack",
|
|
1640
|
+
name: this.state.selectedSessionPack?.name || "Session Pack",
|
|
1641
|
+
amount: "Prepaid",
|
|
1642
|
+
remaining: `${(this.state.selectedSessionPack?.remainingSessions || 1) - 1} sessions remaining after this appointment`,
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
else if (usingNewPackage) {
|
|
1646
|
+
return {
|
|
1647
|
+
type: "New Package",
|
|
1648
|
+
name: this.state.selectedNewPackage?.name || "Package",
|
|
1649
|
+
amount: `₹${this.state.selectedNewPackage?.price?.toLocaleString() || 0}`,
|
|
1650
|
+
remaining: `${this.state.selectedNewPackage?.totalSessions ||
|
|
1651
|
+
this.state.selectedNewPackage?.sessions ||
|
|
1652
|
+
1} sessions included`,
|
|
1653
|
+
};
|
|
1654
|
+
}
|
|
1655
|
+
else {
|
|
1656
|
+
return {
|
|
1657
|
+
type: "Single Appointment",
|
|
1658
|
+
name: this.state.consultationMode === "ONLINE"
|
|
1659
|
+
? "Online Consultation"
|
|
1660
|
+
: "In-Person Visit",
|
|
1661
|
+
amount: this.state.consultationCharge
|
|
1662
|
+
? `₹${this.state.consultationCharge}`
|
|
1663
|
+
: "Pay at clinic",
|
|
1664
|
+
};
|
|
1665
|
+
}
|
|
1666
|
+
};
|
|
1667
|
+
const paymentInfo = getPaymentInfo();
|
|
1668
|
+
const patient = this.state.selectedPatient;
|
|
1669
|
+
const patientName = patient
|
|
1670
|
+
? `${patient.firstName} ${patient.lastName}`
|
|
1671
|
+
: this.state.patientName || "New Patient";
|
|
1527
1672
|
return `
|
|
1528
|
-
<div class="medos-
|
|
1529
|
-
<
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
</
|
|
1533
|
-
|
|
1673
|
+
<div class="medos-summary-container">
|
|
1674
|
+
<h3 class="medos-summary-title">Appointment Summary</h3>
|
|
1675
|
+
<p class="medos-summary-subtitle">
|
|
1676
|
+
Please review your appointment details before confirming
|
|
1677
|
+
</p>
|
|
1678
|
+
|
|
1679
|
+
<!-- Patient Information -->
|
|
1534
1680
|
<div class="medos-summary-section">
|
|
1535
|
-
<
|
|
1536
|
-
|
|
1537
|
-
<div class="medos-summary-grid">
|
|
1681
|
+
<h4 class="medos-summary-section-title">👤 Patient Information</h4>
|
|
1682
|
+
<div class="medos-summary-card">
|
|
1538
1683
|
<div class="medos-summary-row">
|
|
1539
|
-
<span class="medos-summary-label">
|
|
1684
|
+
<span class="medos-summary-label">Name</span>
|
|
1540
1685
|
<span class="medos-summary-value">${this.escapeHtml(patientName)}</span>
|
|
1541
1686
|
</div>
|
|
1542
|
-
${this.state.
|
|
1543
|
-
?
|
|
1544
|
-
|
|
1545
|
-
<span class="medos-summary-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
? `<div class="medos-summary-row">
|
|
1550
|
-
<span class="medos-summary-label">Blood Group:</span>
|
|
1551
|
-
<span class="medos-summary-value">${this.escapeHtml(this.state.bloodGroup)}</span>
|
|
1552
|
-
</div>`
|
|
1687
|
+
${patient?.email || this.state.patientEmail
|
|
1688
|
+
? `
|
|
1689
|
+
<div class="medos-summary-row">
|
|
1690
|
+
<span class="medos-summary-label">Email</span>
|
|
1691
|
+
<span class="medos-summary-value">${this.escapeHtml(patient?.email || this.state.patientEmail || "")}</span>
|
|
1692
|
+
</div>
|
|
1693
|
+
`
|
|
1553
1694
|
: ""}
|
|
1554
1695
|
<div class="medos-summary-row">
|
|
1555
|
-
<span class="medos-summary-label">
|
|
1556
|
-
<span class="medos-summary-value">${
|
|
1557
|
-
? this.escapeHtml(selectedDoctor.name)
|
|
1558
|
-
: "Not selected"}</span>
|
|
1696
|
+
<span class="medos-summary-label">Phone</span>
|
|
1697
|
+
<span class="medos-summary-value">${this.escapeHtml(this.state.countryCode)} ${this.escapeHtml(this.state.patientPhone)}</span>
|
|
1559
1698
|
</div>
|
|
1560
|
-
${
|
|
1561
|
-
?
|
|
1562
|
-
|
|
1563
|
-
<span class="medos-summary-
|
|
1564
|
-
|
|
1699
|
+
${patient?.age || this.state.patientAge
|
|
1700
|
+
? `
|
|
1701
|
+
<div class="medos-summary-row">
|
|
1702
|
+
<span class="medos-summary-label">Age</span>
|
|
1703
|
+
<span class="medos-summary-value">${patient?.age || this.state.patientAge} years</span>
|
|
1704
|
+
</div>
|
|
1705
|
+
`
|
|
1706
|
+
: ""}
|
|
1707
|
+
${patient?.bloodGroup || this.state.bloodGroup
|
|
1708
|
+
? `
|
|
1709
|
+
<div class="medos-summary-row">
|
|
1710
|
+
<span class="medos-summary-label">Blood Group</span>
|
|
1711
|
+
<span class="medos-summary-value">${this.escapeHtml(patient?.bloodGroup || this.state.bloodGroup || "")}</span>
|
|
1712
|
+
</div>
|
|
1713
|
+
`
|
|
1565
1714
|
: ""}
|
|
1715
|
+
</div>
|
|
1716
|
+
</div>
|
|
1717
|
+
|
|
1718
|
+
<!-- Appointment Details -->
|
|
1719
|
+
<div class="medos-summary-section">
|
|
1720
|
+
<h4 class="medos-summary-section-title">📅 Appointment Details</h4>
|
|
1721
|
+
<div class="medos-summary-card">
|
|
1566
1722
|
<div class="medos-summary-row">
|
|
1567
|
-
<span class="medos-summary-label">Date
|
|
1568
|
-
<span class="medos-summary-value">${
|
|
1723
|
+
<span class="medos-summary-label">Date</span>
|
|
1724
|
+
<span class="medos-summary-value">${formatDate(this.state.selectedDate)}</span>
|
|
1569
1725
|
</div>
|
|
1570
1726
|
<div class="medos-summary-row">
|
|
1571
|
-
<span class="medos-summary-label">
|
|
1572
|
-
<span class="medos-summary-value">${this.state.
|
|
1573
|
-
?
|
|
1574
|
-
: "
|
|
1727
|
+
<span class="medos-summary-label">Time</span>
|
|
1728
|
+
<span class="medos-summary-value">${this.state.selectedSlot
|
|
1729
|
+
? `${formatTime(this.state.selectedSlot.start)} - ${formatTime(this.state.selectedSlot.end)}`
|
|
1730
|
+
: "Not selected"}</span>
|
|
1575
1731
|
</div>
|
|
1576
1732
|
<div class="medos-summary-row">
|
|
1577
|
-
<span class="medos-summary-label">
|
|
1578
|
-
<span class="medos-summary-value"
|
|
1579
|
-
? this.escapeHtml(this.state.selectedSessionPack?.name || "Session Pack")
|
|
1580
|
-
: usingNewPackage
|
|
1581
|
-
? this.escapeHtml(this.state.selectedNewPackage?.name || "Package")
|
|
1582
|
-
: "Standard Consultation"}</span>
|
|
1733
|
+
<span class="medos-summary-label">Duration</span>
|
|
1734
|
+
<span class="medos-summary-value">~${getDuration()} minutes</span>
|
|
1583
1735
|
</div>
|
|
1584
1736
|
<div class="medos-summary-row">
|
|
1585
|
-
<span class="medos-summary-label">
|
|
1586
|
-
<span class="medos-summary-value">${
|
|
1737
|
+
<span class="medos-summary-label">Type</span>
|
|
1738
|
+
<span class="medos-summary-value">${this.state.consultationMode === "ONLINE"
|
|
1739
|
+
? "Online Consultation"
|
|
1740
|
+
: "In-Person Visit"}</span>
|
|
1587
1741
|
</div>
|
|
1588
|
-
|
|
1742
|
+
</div>
|
|
1743
|
+
</div>
|
|
1744
|
+
|
|
1745
|
+
<!-- Doctor & Location -->
|
|
1746
|
+
<div class="medos-summary-section">
|
|
1747
|
+
<h4 class="medos-summary-section-title">🏥 Doctor & Location</h4>
|
|
1748
|
+
<div class="medos-summary-card">
|
|
1749
|
+
${selectedDoctor
|
|
1589
1750
|
? `
|
|
1590
1751
|
<div class="medos-summary-row">
|
|
1591
|
-
<span class="medos-summary-label">
|
|
1592
|
-
<span class="medos-summary-value">${
|
|
1593
|
-
? this.
|
|
1594
|
-
|
|
1595
|
-
: "Today"}</span>
|
|
1752
|
+
<span class="medos-summary-label">Doctor</span>
|
|
1753
|
+
<span class="medos-summary-value">${this.escapeHtml(selectedDoctor.name)}${selectedDoctor.specialty
|
|
1754
|
+
? ` • ${this.escapeHtml(selectedDoctor.specialty)}`
|
|
1755
|
+
: ""}</span>
|
|
1596
1756
|
</div>
|
|
1757
|
+
`
|
|
1758
|
+
: ""}
|
|
1759
|
+
${selectedAddress
|
|
1760
|
+
? `
|
|
1597
1761
|
<div class="medos-summary-row">
|
|
1598
|
-
<span class="medos-summary-label">
|
|
1599
|
-
<span class="medos-summary-value
|
|
1762
|
+
<span class="medos-summary-label">Location</span>
|
|
1763
|
+
<span class="medos-summary-value">${this.escapeHtml(selectedAddress.label || "Unknown Location")}</span>
|
|
1600
1764
|
</div>
|
|
1601
1765
|
`
|
|
1602
1766
|
: ""}
|
|
1603
1767
|
</div>
|
|
1604
1768
|
</div>
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1769
|
+
|
|
1770
|
+
<!-- Payment Information -->
|
|
1771
|
+
<div class="medos-summary-section">
|
|
1772
|
+
<h4 class="medos-summary-section-title">💳 Payment</h4>
|
|
1773
|
+
<div class="medos-summary-card">
|
|
1774
|
+
<div class="medos-summary-row">
|
|
1775
|
+
<span class="medos-summary-label">Booking Type</span>
|
|
1776
|
+
<span class="medos-summary-value">${paymentInfo.type}</span>
|
|
1777
|
+
</div>
|
|
1778
|
+
<div class="medos-summary-row">
|
|
1779
|
+
<span class="medos-summary-label">${usingSessionPack ? "Pack" : "Service"}</span>
|
|
1780
|
+
<span class="medos-summary-value">${paymentInfo.name}</span>
|
|
1781
|
+
</div>
|
|
1782
|
+
${isPackageBooking && this.state.selectedNewPackage
|
|
1783
|
+
? `
|
|
1784
|
+
<div class="medos-summary-row medos-summary-total-row">
|
|
1785
|
+
<span class="medos-summary-total-label">Amount</span>
|
|
1786
|
+
<div class="medos-summary-price-container">
|
|
1787
|
+
${this.state.selectedNewPackage.discountedPrice &&
|
|
1788
|
+
this.state.selectedNewPackage.discountedPrice <
|
|
1789
|
+
this.state.selectedNewPackage.price
|
|
1790
|
+
? `
|
|
1791
|
+
<span class="medos-summary-strikethrough-price">
|
|
1792
|
+
₹${this.state.selectedNewPackage.price.toLocaleString()}
|
|
1793
|
+
</span>
|
|
1794
|
+
<span class="medos-summary-total-value">
|
|
1795
|
+
₹${this.state.selectedNewPackage.discountedPrice.toLocaleString()}
|
|
1796
|
+
</span>
|
|
1797
|
+
${this.state.selectedNewPackage.discount
|
|
1798
|
+
? `
|
|
1799
|
+
<span class="medos-summary-discount-badge">
|
|
1800
|
+
${this.state.selectedNewPackage.discountType ===
|
|
1801
|
+
"PERCENTAGE"
|
|
1802
|
+
? `${this.state.selectedNewPackage.discount}% OFF`
|
|
1803
|
+
: `₹${this.state.selectedNewPackage.discount} OFF`}
|
|
1804
|
+
</span>
|
|
1805
|
+
`
|
|
1806
|
+
: ""}
|
|
1807
|
+
`
|
|
1808
|
+
: `
|
|
1809
|
+
<span class="medos-summary-total-value">
|
|
1810
|
+
₹${this.state.selectedNewPackage.price.toLocaleString()}
|
|
1811
|
+
</span>
|
|
1812
|
+
`}
|
|
1813
|
+
</div>
|
|
1814
|
+
</div>
|
|
1815
|
+
`
|
|
1816
|
+
: !usingSessionPack
|
|
1817
|
+
? `
|
|
1818
|
+
<div class="medos-summary-row medos-summary-total-row">
|
|
1819
|
+
<span class="medos-summary-total-label">Amount</span>
|
|
1820
|
+
<span class="medos-summary-total-value">${paymentInfo.amount}</span>
|
|
1821
|
+
</div>
|
|
1822
|
+
`
|
|
1823
|
+
: `
|
|
1824
|
+
<div class="medos-summary-row medos-summary-total-row">
|
|
1825
|
+
<span class="medos-summary-total-label">Amount</span>
|
|
1826
|
+
<span class="medos-summary-total-value">${paymentInfo.amount}</span>
|
|
1827
|
+
</div>
|
|
1828
|
+
`}
|
|
1829
|
+
${paymentInfo.remaining
|
|
1830
|
+
? `
|
|
1831
|
+
<div class="medos-summary-remaining-info">${paymentInfo.remaining}</div>
|
|
1832
|
+
`
|
|
1833
|
+
: ""}
|
|
1610
1834
|
</div>
|
|
1611
|
-
<div class="medos-total-amount">₹${totalAmount.toLocaleString()}</div>
|
|
1612
1835
|
</div>
|
|
1613
|
-
|
|
1836
|
+
|
|
1837
|
+
<!-- Actions -->
|
|
1614
1838
|
<div class="medos-actions">
|
|
1615
|
-
<button class="medos-btn medos-btn-
|
|
1616
|
-
<button class="medos-btn medos-btn-
|
|
1617
|
-
<button class="medos-btn medos-btn-primary" id="medos-btn-confirm">Confirm Book</button>
|
|
1839
|
+
<button class="medos-btn medos-btn-secondary" id="medos-btn-back">Back</button>
|
|
1840
|
+
<button class="medos-btn medos-btn-primary" id="medos-btn-confirm" ${this.state.loading ? "disabled" : ""}>${this.state.loading ? "Confirming..." : "Confirm Appointment"}</button>
|
|
1618
1841
|
</div>
|
|
1619
1842
|
</div>
|
|
1620
1843
|
`;
|
|
@@ -1726,7 +1949,8 @@ class AppointmentCalendarWidget {
|
|
|
1726
1949
|
});
|
|
1727
1950
|
const slotCards = this.container.querySelectorAll(".medos-slot-card, .medos-slot-btn");
|
|
1728
1951
|
slotCards.forEach((card) => {
|
|
1729
|
-
card.addEventListener("click", () => {
|
|
1952
|
+
card.addEventListener("click", (e) => {
|
|
1953
|
+
e.preventDefault();
|
|
1730
1954
|
const slotId = card.dataset.slotId;
|
|
1731
1955
|
const slotStart = card.dataset.slotStart;
|
|
1732
1956
|
const slotEnd = card.dataset.slotEnd;
|
|
@@ -1877,82 +2101,23 @@ class AppointmentCalendarWidget {
|
|
|
1877
2101
|
this.updatePatientDetailsButtonState();
|
|
1878
2102
|
});
|
|
1879
2103
|
}
|
|
1880
|
-
const patientDobInput = this.container.querySelector("#medos-patient-dob");
|
|
1881
|
-
if (patientDobInput) {
|
|
1882
|
-
patientDobInput.addEventListener("input", (e) => {
|
|
1883
|
-
const target = e.target;
|
|
1884
|
-
const dobValue = target.value;
|
|
1885
|
-
this.setState({ patientDob: dobValue });
|
|
1886
|
-
this.setState({ error: null });
|
|
1887
|
-
if (dobValue && dobValue.trim() !== "") {
|
|
1888
|
-
try {
|
|
1889
|
-
if (!this.isValidDateOfBirth(dobValue)) {
|
|
1890
|
-
target.classList.add("medos-input-error");
|
|
1891
|
-
const today = new Date();
|
|
1892
|
-
const inputDate = new Date(dobValue);
|
|
1893
|
-
if (inputDate > today) {
|
|
1894
|
-
target.title = "Date of birth cannot be in the future";
|
|
1895
|
-
}
|
|
1896
|
-
else if (!/^\d{4}-\d{2}-\d{2}$/.test(dobValue)) {
|
|
1897
|
-
target.title = "Please use YYYY-MM-DD format";
|
|
1898
|
-
}
|
|
1899
|
-
else {
|
|
1900
|
-
target.title = "Please enter a valid date";
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
else {
|
|
1904
|
-
target.classList.remove("medos-input-error");
|
|
1905
|
-
target.title = "";
|
|
1906
|
-
}
|
|
1907
|
-
}
|
|
1908
|
-
catch (error) {
|
|
1909
|
-
console.warn("Date validation error:", error);
|
|
1910
|
-
target.classList.add("medos-input-error");
|
|
1911
|
-
target.title = "Date validation failed";
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
|
-
else {
|
|
1915
|
-
target.classList.remove("medos-input-error");
|
|
1916
|
-
target.title = "";
|
|
1917
|
-
}
|
|
1918
|
-
this.updatePatientDetailsButtonState();
|
|
1919
|
-
this.updateSubmitButtonState();
|
|
1920
|
-
});
|
|
1921
|
-
patientDobInput.addEventListener("blur", (e) => {
|
|
1922
|
-
const target = e.target;
|
|
1923
|
-
const dobValue = target.value;
|
|
1924
|
-
if (dobValue && dobValue.trim() !== "") {
|
|
1925
|
-
try {
|
|
1926
|
-
if (!this.isValidDateOfBirth(dobValue)) {
|
|
1927
|
-
target.classList.add("medos-input-error");
|
|
1928
|
-
const today = new Date();
|
|
1929
|
-
const inputDate = new Date(dobValue);
|
|
1930
|
-
if (inputDate > today) {
|
|
1931
|
-
this.displayFieldValidationError("dateOfBirth", "future");
|
|
1932
|
-
}
|
|
1933
|
-
else if (!/^\d{4}-\d{2}-\d{2}$/.test(dobValue)) {
|
|
1934
|
-
this.displayFieldValidationError("dateOfBirth", "format");
|
|
1935
|
-
}
|
|
1936
|
-
else {
|
|
1937
|
-
this.displayFieldValidationError("dateOfBirth", "invalid");
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
catch (error) {
|
|
1942
|
-
console.warn("Date validation error on blur:", error);
|
|
1943
|
-
this.displayFieldValidationError("dateOfBirth", "invalid");
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
});
|
|
1947
|
-
}
|
|
1948
2104
|
const optionCards = this.container.querySelectorAll(".medos-option-card");
|
|
1949
2105
|
optionCards.forEach((card) => {
|
|
1950
2106
|
card.addEventListener("click", () => {
|
|
1951
2107
|
const option = card.dataset.option;
|
|
2108
|
+
const packId = card.dataset.packId
|
|
2109
|
+
? Number.parseInt(card.dataset.packId, 10)
|
|
2110
|
+
: null;
|
|
1952
2111
|
if (option === "new-appointment" ||
|
|
1953
2112
|
option === "session-pack" ||
|
|
1954
2113
|
option === "explore-packages") {
|
|
1955
2114
|
this.state.bookingOptionType = option;
|
|
2115
|
+
if (option === "session-pack" && packId) {
|
|
2116
|
+
const pack = this.state.userSessionPacks.find((p) => p.id === packId);
|
|
2117
|
+
if (pack) {
|
|
2118
|
+
this.state.selectedSessionPack = pack;
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
1956
2121
|
this.render();
|
|
1957
2122
|
}
|
|
1958
2123
|
});
|
|
@@ -1999,8 +2164,7 @@ class AppointmentCalendarWidget {
|
|
|
1999
2164
|
: this.getPlaceholderPatients();
|
|
2000
2165
|
const patient = patients.find((p) => p.id === patientId);
|
|
2001
2166
|
if (patient) {
|
|
2002
|
-
this.
|
|
2003
|
-
this.render();
|
|
2167
|
+
this.handleSelectExistingPatient(patient);
|
|
2004
2168
|
}
|
|
2005
2169
|
});
|
|
2006
2170
|
});
|
|
@@ -2024,10 +2188,6 @@ class AppointmentCalendarWidget {
|
|
|
2024
2188
|
if (backBtn) {
|
|
2025
2189
|
backBtn.addEventListener("click", () => this.goBack());
|
|
2026
2190
|
}
|
|
2027
|
-
const cancelBtn = this.container.querySelector("#medos-btn-cancel");
|
|
2028
|
-
if (cancelBtn) {
|
|
2029
|
-
cancelBtn.addEventListener("click", () => this.reset());
|
|
2030
|
-
}
|
|
2031
2191
|
const sendOtpBtn = this.container.querySelector("#medos-btn-send-otp");
|
|
2032
2192
|
if (sendOtpBtn) {
|
|
2033
2193
|
sendOtpBtn.addEventListener("click", () => {
|
|
@@ -2080,12 +2240,46 @@ class AppointmentCalendarWidget {
|
|
|
2080
2240
|
const addPatientBtn = this.container.querySelector("#medos-btn-add-patient");
|
|
2081
2241
|
if (addPatientBtn) {
|
|
2082
2242
|
addPatientBtn.addEventListener("click", () => {
|
|
2083
|
-
this.
|
|
2084
|
-
this.state.useExistingPatient = false;
|
|
2085
|
-
this.goToNext();
|
|
2243
|
+
this.handleProceedAsNewPatient();
|
|
2086
2244
|
});
|
|
2087
2245
|
}
|
|
2088
2246
|
}
|
|
2247
|
+
handleSelectExistingPatient(patient) {
|
|
2248
|
+
this.state.selectedPatient = patient;
|
|
2249
|
+
this.state.useExistingPatient = true;
|
|
2250
|
+
this.state.patientName = `${patient.firstName} ${patient.lastName}`;
|
|
2251
|
+
this.state.patientEmail = patient.email;
|
|
2252
|
+
this.state.patientAge = patient.age.toString();
|
|
2253
|
+
this.state.patientGender = patient.gender;
|
|
2254
|
+
this.state.bloodGroup = patient.bloodGroup;
|
|
2255
|
+
if (patient.address) {
|
|
2256
|
+
this.state.patientAddress = patient.address.addressLine1;
|
|
2257
|
+
this.state.patientCity = patient.address.city;
|
|
2258
|
+
this.state.patientState = patient.address.state;
|
|
2259
|
+
this.state.patientCountry = patient.address.country;
|
|
2260
|
+
this.state.patientZipcode = patient.address.zipcode;
|
|
2261
|
+
this.state.patientLandmark = patient.address.landmark || "";
|
|
2262
|
+
}
|
|
2263
|
+
this.state.step = 6;
|
|
2264
|
+
this.render();
|
|
2265
|
+
}
|
|
2266
|
+
handleProceedAsNewPatient() {
|
|
2267
|
+
this.state.selectedPatient = null;
|
|
2268
|
+
this.state.useExistingPatient = false;
|
|
2269
|
+
this.state.patientName = "";
|
|
2270
|
+
this.state.patientEmail = "";
|
|
2271
|
+
this.state.patientAge = "";
|
|
2272
|
+
this.state.patientGender = "";
|
|
2273
|
+
this.state.bloodGroup = "";
|
|
2274
|
+
this.state.patientAddress = "";
|
|
2275
|
+
this.state.patientCity = "";
|
|
2276
|
+
this.state.patientState = "";
|
|
2277
|
+
this.state.patientCountry = "";
|
|
2278
|
+
this.state.patientZipcode = "";
|
|
2279
|
+
this.state.patientLandmark = "";
|
|
2280
|
+
this.state.step = 5;
|
|
2281
|
+
this.render();
|
|
2282
|
+
}
|
|
2089
2283
|
getPlaceholderPatients() {
|
|
2090
2284
|
return [
|
|
2091
2285
|
{
|
|
@@ -2265,6 +2459,68 @@ class AppointmentCalendarWidget {
|
|
|
2265
2459
|
}
|
|
2266
2460
|
this.setState({ error: errorMessage });
|
|
2267
2461
|
}
|
|
2462
|
+
async handleSubmitAppointment() {
|
|
2463
|
+
await this.submitAppointment();
|
|
2464
|
+
}
|
|
2465
|
+
async handleOtpVerification(otpCode) {
|
|
2466
|
+
this.state.otpCode = otpCode;
|
|
2467
|
+
await this.verifyOtp();
|
|
2468
|
+
if (this.state.otpVerified) {
|
|
2469
|
+
this.goToNext();
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
handleAddressSelect(addressId) {
|
|
2473
|
+
return this.handleAddressChange(addressId);
|
|
2474
|
+
}
|
|
2475
|
+
handleDoctorSelect(doctorId) {
|
|
2476
|
+
this.state.selectedDoctor = doctorId;
|
|
2477
|
+
const selectedDoc = this.doctors.find((d) => d.id === doctorId);
|
|
2478
|
+
if (selectedDoc?.consultationCharge) {
|
|
2479
|
+
this.state.consultationCharge = selectedDoc.consultationCharge;
|
|
2480
|
+
}
|
|
2481
|
+
this.render();
|
|
2482
|
+
}
|
|
2483
|
+
handleDateSelect(date) {
|
|
2484
|
+
this.state.selectedDate = date;
|
|
2485
|
+
this.loadSlots();
|
|
2486
|
+
}
|
|
2487
|
+
handleSlotSelect(slot) {
|
|
2488
|
+
this.state.selectedSlot = slot;
|
|
2489
|
+
this.render();
|
|
2490
|
+
}
|
|
2491
|
+
handleSessionPackSelect(sessionPack) {
|
|
2492
|
+
this.state.selectedSessionPack = sessionPack;
|
|
2493
|
+
this.state.bookingOptionType = "session-pack";
|
|
2494
|
+
this.render();
|
|
2495
|
+
}
|
|
2496
|
+
handleExplorePackages() {
|
|
2497
|
+
this.state.bookingOptionType = "explore-packages";
|
|
2498
|
+
this.state.showPackageExplorer = true;
|
|
2499
|
+
this.render();
|
|
2500
|
+
}
|
|
2501
|
+
handlePackageSelect(packageItem) {
|
|
2502
|
+
this.state.selectedNewPackage = packageItem;
|
|
2503
|
+
this.render();
|
|
2504
|
+
}
|
|
2505
|
+
handleNewAppointmentSelect() {
|
|
2506
|
+
this.state.bookingOptionType = "new-appointment";
|
|
2507
|
+
this.render();
|
|
2508
|
+
}
|
|
2509
|
+
handlePatientSelect(patient) {
|
|
2510
|
+
this.handleSelectExistingPatient(patient);
|
|
2511
|
+
}
|
|
2512
|
+
handleNewPatient() {
|
|
2513
|
+
this.handleProceedAsNewPatient();
|
|
2514
|
+
}
|
|
2515
|
+
goToNextStep() {
|
|
2516
|
+
this.goToNext();
|
|
2517
|
+
}
|
|
2518
|
+
goBackStep() {
|
|
2519
|
+
this.goBack();
|
|
2520
|
+
}
|
|
2521
|
+
getState() {
|
|
2522
|
+
return { ...this.state };
|
|
2523
|
+
}
|
|
2268
2524
|
destroy() {
|
|
2269
2525
|
this.mounted = false;
|
|
2270
2526
|
this.container.innerHTML = "";
|