simpo-component-library 3.6.950 → 3.6.952
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/esm2022/lib/ecommerce/sections/book-appointment/book-appointment.component.mjs +19 -3
- package/esm2022/lib/elements/my-bookings/my-bookings.component.mjs +13 -3
- package/esm2022/lib/sections/appointment-form/appointment-booking/appointment-booking/appointment-booking.component.mjs +22 -4
- package/fesm2022/simpo-component-library.mjs +44 -7
- package/fesm2022/simpo-component-library.mjs.map +1 -1
- package/lib/ecommerce/sections/book-appointment/book-appointment.component.d.ts +10 -0
- package/lib/elements/my-bookings/my-bookings.component.d.ts +4 -0
- package/lib/sections/appointment-form/appointment-booking/appointment-booking/appointment-booking.component.d.ts +11 -1
- package/package.json +1 -1
- package/simpo-component-library-3.6.952.tgz +0 -0
- package/simpo-component-library-3.6.950.tgz +0 -0
|
@@ -22424,6 +22424,8 @@ class MyBookingsComponent {
|
|
|
22424
22424
|
return 'Completed';
|
|
22425
22425
|
if (status === 'CANCELLED')
|
|
22426
22426
|
return 'Cancelled';
|
|
22427
|
+
if (status === 'HOLD' || status === 'PENDING')
|
|
22428
|
+
return 'Payment Pending';
|
|
22427
22429
|
return 'Confirmed';
|
|
22428
22430
|
}
|
|
22429
22431
|
statusClass(status) {
|
|
@@ -22431,11 +22433,19 @@ class MyBookingsComponent {
|
|
|
22431
22433
|
return 'status-completed';
|
|
22432
22434
|
if (status === 'CANCELLED')
|
|
22433
22435
|
return 'status-cancelled';
|
|
22436
|
+
if (status === 'HOLD' || status === 'PENDING')
|
|
22437
|
+
return 'status-pending';
|
|
22434
22438
|
return 'status-confirmed';
|
|
22435
22439
|
}
|
|
22436
22440
|
paidLabel(b) {
|
|
22437
22441
|
return b.totalCollectedAtBooking && b.totalCollectedAtBooking > 0 ? `₹${b.totalCollectedAtBooking}` : 'Nothing — free';
|
|
22438
22442
|
}
|
|
22443
|
+
totalDue(b) {
|
|
22444
|
+
return (b.totalPayable ?? 0) + (b.homeVisitCharge ?? 0);
|
|
22445
|
+
}
|
|
22446
|
+
pendingAmount(b) {
|
|
22447
|
+
return Math.max(0, this.totalDue(b) - (b.totalCollectedAtBooking ?? 0));
|
|
22448
|
+
}
|
|
22439
22449
|
get canCancelSelected() {
|
|
22440
22450
|
return !!this.selected && (this.selected.status === 'HOLD' || this.selected.status === 'BOOKED' || this.selected.status === 'PENDING');
|
|
22441
22451
|
}
|
|
@@ -22463,11 +22473,11 @@ class MyBookingsComponent {
|
|
|
22463
22473
|
});
|
|
22464
22474
|
}
|
|
22465
22475
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MyBookingsComponent, deps: [{ token: RestService }, { token: StorageServiceService }, { token: i6$1.MessageService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
22466
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MyBookingsComponent, isStandalone: true, selector: "simpo-my-bookings", providers: [MessageService], ngImport: i0, template: "<p-toast position=\"bottom-right\"></p-toast>\n\n<div class=\"mb-root\">\n <ng-container *ngIf=\"currentTab === 'LIST'\">\n <div class=\"mb-title\">My Bookings</div>\n\n <div class=\"mb-tabs\">\n <button type=\"button\" class=\"mb-tab\" [class.active]=\"profTab === 'upcoming'\" (click)=\"setProfTab('upcoming')\">Upcoming</button>\n <button type=\"button\" class=\"mb-tab\" [class.active]=\"profTab === 'past'\" (click)=\"setProfTab('past')\">Past</button>\n </div>\n\n <div class=\"mb-loading\" *ngIf=\"loading\">Loading your bookings\u2026</div>\n\n <div class=\"mb-rows\" *ngIf=\"!loading && !isEmpty\">\n <button type=\"button\" class=\"mb-row\" *ngFor=\"let b of rows\" (click)=\"viewBookingDetail(b)\">\n <div class=\"mb-row-stripe\" [ngClass]=\"b.mode === 'HOME_VISIT' ? 'stripe-home' : b.mode === 'VIDEO_CALL' ? 'stripe-video' : 'stripe-store'\"></div>\n <div class=\"mb-row-info\">\n <div class=\"mb-row-top\">\n <div class=\"mb-row-title\">{{title(b)}}</div>\n </div>\n <div class=\"mb-row-when\">{{when(b)}}</div>\n <div class=\"mb-row-detail\">{{detail(b)}}</div>\n </div>\n <div class=\"mb-row-end\">\n <span class=\"mb-status\" [ngClass]=\"statusClass(b.status)\">{{statusLabel(b.status)}}</span>\n </div>\n </button>\n </div>\n\n <div class=\"mb-empty\" *ngIf=\"isEmpty\">\n <mat-icon class=\"mb-empty-icon\">event_busy</mat-icon>\n <div class=\"mb-empty-title\">No {{profTab}} bookings yet.</div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"currentTab === 'DETAIL' && selected\">\n <button type=\"button\" class=\"mb-back\" (click)=\"backToList()\">\n <mat-icon>arrow_back</mat-icon> Back to My Bookings\n </button>\n\n <div class=\"mb-detail-card\">\n <div class=\"mb-detail-header\">\n <div class=\"mb-detail-title-row\">\n <div class=\"mb-detail-title\">{{title(selected)}}</div>\n <span class=\"mb-status\" [ngClass]=\"statusClass(selected.status)\">{{statusLabel(selected.status)}}</span>\n </div>\n <div class=\"mb-detail-when\">{{when(selected)}}</div>\n </div>\n\n <div class=\"mb-detail-rows\">\n <div class=\"mb-detail-row\" *ngIf=\"selected.services?.length\">\n <div class=\"mb-detail-k\">Services</div>\n <div class=\"mb-detail-v\">{{serviceNames(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.productLines?.length\">\n <div class=\"mb-detail-k\">Products</div>\n <div class=\"mb-detail-v\">{{productNames(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.customerDetail\">\n <div class=\"mb-detail-k\">Contact</div>\n <div class=\"mb-detail-v\">{{selected.customerDetail?.name}} \u00B7 {{selected.customerDetail?.phoneNumber}} \u00B7 {{selected.customerDetail?.email}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.mode === 'HOME_VISIT' && selected.addressDetails\">\n <div class=\"mb-detail-k\">Address</div>\n <div class=\"mb-detail-v\">{{selected.addressDetails?.addressLine1}}, {{selected.addressDetails?.city}}, {{selected.addressDetails?.state}} {{selected.addressDetails?.zipCode}}</div>\n </div>\n <div class=\"mb-detail-row\">\n <div class=\"mb-detail-k\">Paid</div>\n <div class=\"mb-detail-v\">{{paidLabel(selected)}}</div>\n </div>\n </div>\n\n <div class=\"mb-video-link\" *ngIf=\"selected.mode === 'VIDEO_CALL' && selected.videoCallLink && selected.status !== 'CANCELLED'\">\n <mat-icon>videocam</mat-icon>\n <a [href]=\"selected.videoCallLink\" target=\"_blank\">{{selected.videoCallLink}}</a>\n </div>\n\n <ng-container *ngIf=\"canCancelSelected\">\n <div class=\"mb-policy\" *ngIf=\"cancellationPolicy\">\n <div class=\"mb-policy-title\">{{cancellationPolicy.title}}</div>\n <div class=\"mb-policy-text\">{{cancellationPolicy.policyDetails}}</div>\n </div>\n <button type=\"button\" class=\"mb-cancel-btn\" [disabled]=\"cancelling\" (click)=\"cancelBooking()\">\n {{cancelling ? 'Cancelling\u2026' : 'Cancel booking'}}\n </button>\n </ng-container>\n\n <div class=\"mb-cancelled-note\" *ngIf=\"selected.status === 'CANCELLED'\">This booking has been cancelled.</div>\n </div>\n </ng-container>\n</div>\n", styles: [".mb-root{display:flex;flex-direction:column;gap:16px;padding:4px 0 24px}.mb-title{font-size:20px;font-weight:600;color:#1b2436}.mb-tabs{display:flex;background:#f5f2ee;border-radius:8px;padding:4px;gap:4px;width:fit-content}.mb-tab{border:none;background:transparent;border-radius:6px;padding:8px 18px;font-size:13.5px;font-weight:500;color:#8a94a3;cursor:pointer}.mb-tab.active{background:#fff;color:#1b2436;font-weight:600;box-shadow:0 1px 3px #00000012}.mb-loading{font-size:13.5px;color:#8a94a3;padding:20px 0}.mb-rows{display:flex;flex-direction:column;gap:12px}.mb-row{border:1px solid #EEE9E3;border-radius:10px;padding:16px 18px;display:flex;align-items:flex-start;gap:14px;background:#fff;cursor:pointer;text-align:left;width:100%}.mb-row-stripe{width:3px;align-self:stretch;border-radius:999px;flex:none}.stripe-home{background:#16233a}.stripe-video{background:#7c3a11}.stripe-store{background:#8a94a3}.mb-row-info{flex:1;display:flex;flex-direction:column;gap:4px;min-width:0}.mb-row-title{font-size:14.5px;font-weight:600;color:#1b2436}.mb-row-when{font-size:12.5px;color:#6b7688}.mb-row-detail{font-size:12px;color:#8a94a3}.mb-row-end{flex:none}.mb-status{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;font-weight:600;border-radius:999px;padding:4px 9px;white-space:nowrap}.status-confirmed{background:#e8f4ee;color:#1e7a4b}.status-completed{background:#f2eee9;color:#8a7c6c}.status-cancelled{background:#fbedec;color:#b4432e}.mb-empty{display:flex;flex-direction:column;align-items:center;gap:10px;padding:50px 20px;text-align:center}.mb-empty-icon{font-size:40px!important;height:40px!important;width:40px!important;color:#c9b7a2!important}.mb-empty-title{font-size:14.5px;color:#8a94a3}.mb-back{display:flex;align-items:center;gap:6px;border:none;background:none;padding:0;cursor:pointer;font-size:12.5px;color:#7c3a11;margin-bottom:6px;width:fit-content}.mb-back mat-icon{font-size:16px!important;height:16px!important;width:16px!important}.mb-detail-card{border:1px solid #EEE9E3;border-radius:12px;padding:20px 22px;display:flex;flex-direction:column;gap:16px;background:#fff}.mb-detail-header{display:flex;flex-direction:column;gap:6px;padding-bottom:14px;border-bottom:1px solid #F0ECE7}.mb-detail-title-row{display:flex;align-items:center;gap:10px}.mb-detail-title{font-size:17px;font-weight:600;color:#1b2436}.mb-detail-when{font-size:13px;color:#6b7688}.mb-detail-rows{display:flex;flex-direction:column;gap:12px}.mb-detail-row{display:flex;justify-content:space-between;gap:16px;font-size:13px}.mb-detail-k{color:#8a94a3;flex:none}.mb-detail-v{color:#1b2436;font-weight:500;text-align:right}.mb-video-link{display:flex;align-items:center;gap:10px;padding:12px 14px;background:#f2f9f5;border-radius:8px;font-size:13px;color:#2c6a4b}.mb-video-link mat-icon{color:#1e7a4b!important;flex:none}.mb-policy{background:#fbfaf8;border:1px solid #EDE8E2;border-radius:8px;padding:12px 14px;display:flex;flex-direction:column;gap:4px}.mb-policy-title{font-size:12px;font-weight:600;color:#a08b72;text-transform:uppercase;letter-spacing:.06em}.mb-policy-text{font-size:12.5px;line-height:1.6;color:#5f6b7c}.mb-cancel-btn{height:46px;border:1.5px solid #E3CFC9;border-radius:8px;background:#fff;color:#b4432e;font-size:13.5px;font-weight:600;cursor:pointer}.mb-cancel-btn:disabled{opacity:.6;cursor:not-allowed}.mb-cancelled-note{font-size:13px;color:#b4432e;font-weight:600}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }] }); }
|
|
22476
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MyBookingsComponent, isStandalone: true, selector: "simpo-my-bookings", providers: [MessageService], ngImport: i0, template: "<p-toast position=\"bottom-right\"></p-toast>\n\n<div class=\"mb-root\">\n <ng-container *ngIf=\"currentTab === 'LIST'\">\n <div class=\"mb-title\">My Bookings</div>\n\n <div class=\"mb-tabs\">\n <button type=\"button\" class=\"mb-tab\" [class.active]=\"profTab === 'upcoming'\" (click)=\"setProfTab('upcoming')\">Upcoming</button>\n <button type=\"button\" class=\"mb-tab\" [class.active]=\"profTab === 'past'\" (click)=\"setProfTab('past')\">Past</button>\n </div>\n\n <div class=\"mb-loading\" *ngIf=\"loading\">Loading your bookings\u2026</div>\n\n <div class=\"mb-rows\" *ngIf=\"!loading && !isEmpty\">\n <button type=\"button\" class=\"mb-row\" *ngFor=\"let b of rows\" (click)=\"viewBookingDetail(b)\">\n <div class=\"mb-row-stripe\" [ngClass]=\"b.mode === 'HOME_VISIT' ? 'stripe-home' : b.mode === 'VIDEO_CALL' ? 'stripe-video' : 'stripe-store'\"></div>\n <div class=\"mb-row-info\">\n <div class=\"mb-row-top\">\n <div class=\"mb-row-title\">{{title(b)}}</div>\n </div>\n <div class=\"mb-row-when\">{{when(b)}}</div>\n <div class=\"mb-row-detail\">{{detail(b)}}</div>\n </div>\n <div class=\"mb-row-end\">\n <span class=\"mb-status\" [ngClass]=\"statusClass(b.status)\">{{statusLabel(b.status)}}</span>\n </div>\n </button>\n </div>\n\n <div class=\"mb-empty\" *ngIf=\"isEmpty\">\n <mat-icon class=\"mb-empty-icon\">event_busy</mat-icon>\n <div class=\"mb-empty-title\">No {{profTab}} bookings yet.</div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"currentTab === 'DETAIL' && selected\">\n <button type=\"button\" class=\"mb-back\" (click)=\"backToList()\">\n <mat-icon>arrow_back</mat-icon> Back to My Bookings\n </button>\n\n <div class=\"mb-detail-card\">\n <div class=\"mb-detail-header\">\n <div class=\"mb-detail-title-row\">\n <div class=\"mb-detail-title\">{{title(selected)}}</div>\n <span class=\"mb-status\" [ngClass]=\"statusClass(selected.status)\">{{statusLabel(selected.status)}}</span>\n </div>\n <div class=\"mb-detail-when\">{{when(selected)}}</div>\n </div>\n\n <div class=\"mb-detail-rows\">\n <div class=\"mb-detail-row\" *ngIf=\"selected.services?.length\">\n <div class=\"mb-detail-k\">Services</div>\n <div class=\"mb-detail-v\">{{serviceNames(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.productLines?.length\">\n <div class=\"mb-detail-k\">Products</div>\n <div class=\"mb-detail-v\">{{productNames(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.customerDetail\">\n <div class=\"mb-detail-k\">Contact</div>\n <div class=\"mb-detail-v\">{{selected.customerDetail?.name}} \u00B7 {{selected.customerDetail?.phoneNumber}} \u00B7 {{selected.customerDetail?.email}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.mode === 'HOME_VISIT' && selected.addressDetails\">\n <div class=\"mb-detail-k\">Address</div>\n <div class=\"mb-detail-v\">{{selected.addressDetails?.addressLine1}}, {{selected.addressDetails?.city}}, {{selected.addressDetails?.state}} {{selected.addressDetails?.zipCode}}</div>\n </div>\n <div class=\"mb-detail-row\">\n <div class=\"mb-detail-k\">Total</div>\n <div class=\"mb-detail-v\">\u20B9{{totalDue(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\">\n <div class=\"mb-detail-k\">Paid</div>\n <div class=\"mb-detail-v\">{{paidLabel(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"pendingAmount(selected) > 0\">\n <div class=\"mb-detail-k\">Pending at appointment</div>\n <div class=\"mb-detail-v\">\u20B9{{pendingAmount(selected)}}</div>\n </div>\n </div>\n\n <div class=\"mb-video-link\" *ngIf=\"selected.mode === 'VIDEO_CALL' && selected.videoCallLink && selected.status !== 'CANCELLED'\">\n <mat-icon>videocam</mat-icon>\n <a [href]=\"selected.videoCallLink\" target=\"_blank\">{{selected.videoCallLink}}</a>\n </div>\n\n <ng-container *ngIf=\"canCancelSelected\">\n <div class=\"mb-policy\" *ngIf=\"cancellationPolicy\">\n <div class=\"mb-policy-title\">{{cancellationPolicy.title}}</div>\n <div class=\"mb-policy-text\">{{cancellationPolicy.policyDetails}}</div>\n </div>\n <button type=\"button\" class=\"mb-cancel-btn\" [disabled]=\"cancelling\" (click)=\"cancelBooking()\">\n {{cancelling ? 'Cancelling\u2026' : 'Cancel booking'}}\n </button>\n </ng-container>\n\n <div class=\"mb-cancelled-note\" *ngIf=\"selected.status === 'CANCELLED'\">This booking has been cancelled.</div>\n </div>\n </ng-container>\n</div>\n", styles: [".mb-root{display:flex;flex-direction:column;gap:16px;padding:4px 0 24px}.mb-title{font-size:20px;font-weight:600;color:#1b2436}.mb-tabs{display:flex;background:#f5f2ee;border-radius:8px;padding:4px;gap:4px;width:fit-content}.mb-tab{border:none;background:transparent;border-radius:6px;padding:8px 18px;font-size:13.5px;font-weight:500;color:#8a94a3;cursor:pointer}.mb-tab.active{background:#fff;color:#1b2436;font-weight:600;box-shadow:0 1px 3px #00000012}.mb-loading{font-size:13.5px;color:#8a94a3;padding:20px 0}.mb-rows{display:flex;flex-direction:column;gap:12px}.mb-row{border:1px solid #EEE9E3;border-radius:10px;padding:16px 18px;display:flex;align-items:flex-start;gap:14px;background:#fff;cursor:pointer;text-align:left;width:100%}.mb-row-stripe{width:3px;align-self:stretch;border-radius:999px;flex:none}.stripe-home{background:#16233a}.stripe-video{background:#7c3a11}.stripe-store{background:#8a94a3}.mb-row-info{flex:1;display:flex;flex-direction:column;gap:4px;min-width:0}.mb-row-title{font-size:14.5px;font-weight:600;color:#1b2436}.mb-row-when{font-size:12.5px;color:#6b7688}.mb-row-detail{font-size:12px;color:#8a94a3}.mb-row-end{flex:none}.mb-status{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;font-weight:600;border-radius:999px;padding:4px 9px;white-space:nowrap}.status-confirmed{background:#e8f4ee;color:#1e7a4b}.status-completed{background:#f2eee9;color:#8a7c6c}.status-cancelled{background:#fbedec;color:#b4432e}.status-pending{background:#fdf3e3;color:#b36b00}.mb-empty{display:flex;flex-direction:column;align-items:center;gap:10px;padding:50px 20px;text-align:center}.mb-empty-icon{font-size:40px!important;height:40px!important;width:40px!important;color:#c9b7a2!important}.mb-empty-title{font-size:14.5px;color:#8a94a3}.mb-back{display:flex;align-items:center;gap:6px;border:none;background:none;padding:0;cursor:pointer;font-size:12.5px;color:#7c3a11;margin-bottom:6px;width:fit-content}.mb-back mat-icon{font-size:16px!important;height:16px!important;width:16px!important}.mb-detail-card{border:1px solid #EEE9E3;border-radius:12px;padding:20px 22px;display:flex;flex-direction:column;gap:16px;background:#fff}.mb-detail-header{display:flex;flex-direction:column;gap:6px;padding-bottom:14px;border-bottom:1px solid #F0ECE7}.mb-detail-title-row{display:flex;align-items:center;gap:10px}.mb-detail-title{font-size:17px;font-weight:600;color:#1b2436}.mb-detail-when{font-size:13px;color:#6b7688}.mb-detail-rows{display:flex;flex-direction:column;gap:12px}.mb-detail-row{display:flex;justify-content:space-between;gap:16px;font-size:13px}.mb-detail-k{color:#8a94a3;flex:none}.mb-detail-v{color:#1b2436;font-weight:500;text-align:right}.mb-video-link{display:flex;align-items:center;gap:10px;padding:12px 14px;background:#f2f9f5;border-radius:8px;font-size:13px;color:#2c6a4b}.mb-video-link mat-icon{color:#1e7a4b!important;flex:none}.mb-policy{background:#fbfaf8;border:1px solid #EDE8E2;border-radius:8px;padding:12px 14px;display:flex;flex-direction:column;gap:4px}.mb-policy-title{font-size:12px;font-weight:600;color:#a08b72;text-transform:uppercase;letter-spacing:.06em}.mb-policy-text{font-size:12.5px;line-height:1.6;color:#5f6b7c}.mb-cancel-btn{height:46px;border:1.5px solid #E3CFC9;border-radius:8px;background:#fff;color:#b4432e;font-size:13.5px;font-weight:600;cursor:pointer}.mb-cancel-btn:disabled{opacity:.6;cursor:not-allowed}.mb-cancelled-note{font-size:13px;color:#b4432e;font-weight:600}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }] }); }
|
|
22467
22477
|
}
|
|
22468
22478
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MyBookingsComponent, decorators: [{
|
|
22469
22479
|
type: Component,
|
|
22470
|
-
args: [{ selector: 'simpo-my-bookings', standalone: true, imports: [CommonModule, MatIconModule, ToastModule], providers: [MessageService], template: "<p-toast position=\"bottom-right\"></p-toast>\n\n<div class=\"mb-root\">\n <ng-container *ngIf=\"currentTab === 'LIST'\">\n <div class=\"mb-title\">My Bookings</div>\n\n <div class=\"mb-tabs\">\n <button type=\"button\" class=\"mb-tab\" [class.active]=\"profTab === 'upcoming'\" (click)=\"setProfTab('upcoming')\">Upcoming</button>\n <button type=\"button\" class=\"mb-tab\" [class.active]=\"profTab === 'past'\" (click)=\"setProfTab('past')\">Past</button>\n </div>\n\n <div class=\"mb-loading\" *ngIf=\"loading\">Loading your bookings\u2026</div>\n\n <div class=\"mb-rows\" *ngIf=\"!loading && !isEmpty\">\n <button type=\"button\" class=\"mb-row\" *ngFor=\"let b of rows\" (click)=\"viewBookingDetail(b)\">\n <div class=\"mb-row-stripe\" [ngClass]=\"b.mode === 'HOME_VISIT' ? 'stripe-home' : b.mode === 'VIDEO_CALL' ? 'stripe-video' : 'stripe-store'\"></div>\n <div class=\"mb-row-info\">\n <div class=\"mb-row-top\">\n <div class=\"mb-row-title\">{{title(b)}}</div>\n </div>\n <div class=\"mb-row-when\">{{when(b)}}</div>\n <div class=\"mb-row-detail\">{{detail(b)}}</div>\n </div>\n <div class=\"mb-row-end\">\n <span class=\"mb-status\" [ngClass]=\"statusClass(b.status)\">{{statusLabel(b.status)}}</span>\n </div>\n </button>\n </div>\n\n <div class=\"mb-empty\" *ngIf=\"isEmpty\">\n <mat-icon class=\"mb-empty-icon\">event_busy</mat-icon>\n <div class=\"mb-empty-title\">No {{profTab}} bookings yet.</div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"currentTab === 'DETAIL' && selected\">\n <button type=\"button\" class=\"mb-back\" (click)=\"backToList()\">\n <mat-icon>arrow_back</mat-icon> Back to My Bookings\n </button>\n\n <div class=\"mb-detail-card\">\n <div class=\"mb-detail-header\">\n <div class=\"mb-detail-title-row\">\n <div class=\"mb-detail-title\">{{title(selected)}}</div>\n <span class=\"mb-status\" [ngClass]=\"statusClass(selected.status)\">{{statusLabel(selected.status)}}</span>\n </div>\n <div class=\"mb-detail-when\">{{when(selected)}}</div>\n </div>\n\n <div class=\"mb-detail-rows\">\n <div class=\"mb-detail-row\" *ngIf=\"selected.services?.length\">\n <div class=\"mb-detail-k\">Services</div>\n <div class=\"mb-detail-v\">{{serviceNames(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.productLines?.length\">\n <div class=\"mb-detail-k\">Products</div>\n <div class=\"mb-detail-v\">{{productNames(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.customerDetail\">\n <div class=\"mb-detail-k\">Contact</div>\n <div class=\"mb-detail-v\">{{selected.customerDetail?.name}} \u00B7 {{selected.customerDetail?.phoneNumber}} \u00B7 {{selected.customerDetail?.email}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.mode === 'HOME_VISIT' && selected.addressDetails\">\n <div class=\"mb-detail-k\">Address</div>\n <div class=\"mb-detail-v\">{{selected.addressDetails?.addressLine1}}, {{selected.addressDetails?.city}}, {{selected.addressDetails?.state}} {{selected.addressDetails?.zipCode}}</div>\n </div>\n <div class=\"mb-detail-row\">\n <div class=\"mb-detail-k\">Paid</div>\n <div class=\"mb-detail-v\">{{paidLabel(selected)}}</div>\n </div>\n </div>\n\n <div class=\"mb-video-link\" *ngIf=\"selected.mode === 'VIDEO_CALL' && selected.videoCallLink && selected.status !== 'CANCELLED'\">\n <mat-icon>videocam</mat-icon>\n <a [href]=\"selected.videoCallLink\" target=\"_blank\">{{selected.videoCallLink}}</a>\n </div>\n\n <ng-container *ngIf=\"canCancelSelected\">\n <div class=\"mb-policy\" *ngIf=\"cancellationPolicy\">\n <div class=\"mb-policy-title\">{{cancellationPolicy.title}}</div>\n <div class=\"mb-policy-text\">{{cancellationPolicy.policyDetails}}</div>\n </div>\n <button type=\"button\" class=\"mb-cancel-btn\" [disabled]=\"cancelling\" (click)=\"cancelBooking()\">\n {{cancelling ? 'Cancelling\u2026' : 'Cancel booking'}}\n </button>\n </ng-container>\n\n <div class=\"mb-cancelled-note\" *ngIf=\"selected.status === 'CANCELLED'\">This booking has been cancelled.</div>\n </div>\n </ng-container>\n</div>\n", styles: [".mb-root{display:flex;flex-direction:column;gap:16px;padding:4px 0 24px}.mb-title{font-size:20px;font-weight:600;color:#1b2436}.mb-tabs{display:flex;background:#f5f2ee;border-radius:8px;padding:4px;gap:4px;width:fit-content}.mb-tab{border:none;background:transparent;border-radius:6px;padding:8px 18px;font-size:13.5px;font-weight:500;color:#8a94a3;cursor:pointer}.mb-tab.active{background:#fff;color:#1b2436;font-weight:600;box-shadow:0 1px 3px #00000012}.mb-loading{font-size:13.5px;color:#8a94a3;padding:20px 0}.mb-rows{display:flex;flex-direction:column;gap:12px}.mb-row{border:1px solid #EEE9E3;border-radius:10px;padding:16px 18px;display:flex;align-items:flex-start;gap:14px;background:#fff;cursor:pointer;text-align:left;width:100%}.mb-row-stripe{width:3px;align-self:stretch;border-radius:999px;flex:none}.stripe-home{background:#16233a}.stripe-video{background:#7c3a11}.stripe-store{background:#8a94a3}.mb-row-info{flex:1;display:flex;flex-direction:column;gap:4px;min-width:0}.mb-row-title{font-size:14.5px;font-weight:600;color:#1b2436}.mb-row-when{font-size:12.5px;color:#6b7688}.mb-row-detail{font-size:12px;color:#8a94a3}.mb-row-end{flex:none}.mb-status{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;font-weight:600;border-radius:999px;padding:4px 9px;white-space:nowrap}.status-confirmed{background:#e8f4ee;color:#1e7a4b}.status-completed{background:#f2eee9;color:#8a7c6c}.status-cancelled{background:#fbedec;color:#b4432e}.mb-empty{display:flex;flex-direction:column;align-items:center;gap:10px;padding:50px 20px;text-align:center}.mb-empty-icon{font-size:40px!important;height:40px!important;width:40px!important;color:#c9b7a2!important}.mb-empty-title{font-size:14.5px;color:#8a94a3}.mb-back{display:flex;align-items:center;gap:6px;border:none;background:none;padding:0;cursor:pointer;font-size:12.5px;color:#7c3a11;margin-bottom:6px;width:fit-content}.mb-back mat-icon{font-size:16px!important;height:16px!important;width:16px!important}.mb-detail-card{border:1px solid #EEE9E3;border-radius:12px;padding:20px 22px;display:flex;flex-direction:column;gap:16px;background:#fff}.mb-detail-header{display:flex;flex-direction:column;gap:6px;padding-bottom:14px;border-bottom:1px solid #F0ECE7}.mb-detail-title-row{display:flex;align-items:center;gap:10px}.mb-detail-title{font-size:17px;font-weight:600;color:#1b2436}.mb-detail-when{font-size:13px;color:#6b7688}.mb-detail-rows{display:flex;flex-direction:column;gap:12px}.mb-detail-row{display:flex;justify-content:space-between;gap:16px;font-size:13px}.mb-detail-k{color:#8a94a3;flex:none}.mb-detail-v{color:#1b2436;font-weight:500;text-align:right}.mb-video-link{display:flex;align-items:center;gap:10px;padding:12px 14px;background:#f2f9f5;border-radius:8px;font-size:13px;color:#2c6a4b}.mb-video-link mat-icon{color:#1e7a4b!important;flex:none}.mb-policy{background:#fbfaf8;border:1px solid #EDE8E2;border-radius:8px;padding:12px 14px;display:flex;flex-direction:column;gap:4px}.mb-policy-title{font-size:12px;font-weight:600;color:#a08b72;text-transform:uppercase;letter-spacing:.06em}.mb-policy-text{font-size:12.5px;line-height:1.6;color:#5f6b7c}.mb-cancel-btn{height:46px;border:1.5px solid #E3CFC9;border-radius:8px;background:#fff;color:#b4432e;font-size:13.5px;font-weight:600;cursor:pointer}.mb-cancel-btn:disabled{opacity:.6;cursor:not-allowed}.mb-cancelled-note{font-size:13px;color:#b4432e;font-weight:600}\n"] }]
|
|
22480
|
+
args: [{ selector: 'simpo-my-bookings', standalone: true, imports: [CommonModule, MatIconModule, ToastModule], providers: [MessageService], template: "<p-toast position=\"bottom-right\"></p-toast>\n\n<div class=\"mb-root\">\n <ng-container *ngIf=\"currentTab === 'LIST'\">\n <div class=\"mb-title\">My Bookings</div>\n\n <div class=\"mb-tabs\">\n <button type=\"button\" class=\"mb-tab\" [class.active]=\"profTab === 'upcoming'\" (click)=\"setProfTab('upcoming')\">Upcoming</button>\n <button type=\"button\" class=\"mb-tab\" [class.active]=\"profTab === 'past'\" (click)=\"setProfTab('past')\">Past</button>\n </div>\n\n <div class=\"mb-loading\" *ngIf=\"loading\">Loading your bookings\u2026</div>\n\n <div class=\"mb-rows\" *ngIf=\"!loading && !isEmpty\">\n <button type=\"button\" class=\"mb-row\" *ngFor=\"let b of rows\" (click)=\"viewBookingDetail(b)\">\n <div class=\"mb-row-stripe\" [ngClass]=\"b.mode === 'HOME_VISIT' ? 'stripe-home' : b.mode === 'VIDEO_CALL' ? 'stripe-video' : 'stripe-store'\"></div>\n <div class=\"mb-row-info\">\n <div class=\"mb-row-top\">\n <div class=\"mb-row-title\">{{title(b)}}</div>\n </div>\n <div class=\"mb-row-when\">{{when(b)}}</div>\n <div class=\"mb-row-detail\">{{detail(b)}}</div>\n </div>\n <div class=\"mb-row-end\">\n <span class=\"mb-status\" [ngClass]=\"statusClass(b.status)\">{{statusLabel(b.status)}}</span>\n </div>\n </button>\n </div>\n\n <div class=\"mb-empty\" *ngIf=\"isEmpty\">\n <mat-icon class=\"mb-empty-icon\">event_busy</mat-icon>\n <div class=\"mb-empty-title\">No {{profTab}} bookings yet.</div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"currentTab === 'DETAIL' && selected\">\n <button type=\"button\" class=\"mb-back\" (click)=\"backToList()\">\n <mat-icon>arrow_back</mat-icon> Back to My Bookings\n </button>\n\n <div class=\"mb-detail-card\">\n <div class=\"mb-detail-header\">\n <div class=\"mb-detail-title-row\">\n <div class=\"mb-detail-title\">{{title(selected)}}</div>\n <span class=\"mb-status\" [ngClass]=\"statusClass(selected.status)\">{{statusLabel(selected.status)}}</span>\n </div>\n <div class=\"mb-detail-when\">{{when(selected)}}</div>\n </div>\n\n <div class=\"mb-detail-rows\">\n <div class=\"mb-detail-row\" *ngIf=\"selected.services?.length\">\n <div class=\"mb-detail-k\">Services</div>\n <div class=\"mb-detail-v\">{{serviceNames(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.productLines?.length\">\n <div class=\"mb-detail-k\">Products</div>\n <div class=\"mb-detail-v\">{{productNames(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.customerDetail\">\n <div class=\"mb-detail-k\">Contact</div>\n <div class=\"mb-detail-v\">{{selected.customerDetail?.name}} \u00B7 {{selected.customerDetail?.phoneNumber}} \u00B7 {{selected.customerDetail?.email}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.mode === 'HOME_VISIT' && selected.addressDetails\">\n <div class=\"mb-detail-k\">Address</div>\n <div class=\"mb-detail-v\">{{selected.addressDetails?.addressLine1}}, {{selected.addressDetails?.city}}, {{selected.addressDetails?.state}} {{selected.addressDetails?.zipCode}}</div>\n </div>\n <div class=\"mb-detail-row\">\n <div class=\"mb-detail-k\">Total</div>\n <div class=\"mb-detail-v\">\u20B9{{totalDue(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\">\n <div class=\"mb-detail-k\">Paid</div>\n <div class=\"mb-detail-v\">{{paidLabel(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"pendingAmount(selected) > 0\">\n <div class=\"mb-detail-k\">Pending at appointment</div>\n <div class=\"mb-detail-v\">\u20B9{{pendingAmount(selected)}}</div>\n </div>\n </div>\n\n <div class=\"mb-video-link\" *ngIf=\"selected.mode === 'VIDEO_CALL' && selected.videoCallLink && selected.status !== 'CANCELLED'\">\n <mat-icon>videocam</mat-icon>\n <a [href]=\"selected.videoCallLink\" target=\"_blank\">{{selected.videoCallLink}}</a>\n </div>\n\n <ng-container *ngIf=\"canCancelSelected\">\n <div class=\"mb-policy\" *ngIf=\"cancellationPolicy\">\n <div class=\"mb-policy-title\">{{cancellationPolicy.title}}</div>\n <div class=\"mb-policy-text\">{{cancellationPolicy.policyDetails}}</div>\n </div>\n <button type=\"button\" class=\"mb-cancel-btn\" [disabled]=\"cancelling\" (click)=\"cancelBooking()\">\n {{cancelling ? 'Cancelling\u2026' : 'Cancel booking'}}\n </button>\n </ng-container>\n\n <div class=\"mb-cancelled-note\" *ngIf=\"selected.status === 'CANCELLED'\">This booking has been cancelled.</div>\n </div>\n </ng-container>\n</div>\n", styles: [".mb-root{display:flex;flex-direction:column;gap:16px;padding:4px 0 24px}.mb-title{font-size:20px;font-weight:600;color:#1b2436}.mb-tabs{display:flex;background:#f5f2ee;border-radius:8px;padding:4px;gap:4px;width:fit-content}.mb-tab{border:none;background:transparent;border-radius:6px;padding:8px 18px;font-size:13.5px;font-weight:500;color:#8a94a3;cursor:pointer}.mb-tab.active{background:#fff;color:#1b2436;font-weight:600;box-shadow:0 1px 3px #00000012}.mb-loading{font-size:13.5px;color:#8a94a3;padding:20px 0}.mb-rows{display:flex;flex-direction:column;gap:12px}.mb-row{border:1px solid #EEE9E3;border-radius:10px;padding:16px 18px;display:flex;align-items:flex-start;gap:14px;background:#fff;cursor:pointer;text-align:left;width:100%}.mb-row-stripe{width:3px;align-self:stretch;border-radius:999px;flex:none}.stripe-home{background:#16233a}.stripe-video{background:#7c3a11}.stripe-store{background:#8a94a3}.mb-row-info{flex:1;display:flex;flex-direction:column;gap:4px;min-width:0}.mb-row-title{font-size:14.5px;font-weight:600;color:#1b2436}.mb-row-when{font-size:12.5px;color:#6b7688}.mb-row-detail{font-size:12px;color:#8a94a3}.mb-row-end{flex:none}.mb-status{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;font-weight:600;border-radius:999px;padding:4px 9px;white-space:nowrap}.status-confirmed{background:#e8f4ee;color:#1e7a4b}.status-completed{background:#f2eee9;color:#8a7c6c}.status-cancelled{background:#fbedec;color:#b4432e}.status-pending{background:#fdf3e3;color:#b36b00}.mb-empty{display:flex;flex-direction:column;align-items:center;gap:10px;padding:50px 20px;text-align:center}.mb-empty-icon{font-size:40px!important;height:40px!important;width:40px!important;color:#c9b7a2!important}.mb-empty-title{font-size:14.5px;color:#8a94a3}.mb-back{display:flex;align-items:center;gap:6px;border:none;background:none;padding:0;cursor:pointer;font-size:12.5px;color:#7c3a11;margin-bottom:6px;width:fit-content}.mb-back mat-icon{font-size:16px!important;height:16px!important;width:16px!important}.mb-detail-card{border:1px solid #EEE9E3;border-radius:12px;padding:20px 22px;display:flex;flex-direction:column;gap:16px;background:#fff}.mb-detail-header{display:flex;flex-direction:column;gap:6px;padding-bottom:14px;border-bottom:1px solid #F0ECE7}.mb-detail-title-row{display:flex;align-items:center;gap:10px}.mb-detail-title{font-size:17px;font-weight:600;color:#1b2436}.mb-detail-when{font-size:13px;color:#6b7688}.mb-detail-rows{display:flex;flex-direction:column;gap:12px}.mb-detail-row{display:flex;justify-content:space-between;gap:16px;font-size:13px}.mb-detail-k{color:#8a94a3;flex:none}.mb-detail-v{color:#1b2436;font-weight:500;text-align:right}.mb-video-link{display:flex;align-items:center;gap:10px;padding:12px 14px;background:#f2f9f5;border-radius:8px;font-size:13px;color:#2c6a4b}.mb-video-link mat-icon{color:#1e7a4b!important;flex:none}.mb-policy{background:#fbfaf8;border:1px solid #EDE8E2;border-radius:8px;padding:12px 14px;display:flex;flex-direction:column;gap:4px}.mb-policy-title{font-size:12px;font-weight:600;color:#a08b72;text-transform:uppercase;letter-spacing:.06em}.mb-policy-text{font-size:12.5px;line-height:1.6;color:#5f6b7c}.mb-cancel-btn{height:46px;border:1.5px solid #E3CFC9;border-radius:8px;background:#fff;color:#b4432e;font-size:13.5px;font-weight:600;cursor:pointer}.mb-cancel-btn:disabled{opacity:.6;cursor:not-allowed}.mb-cancelled-note{font-size:13px;color:#b4432e;font-weight:600}\n"] }]
|
|
22471
22481
|
}], ctorParameters: () => [{ type: RestService }, { type: StorageServiceService }, { type: i6$1.MessageService }] });
|
|
22472
22482
|
|
|
22473
22483
|
class PassbookTransactionsComponent {
|
|
@@ -25335,8 +25345,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
25335
25345
|
args: ['input', ['$event']]
|
|
25336
25346
|
}] } });
|
|
25337
25347
|
|
|
25338
|
-
class AppointmentBookingComponent {
|
|
25348
|
+
class AppointmentBookingComponent extends BaseSection {
|
|
25339
25349
|
constructor(restService, _eventService, router, messageService, bookingProductCartService, storageService, matDialog, dialogRef) {
|
|
25350
|
+
super();
|
|
25340
25351
|
this.restService = restService;
|
|
25341
25352
|
this._eventService = _eventService;
|
|
25342
25353
|
this.router = router;
|
|
@@ -25408,6 +25419,19 @@ class AppointmentBookingComponent {
|
|
|
25408
25419
|
};
|
|
25409
25420
|
this.apiStatus = false;
|
|
25410
25421
|
}
|
|
25422
|
+
/** Editor-configurable background - falls back to undefined (letting the component's own CSS
|
|
25423
|
+
* defaults show through unchanged) for existing pages saved before this section supported
|
|
25424
|
+
* custom colors. */
|
|
25425
|
+
get backgroundInfo() {
|
|
25426
|
+
return this.data?.styles?.background;
|
|
25427
|
+
}
|
|
25428
|
+
/** Overrides this component's own --color-accent-gradient CSS variable (scoped to its :host,
|
|
25429
|
+
* see appointment-booking.component.css) when a business has picked a custom accent color -
|
|
25430
|
+
* null when unset, so the [style.--color-accent-gradient] binding removes the inline override
|
|
25431
|
+
* entirely and the CSS default shows through, rather than forcing an empty value. */
|
|
25432
|
+
get accentColor() {
|
|
25433
|
+
return this.data?.styles?.background?.accentColor || null;
|
|
25434
|
+
}
|
|
25411
25435
|
ngOnInit() {
|
|
25412
25436
|
// Login is required before entering the wizard at all (not mid-flow, like cart's
|
|
25413
25437
|
// checkout-commit gate) - the wizard's selections live only in component memory, so a
|
|
@@ -25951,11 +25975,11 @@ class AppointmentBookingComponent {
|
|
|
25951
25975
|
this.resetWizard();
|
|
25952
25976
|
}
|
|
25953
25977
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppointmentBookingComponent, deps: [{ token: RestService }, { token: EventsService }, { token: i2$2.Router }, { token: i6$1.MessageService }, { token: BookingProductCartService }, { token: StorageServiceService }, { token: i3$2.MatDialog }, { token: i3$2.MatDialogRef, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
25954
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AppointmentBookingComponent, isStandalone: true, selector: "simpo-appointment-booking", inputs: { data: "data", index: "index", edit: "edit", isAdminBooking: "isAdminBooking", delete: "delete", customClass: "customClass", nextComponentColor: "nextComponentColor", prefillContact: "prefillContact" }, host: { listeners: { "window: resize": "getScreenSize($event)", "document:click": "closeOnOutsideClick()" } }, providers: [MessageService], ngImport: i0, template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\">\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"back-btn d-flex justify-content-center align-items-center cursor-pointer gap-2 mb-3\"\n (click)=\"goBack()\">\n <mat-icon>keyboard_backspace</mat-icon><span *ngIf=\"screenWidth > 475\">Back to Home</span>\n </div>\n <div class=\"header-title\">\n <h1>Book New Appointment</h1>\n <p>{{businessName ?? \"N/A\" }}</p>\n </div>\n </div>\n\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width]=\"barWidth + '%'\"></div>\n </div>\n </div>\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <ng-container *ngIf=\"selectedTab === 'modeSelection'\">\n <ng-container *ngTemplateOutlet=\"modeSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'serviceListing'\">\n <ng-container *ngIf=\"!skeletonLoader\">\n <ng-container *ngTemplateOutlet=\"serviceListing\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'locationListing'\">\n <ng-container *ngTemplateOutlet=\"locationListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'staffListing'\">\n <ng-container *ngTemplateOutlet=\"staffListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'dateSelection'\">\n <ng-container *ngTemplateOutlet=\"dateSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='contactDetails'\">\n <ng-container *ngTemplateOutlet=\"contactDetails\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='paymentTab'\">\n <ng-container *ngTemplateOutlet=\"paymentTab\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='statusTemplate'\">\n <ng-container *ngTemplateOutlet=\"statusTemplate\"></ng-container>\n </ng-container>\n </div>\n <div class=\"main_footer d-flex justify-content-center align-items-center\"\n *ngIf=\"selectedTab!=='statusTemplate' && selectedTab!=='modeSelection'\">\n <div class=\"footer-buttons\"\n [ngStyle]=\"{'justify-content': selectedTab != 'serviceListing' ? 'space-between' : 'end'}\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"previousStep()\"\n *ngIf=\"selectedTab != 'serviceListing'\">Back</span>\n <button class=\"continue-btn\" [disabled]=\"!activeButton\" (click)=\"nextStep()\"\n *ngIf=\"selectedTab!='paymentTab'\">{{!loader ? 'Continue' : 'Loading...'}}</button>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center\"\n *ngIf=\"selectedTab==='paymentTab'\" (click)=\"confirmBooking()\" [disabled]=\"isProcessing\"\n [ngClass]=\"{'pay-now-btn' : bookingGroup?.totalCollectedAtBooking > 0 || !bookingGroup,'complete_booking' : bookingGroup && !bookingGroup?.totalCollectedAtBooking}\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n\n<ng-template #modeSelection>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>How would you like this?</h2>\n <p>Choose how you'd like to be served</p>\n <div class=\"services-grid\">\n <div class=\"service-card\" (click)=\"selectMode('STORE_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>storefront</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Visit our Store</div>\n </div>\n </div>\n <div class=\"service-description\">Come to us at one of our locations</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('HOME_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>home</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">We come to you</div>\n </div>\n </div>\n <div class=\"service-description\">A professional visits your address</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('VIDEO_CALL')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>videocam</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Video consultation</div>\n </div>\n </div>\n <div class=\"service-description\">Connect over a video call</div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #serviceListing>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>Select a Service</h2>\n <p>Choose the service(s) you'd like to book<span *ngIf=\"cartServices.length > 0\"> \u2014 {{cartServices.length}} selected</span></p>\n <p *ngIf=\"productCartItems.length > 0\" class=\"cart-hint\">{{productCartItems.length}} product(s) already in your cart \u2014 you can continue without picking a service.</p>\n\n <div class=\"services-grid\">\n <ng-container *ngFor=\"let service of serviceData\">\n <div class=\"\" (click)=\"selectService(service)\"\n [ngClass]=\"{ 'service-card-selected' : service?.selected, 'service-card': !service?.selected }\">\n <div class=\" service-header\">\n <div class=\"service-icon\"><mat-icon>person_outline</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">{{service?.name ? service?.name : 'N/A'}}</div>\n </div>\n <div>\n <div class=\"service-price\">\u20B9{{service?.priceDetails?.price ?\n service?.priceDetails?.price : 'N/A' }}</div>\n <div class=\"service-duration\">{{service?.duration ? service?.duration : 'N/A'}} min\n </div>\n </div>\n </div>\n <div class=\"service-description\" *ngIf=\"service?.description\">\n {{service?.description ? service?.description : 'N/A'}}\n </div>\n <div class=\"home-visit\" *ngIf=\"selectedMode === 'STORE_VISIT' && service?.homeAppointmentAvailable\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/982126c1758628863129furniture_16406103.png\">Home\n Visit Available</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #locationListing>\n <div class=\"location_section\">\n <div class=\"header flex-column align-items-start\">\n <h1>Choose Location</h1>\n <p>Select where you'd like to receive the service</p>\n </div>\n\n <div class=\"location-list\">\n <ng-container *ngFor=\"let location of locationData\">\n <div (click)=\"selectLocation(location)\"\n [ngClass]=\"{ 'location-card-selected' : location?.selected, 'location-card': !location?.selected }\">\n <div class=\"location-content\">\n <div class=\"location-info\">\n <div class=\"location-icon\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/427226c1758629157758store_3171510.png\">\n </div>\n <div class=\"location-details\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <h3>{{location?.storeName ? location?.storeName : 'N/A'}}</h3>\n </div>\n <p>{{location?.addressDetails?.addressLine}}, {{location?.addressDetails?.city}},\n {{location?.addressDetails?.state}} {{location?.pincode}}</p>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #staffListing>\n <div class=\"w-60 overflow-hidden staff-listing\">\n <div class=\"d-flex w-100 h-100\">\n <div class=\"w-100\">\n <div class=\"staff-header mb-3\">\n <h1>Select Staff Member</h1>\n <p class=\"staff-subtitle mb-0\">Choose your preferred professional</p>\n </div>\n\n <div class=\"search-container mb-4\">\n <div class=\"search-input-wrapper d-flex align-items-center\">\n <mat-icon class=\"search-icon me-2\">search</mat-icon>\n <input type=\"text\" class=\"search-input border-0 flex-grow-1\" placeholder=\"Search staff member by name...\" [(ngModel)]=\"staffSearchQuery\">\n <mat-icon class=\"clear-icon cursor-pointer ms-2\" *ngIf=\"staffSearchQuery\" (click)=\"staffSearchQuery = ''\">close</mat-icon>\n </div>\n </div>\n\n <!-- Pure product-only line: one flat staff list, same as the old single-service flow -->\n <div class=\"staff-list\" *ngIf=\"cartServices.length === 0\">\n <ng-container *ngFor=\"let staff of filteredStaff\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForProductOnlyLine(staff)\"\n [ngClass]=\"{ 'staff-card-selected' : staff?.selected, 'staff-card': !staff?.selected }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.staffName.slice(0,2).toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.staffName ? staff?.staffName : 'N/A') | titlecase}}</h3>\n <p class=\"staff-specialty\">{{(businessName && businessName !== 'N/A') ? businessName : 'Booking Specialist'}}</p>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"staff?.selected\">\n <mat-icon *ngIf=\"staff?.selected\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Bundled cart: one pool per line that resolution couldn't collapse to a single provider -->\n <ng-container *ngIf=\"cartServices.length > 0\">\n <div class=\"staff-line-group mb-4\" *ngFor=\"let line of resolvedLines\">\n <ng-container *ngIf=\"line.candidateStaffPool?.length\">\n <h4 class=\"mb-2\">For {{line.services.length}} service(s): {{ (line.services | slice:0:3).length ? '' : '' }}<span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></h4>\n <div class=\"staff-list mb-3\">\n <ng-container *ngFor=\"let staff of line.candidateStaffPool\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForLine(line, staff)\"\n [ngClass]=\"{ 'staff-card-selected' : line.selectedStaffId === staff.id, 'staff-card': line.selectedStaffId !== staff.id }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.name?.slice(0,2)?.toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.name ? staff?.name : 'N/A') | titlecase}}</h3>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"line.selectedStaffId === staff.id\">\n <mat-icon *ngIf=\"line.selectedStaffId === staff.id\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateSelection>\n <div class=\"w-60 date_section\">\n <div class=\"row justify-content-center h-100\">\n <div class=\"col-12 h-100\">\n <div class=\"datetime-header mb-2\">\n <h1>Select Date & Time</h1>\n <p class=\"datetime-subtitle mb-0\">Choose when you'd like your appointment</p>\n </div>\n\n <div class=\"d-flex gap-4 main_container\">\n <div [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\">\n <div class=\"section-card card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Select Date</h3>\n\n <div class=\"date-picker-container d-flex align-items-center justify-content-between\"\n (click)=\"$event.stopPropagation()\">\n <input type=\"text\" class=\"date-input border-0 rounded-2\" placeholder=\"dd-mm-yyyy\"\n [value]=\"selectedDateStr\" readonly (click)=\"toggleCalendar($event)\">\n\n <mat-icon class=\"ms-2\" (click)=\"toggleCalendar($event)\">calendar_today</mat-icon>\n </div>\n <div class=\"position-relative\" (click)=\"$event.stopPropagation()\">\n <div class=\"datepicker-popover\" *ngIf=\"showCalendar\">\n <mat-calendar [(selected)]=\"selectedDate\" [dateFilter]=\"dateFilter\"\n (selectedChange)=\"onDateSelected($event)\" class=\"datepicker-calendar\">\n </mat-calendar>\n </div>\n </div>\n </div>\n </div>\n\n <!-- One slot-picker per resolved line, side by side when there's more than one (design doc \u00A73b) -->\n <div class=\"time_selection\" [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\" *ngIf=\"resolvedLines.length <= 1\">\n <div class=\"section-card card h-100 rounded-3 p-4\">\n <h3 class=\"section-title\">Available Times</h3>\n <div class=\"row g-2 mb-4 overflow-scroll\">\n <ng-container *ngIf=\"!skeletonLoader && resolvedLines[0]\">\n <div class=\"col-4\" *ngFor=\"let time of resolvedLines[0].slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(resolvedLines[0], time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Multi-line case: each line gets its own full-width card with a staff header -->\n <div class=\"d-flex gap-4 main_container flex-wrap\" *ngIf=\"resolvedLines.length > 1\">\n <div class=\"w-100\" *ngFor=\"let line of resolvedLines\">\n <div class=\"section-card card rounded-3 p-4\">\n <h3 class=\"section-title\">Professional: {{line.staffName || line.selectedStaffName}}</h3>\n <p class=\"mb-2\" *ngIf=\"line.services.length\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></p>\n <div class=\"row g-2 mb-2 overflow-scroll\">\n <ng-container *ngIf=\"!line.slotsLoading\">\n <div class=\"col-4\" *ngFor=\"let time of line.slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(line, time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #contactDetails>\n <div class=\"w-60 contact_section\">\n <div class=\"contact-header mb-2\">\n <h1>Contact Details</h1>\n <p class=\"contact-subtitle mb-0\">Provide your contact information</p>\n </div>\n\n <div class=\"d-flex gap-3 details_container flex-column w-100\">\n <div class=\"d-flex gap-4\">\n <div [ngClass]=\"{'w-50' : selectedMode === 'HOME_VISIT', 'w-100' : selectedMode !== 'HOME_VISIT'}\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Personal Information</h3>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Full Name\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"text\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.name\"\n (ngModelChange)=\"checkRequiredValues()\" simpoLettersOnly>\n </div>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Email Address\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"email\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.email\"\n (ngModelChange)=\"checkRequiredValues()\"\n pattern=\"^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$\" #emailField=\"ngModel\"\n name=\"email\" required>\n </div>\n\n <div class=\"mb-0\">\n <label class=\"form-label d-flex align-items-center\">\n Phone Number\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"tel\" class=\"form-control rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.phoneNumber\"\n (ngModelChange)=\"checkRequiredValues()\" simpoNumbersOnly\n [ngClass]=\"{'mobile_number' : appointmentPayload.customerDetail.phoneNumber.length != 10}\">\n </div>\n </div>\n </div>\n <!-- Home Visit address. Customer context: same saved-address flow as\n checkout/BookAppointmentComponent. Admin context (isAdminBooking): no\n logged-in customer account to read a saved address book from, so staff type\n the address manually instead. -->\n <div class=\"w-50\" *ngIf=\"selectedMode === 'HOME_VISIT'\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Home Visit Details</h3>\n\n <ng-container *ngIf=\"!isAdminBooking; else manualHomeVisitAddress\">\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n </ng-container>\n\n <ng-template #manualHomeVisitAddress>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Name</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.receiverName\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Phone</label>\n <input type=\"tel\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.receiverPhone\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 1</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine1\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 2 (optional)</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine2\">\n </div>\n <div class=\"d-flex gap-2 mb-3\">\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">City</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.city\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">State</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.state\">\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Pincode</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.zipCode\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n </ng-template>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Special Instructions</label>\n <textarea class=\"form-control form-textarea rounded-2\"\n placeholder=\"Any special instructions for the professional (optional)\"\n [(ngModel)]=\"instructions\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"policies-container\"\n *ngIf=\"cartServices[0]?.cancellationPolicy?.length > 0 || cartServices[0]?.reschedulePolicy?.length\">\n <h2 class=\"policies-title\">Policies & Terms</h2>\n\n <div class=\"policy-items-container d-flex flex-column gap-3\">\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showCancellationPolicy = !showCancellationPolicy\">\n <h3 class=\"policy-title\">Cancellation Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showCancellationPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showCancellationPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showCancellationPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.cancellationPolicy\">•\n {{policy}}</span>\n </div>\n\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showReducingPolicy = !showReducingPolicy\">\n <h3 class=\"policy-title\">Rescheduling Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showReducingPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showReducingPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showReducingPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.reschedulePolicy\">• {{policy}}</span>\n </div>\n </div>\n\n <div class=\"acceptance-section\">\n <input type=\"checkbox\" class=\"custom-checkbox\" [(ngModel)]=\"termsAndConditions\"\n (ngModelChange)=\"checkRequiredValues()\">\n <p class=\"acceptance-text\" style=\"margin-bottom:0px !important\">\n I understand and accept the cancellation & rescheduling policies.\n </p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #paymentTab>\n <div class=\"w-60 payment_section\">\n <div class=\"w-100 h-100\">\n <div class=\"w-100 d-flex justify-content-center align-items-center flex-column\">\n <div class=\"payment-header mb-3 w-100\">\n <h1 style=\"font-size:24px;font-weight: 600;\">Booking Summary</h1>\n <p class=\"payment-subtitle mb-0\">Review your booking before confirming</p>\n </div>\n\n <div class=\"booking-summary-card\" [ngClass]=\"{'w-100' : screenWidth < 475,'w-50':screenWidth > 475}\">\n <div *ngFor=\"let line of resolvedLines; let i = index\">\n <h2 class=\"summary-title\" *ngIf=\"resolvedLines.length > 1\">Line {{i + 1}}</h2>\n <div class=\"summary-row\" *ngIf=\"line.services.length\">\n <div class=\"summary-label\">Service(s)</div>\n <div class=\"summary-value\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></div>\n </div>\n <div class=\"summary-row\" *ngIf=\"line.staffName || line.selectedStaffName\">\n <div class=\"summary-label\">Professional</div>\n <div class=\"summary-value\">{{line.staffName || line.selectedStaffName}}</div>\n </div>\n <div class=\"summary-row\" *ngIf=\"selectedMode === 'STORE_VISIT'\">\n <div class=\"summary-label\">Location</div>\n <div class=\"summary-value\">{{selectedLocation?.storeName ?? 'N/A'}}</div>\n </div>\n <div class=\"summary-row\">\n <div class=\"summary-label\">Date & Time</div>\n <div class=\"summary-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</div>\n </div>\n </div>\n\n <div *ngIf=\"productCartItems.length > 0\">\n <h2 class=\"summary-title\">Products</h2>\n <div class=\"summary-row\" *ngFor=\"let p of productCartItems\">\n <div class=\"summary-label\">{{p.itemName}} x{{p.quantity}}</div>\n <div class=\"summary-value\"><span class=\"currency-symbol\">\u20B9</span>{{(p.sellingPrice ?? p.price ?? 0) * (p.quantity ?? 1)}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusTemplate>\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book you appointment. Please\n try again later'}}\n </p>\n\n <!-- Video Call link, when already present on the confirmed group (a paid Video Call's\n link only appears once payment verification completes, handled elsewhere - see\n verify-payment.component.ts, not this screen). -->\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && selectedMode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\" *ngFor=\"let line of resolvedLines\">\n <span class=\"detail-label\">{{line.services.length ? (line.services[0].name) : 'Products'}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <ng-container *ngIf=\"!isAdminContext; else adminDoneActions\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </ng-container>\n <ng-template #adminDoneActions>\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToAppointmentsList()\">Back to Appointments List</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"bookAnother()\">Book Another</button>\n </ng-template>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.date-picker-container{border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;display:flex;align-items:center;justify-content:space-between;transition:var(--transition-smooth);background-color:var(--slate-50);cursor:pointer}.date-picker-container:hover{border-color:var(--slate-400);background-color:#fff}.date-input{font-size:.95rem;font-weight:600;color:var(--slate-800)!important;background:transparent;border:none;outline:none;cursor:pointer;width:100%}.date-picker-container mat-icon{color:var(--color-primary)!important;font-size:20px!important;width:20px!important;height:20px!important}.datepicker-popover{position:absolute;z-index:1000;margin-top:4px;border-radius:var(--border-radius-lg);overflow:hidden;box-shadow:var(--shadow-xl);background:#fff;border:1px solid var(--slate-200);width:320px}::ng-deep .datepicker-calendar{border-radius:var(--border-radius-lg)!important;width:100%!important}::ng-deep .mat-calendar-header{background:var(--color-accent-gradient)!important;color:#fff!important;padding:.5rem!important}::ng-deep .mat-calendar-content{padding:8px!important}::ng-deep .mat-calendar-controls{margin:0!important}::ng-deep .mat-calendar-period-button{color:#fff!important;font-weight:700!important;font-size:1rem!important}::ng-deep .mat-calendar-arrow{fill:#fff!important}::ng-deep .mat-calendar-previous-button,::ng-deep .mat-calendar-next-button{color:#fff!important}::ng-deep .mat-calendar-body-cell{font-size:13px!important}::ng-deep .mat-calendar-body-cell-content{font-weight:600!important;color:var(--slate-800)!important;border-radius:8px!important}::ng-deep .mat-calendar-body-selected{background:var(--color-accent-gradient)!important;color:#fff!important;box-shadow:0 4px 10px #23086033!important}::ng-deep .mat-calendar-body-today:not(.mat-calendar-body-selected){border:2px solid var(--color-primary)!important;color:var(--color-primary)!important}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.datepicker-popover{width:100%;left:0}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}h1{font-size:24px!important;font-weight:600!important}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i3.SlicePipe, name: "slice" }, { kind: "pipe", type: i3.TitleCasePipe, name: "titlecase" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i9$2.MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection", "_userDragDrop"], exportAs: ["matCalendar"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i9.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: LettersOnlyDirective, selector: "[simpoLettersOnly]" }, { kind: "directive", type: NumbersOnlyDirective, selector: "[simpoNumbersOnly]" }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }] }); }
|
|
25978
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AppointmentBookingComponent, isStandalone: true, selector: "simpo-appointment-booking", inputs: { data: "data", index: "index", edit: "edit", isAdminBooking: "isAdminBooking", delete: "delete", customClass: "customClass", nextComponentColor: "nextComponentColor", prefillContact: "prefillContact" }, host: { listeners: { "window: resize": "getScreenSize($event)", "document:click": "closeOnOutsideClick()" } }, providers: [MessageService], usesInheritance: true, ngImport: i0, template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\" simpoHover (hovering)=\"showEditTabs($event)\"\n [simpoBackground]=\"backgroundInfo\" [style.--color-accent-gradient]=\"accentColor\">\n <div [ngClass]=\"{'hover_effect': edit}\" *ngIf=\"showEditors\">\n <simpo-hover-elements [data]=\"data\" [index]=\"index\" [editOptions]=\"edit\"></simpo-hover-elements>\n </div>\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"back-btn d-flex justify-content-center align-items-center cursor-pointer gap-2 mb-3\"\n (click)=\"goBack()\">\n <mat-icon>keyboard_backspace</mat-icon><span *ngIf=\"screenWidth > 475\">Back to Home</span>\n </div>\n <div class=\"header-title\">\n <h1>Book New Appointment</h1>\n <p>{{businessName ?? \"N/A\" }}</p>\n </div>\n </div>\n\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width]=\"barWidth + '%'\"></div>\n </div>\n </div>\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <ng-container *ngIf=\"selectedTab === 'modeSelection'\">\n <ng-container *ngTemplateOutlet=\"modeSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'serviceListing'\">\n <ng-container *ngIf=\"!skeletonLoader\">\n <ng-container *ngTemplateOutlet=\"serviceListing\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'locationListing'\">\n <ng-container *ngTemplateOutlet=\"locationListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'staffListing'\">\n <ng-container *ngTemplateOutlet=\"staffListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'dateSelection'\">\n <ng-container *ngTemplateOutlet=\"dateSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='contactDetails'\">\n <ng-container *ngTemplateOutlet=\"contactDetails\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='paymentTab'\">\n <ng-container *ngTemplateOutlet=\"paymentTab\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='statusTemplate'\">\n <ng-container *ngTemplateOutlet=\"statusTemplate\"></ng-container>\n </ng-container>\n </div>\n <div class=\"main_footer d-flex justify-content-center align-items-center\"\n *ngIf=\"selectedTab!=='statusTemplate' && selectedTab!=='modeSelection'\">\n <div class=\"footer-buttons\"\n [ngStyle]=\"{'justify-content': selectedTab != 'serviceListing' ? 'space-between' : 'end'}\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"previousStep()\"\n *ngIf=\"selectedTab != 'serviceListing'\">Back</span>\n <button class=\"continue-btn\" [disabled]=\"!activeButton\" (click)=\"nextStep()\"\n *ngIf=\"selectedTab!='paymentTab'\">{{!loader ? 'Continue' : 'Loading...'}}</button>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center\"\n *ngIf=\"selectedTab==='paymentTab'\" (click)=\"confirmBooking()\" [disabled]=\"isProcessing\"\n [ngClass]=\"{'pay-now-btn' : bookingGroup?.totalCollectedAtBooking > 0 || !bookingGroup,'complete_booking' : bookingGroup && !bookingGroup?.totalCollectedAtBooking}\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n\n<ng-template #modeSelection>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>How would you like this?</h2>\n <p>Choose how you'd like to be served</p>\n <div class=\"services-grid\">\n <div class=\"service-card\" (click)=\"selectMode('STORE_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>storefront</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Visit our Store</div>\n </div>\n </div>\n <div class=\"service-description\">Come to us at one of our locations</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('HOME_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>home</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">We come to you</div>\n </div>\n </div>\n <div class=\"service-description\">A professional visits your address</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('VIDEO_CALL')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>videocam</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Video consultation</div>\n </div>\n </div>\n <div class=\"service-description\">Connect over a video call</div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #serviceListing>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>Select a Service</h2>\n <p>Choose the service(s) you'd like to book<span *ngIf=\"cartServices.length > 0\"> \u2014 {{cartServices.length}} selected</span></p>\n <p *ngIf=\"productCartItems.length > 0\" class=\"cart-hint\">{{productCartItems.length}} product(s) already in your cart \u2014 you can continue without picking a service.</p>\n\n <div class=\"services-grid\">\n <ng-container *ngFor=\"let service of serviceData\">\n <div class=\"\" (click)=\"selectService(service)\"\n [ngClass]=\"{ 'service-card-selected' : service?.selected, 'service-card': !service?.selected }\">\n <div class=\" service-header\">\n <div class=\"service-icon\"><mat-icon>person_outline</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">{{service?.name ? service?.name : 'N/A'}}</div>\n </div>\n <div>\n <div class=\"service-price\">\u20B9{{service?.priceDetails?.price ?\n service?.priceDetails?.price : 'N/A' }}</div>\n <div class=\"service-duration\">{{service?.duration ? service?.duration : 'N/A'}} min\n </div>\n </div>\n </div>\n <div class=\"service-description\" *ngIf=\"service?.description\">\n {{service?.description ? service?.description : 'N/A'}}\n </div>\n <div class=\"home-visit\" *ngIf=\"selectedMode === 'STORE_VISIT' && service?.homeAppointmentAvailable\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/982126c1758628863129furniture_16406103.png\">Home\n Visit Available</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #locationListing>\n <div class=\"location_section\">\n <div class=\"header flex-column align-items-start\">\n <h1>Choose Location</h1>\n <p>Select where you'd like to receive the service</p>\n </div>\n\n <div class=\"location-list\">\n <ng-container *ngFor=\"let location of locationData\">\n <div (click)=\"selectLocation(location)\"\n [ngClass]=\"{ 'location-card-selected' : location?.selected, 'location-card': !location?.selected }\">\n <div class=\"location-content\">\n <div class=\"location-info\">\n <div class=\"location-icon\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/427226c1758629157758store_3171510.png\">\n </div>\n <div class=\"location-details\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <h3>{{location?.storeName ? location?.storeName : 'N/A'}}</h3>\n </div>\n <p>{{location?.addressDetails?.addressLine}}, {{location?.addressDetails?.city}},\n {{location?.addressDetails?.state}} {{location?.pincode}}</p>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #staffListing>\n <div class=\"w-60 overflow-hidden staff-listing\">\n <div class=\"d-flex w-100 h-100\">\n <div class=\"w-100\">\n <div class=\"staff-header mb-3\">\n <h1>Select Staff Member</h1>\n <p class=\"staff-subtitle mb-0\">Choose your preferred professional</p>\n </div>\n\n <div class=\"search-container mb-4\">\n <div class=\"search-input-wrapper d-flex align-items-center\">\n <mat-icon class=\"search-icon me-2\">search</mat-icon>\n <input type=\"text\" class=\"search-input border-0 flex-grow-1\" placeholder=\"Search staff member by name...\" [(ngModel)]=\"staffSearchQuery\">\n <mat-icon class=\"clear-icon cursor-pointer ms-2\" *ngIf=\"staffSearchQuery\" (click)=\"staffSearchQuery = ''\">close</mat-icon>\n </div>\n </div>\n\n <!-- Pure product-only line: one flat staff list, same as the old single-service flow -->\n <div class=\"staff-list\" *ngIf=\"cartServices.length === 0\">\n <ng-container *ngFor=\"let staff of filteredStaff\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForProductOnlyLine(staff)\"\n [ngClass]=\"{ 'staff-card-selected' : staff?.selected, 'staff-card': !staff?.selected }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.staffName.slice(0,2).toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.staffName ? staff?.staffName : 'N/A') | titlecase}}</h3>\n <p class=\"staff-specialty\">{{(businessName && businessName !== 'N/A') ? businessName : 'Booking Specialist'}}</p>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"staff?.selected\">\n <mat-icon *ngIf=\"staff?.selected\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Bundled cart: one pool per line that resolution couldn't collapse to a single provider -->\n <ng-container *ngIf=\"cartServices.length > 0\">\n <div class=\"staff-line-group mb-4\" *ngFor=\"let line of resolvedLines\">\n <ng-container *ngIf=\"line.candidateStaffPool?.length\">\n <h4 class=\"mb-2\">For {{line.services.length}} service(s): {{ (line.services | slice:0:3).length ? '' : '' }}<span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></h4>\n <div class=\"staff-list mb-3\">\n <ng-container *ngFor=\"let staff of line.candidateStaffPool\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForLine(line, staff)\"\n [ngClass]=\"{ 'staff-card-selected' : line.selectedStaffId === staff.id, 'staff-card': line.selectedStaffId !== staff.id }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.name?.slice(0,2)?.toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.name ? staff?.name : 'N/A') | titlecase}}</h3>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"line.selectedStaffId === staff.id\">\n <mat-icon *ngIf=\"line.selectedStaffId === staff.id\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateSelection>\n <div class=\"w-60 date_section\">\n <div class=\"row justify-content-center h-100\">\n <div class=\"col-12 h-100\">\n <div class=\"datetime-header mb-2\">\n <h1>Select Date & Time</h1>\n <p class=\"datetime-subtitle mb-0\">Choose when you'd like your appointment</p>\n </div>\n\n <div class=\"d-flex gap-4 main_container\">\n <div [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\">\n <div class=\"section-card card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Select Date</h3>\n\n <div class=\"date-picker-container d-flex align-items-center justify-content-between\"\n (click)=\"$event.stopPropagation()\">\n <input type=\"text\" class=\"date-input border-0 rounded-2\" placeholder=\"dd-mm-yyyy\"\n [value]=\"selectedDateStr\" readonly (click)=\"toggleCalendar($event)\">\n\n <mat-icon class=\"ms-2\" (click)=\"toggleCalendar($event)\">calendar_today</mat-icon>\n </div>\n <div class=\"position-relative\" (click)=\"$event.stopPropagation()\">\n <div class=\"datepicker-popover\" *ngIf=\"showCalendar\">\n <mat-calendar [(selected)]=\"selectedDate\" [dateFilter]=\"dateFilter\"\n (selectedChange)=\"onDateSelected($event)\" class=\"datepicker-calendar\">\n </mat-calendar>\n </div>\n </div>\n </div>\n </div>\n\n <!-- One slot-picker per resolved line, side by side when there's more than one (design doc \u00A73b) -->\n <div class=\"time_selection\" [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\" *ngIf=\"resolvedLines.length <= 1\">\n <div class=\"section-card card h-100 rounded-3 p-4\">\n <h3 class=\"section-title\">Available Times</h3>\n <div class=\"row g-2 mb-4 overflow-scroll\">\n <ng-container *ngIf=\"!skeletonLoader && resolvedLines[0]\">\n <div class=\"col-4\" *ngFor=\"let time of resolvedLines[0].slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(resolvedLines[0], time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Multi-line case: each line gets its own full-width card with a staff header -->\n <div class=\"d-flex gap-4 main_container flex-wrap\" *ngIf=\"resolvedLines.length > 1\">\n <div class=\"w-100\" *ngFor=\"let line of resolvedLines\">\n <div class=\"section-card card rounded-3 p-4\">\n <h3 class=\"section-title\">Professional: {{line.staffName || line.selectedStaffName}}</h3>\n <p class=\"mb-2\" *ngIf=\"line.services.length\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></p>\n <div class=\"row g-2 mb-2 overflow-scroll\">\n <ng-container *ngIf=\"!line.slotsLoading\">\n <div class=\"col-4\" *ngFor=\"let time of line.slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(line, time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #contactDetails>\n <div class=\"w-60 contact_section\">\n <div class=\"contact-header mb-2\">\n <h1>Contact Details</h1>\n <p class=\"contact-subtitle mb-0\">Provide your contact information</p>\n </div>\n\n <div class=\"d-flex gap-3 details_container flex-column w-100\">\n <div class=\"d-flex gap-4\">\n <div [ngClass]=\"{'w-50' : selectedMode === 'HOME_VISIT', 'w-100' : selectedMode !== 'HOME_VISIT'}\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Personal Information</h3>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Full Name\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"text\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.name\"\n (ngModelChange)=\"checkRequiredValues()\" simpoLettersOnly>\n </div>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Email Address\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"email\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.email\"\n (ngModelChange)=\"checkRequiredValues()\"\n pattern=\"^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$\" #emailField=\"ngModel\"\n name=\"email\" required>\n </div>\n\n <div class=\"mb-0\">\n <label class=\"form-label d-flex align-items-center\">\n Phone Number\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"tel\" class=\"form-control rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.phoneNumber\"\n (ngModelChange)=\"checkRequiredValues()\" simpoNumbersOnly\n [ngClass]=\"{'mobile_number' : appointmentPayload.customerDetail.phoneNumber.length != 10}\">\n </div>\n </div>\n </div>\n <!-- Home Visit address. Customer context: same saved-address flow as\n checkout/BookAppointmentComponent. Admin context (isAdminBooking): no\n logged-in customer account to read a saved address book from, so staff type\n the address manually instead. -->\n <div class=\"w-50\" *ngIf=\"selectedMode === 'HOME_VISIT'\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Home Visit Details</h3>\n\n <ng-container *ngIf=\"!isAdminBooking; else manualHomeVisitAddress\">\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n </ng-container>\n\n <ng-template #manualHomeVisitAddress>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Name</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.receiverName\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Phone</label>\n <input type=\"tel\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.receiverPhone\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 1</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine1\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 2 (optional)</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine2\">\n </div>\n <div class=\"d-flex gap-2 mb-3\">\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">City</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.city\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">State</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.state\">\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Pincode</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.zipCode\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n </ng-template>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Special Instructions</label>\n <textarea class=\"form-control form-textarea rounded-2\"\n placeholder=\"Any special instructions for the professional (optional)\"\n [(ngModel)]=\"instructions\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"policies-container\"\n *ngIf=\"cartServices[0]?.cancellationPolicy?.length > 0 || cartServices[0]?.reschedulePolicy?.length\">\n <h2 class=\"policies-title\">Policies & Terms</h2>\n\n <div class=\"policy-items-container d-flex flex-column gap-3\">\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showCancellationPolicy = !showCancellationPolicy\">\n <h3 class=\"policy-title\">Cancellation Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showCancellationPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showCancellationPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showCancellationPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.cancellationPolicy\">•\n {{policy}}</span>\n </div>\n\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showReducingPolicy = !showReducingPolicy\">\n <h3 class=\"policy-title\">Rescheduling Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showReducingPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showReducingPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showReducingPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.reschedulePolicy\">• {{policy}}</span>\n </div>\n </div>\n\n <div class=\"acceptance-section\">\n <input type=\"checkbox\" class=\"custom-checkbox\" [(ngModel)]=\"termsAndConditions\"\n (ngModelChange)=\"checkRequiredValues()\">\n <p class=\"acceptance-text\" style=\"margin-bottom:0px !important\">\n I understand and accept the cancellation & rescheduling policies.\n </p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #paymentTab>\n <div class=\"w-60 payment_section\">\n <div class=\"w-100 h-100\">\n <div class=\"w-100 d-flex justify-content-center align-items-center flex-column\">\n <div class=\"payment-header mb-3 w-100\">\n <h1 style=\"font-size:24px;font-weight: 600;\">Booking Summary</h1>\n <p class=\"payment-subtitle mb-0\">Review your booking before confirming</p>\n </div>\n\n <div class=\"booking-summary-card\" [ngClass]=\"{'w-100' : screenWidth < 475,'w-50':screenWidth > 475}\">\n <div *ngFor=\"let line of resolvedLines; let i = index\">\n <h2 class=\"summary-title\" *ngIf=\"resolvedLines.length > 1\">Line {{i + 1}}</h2>\n <div class=\"summary-row\" *ngIf=\"line.services.length\">\n <div class=\"summary-label\">Service(s)</div>\n <div class=\"summary-value\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></div>\n </div>\n <div class=\"summary-row\" *ngIf=\"line.staffName || line.selectedStaffName\">\n <div class=\"summary-label\">Professional</div>\n <div class=\"summary-value\">{{line.staffName || line.selectedStaffName}}</div>\n </div>\n <div class=\"summary-row\" *ngIf=\"selectedMode === 'STORE_VISIT'\">\n <div class=\"summary-label\">Location</div>\n <div class=\"summary-value\">{{selectedLocation?.storeName ?? 'N/A'}}</div>\n </div>\n <div class=\"summary-row\">\n <div class=\"summary-label\">Date & Time</div>\n <div class=\"summary-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</div>\n </div>\n </div>\n\n <div *ngIf=\"productCartItems.length > 0\">\n <h2 class=\"summary-title\">Products</h2>\n <div class=\"summary-row\" *ngFor=\"let p of productCartItems\">\n <div class=\"summary-label\">{{p.itemName}} x{{p.quantity}}</div>\n <div class=\"summary-value\"><span class=\"currency-symbol\">\u20B9</span>{{(p.sellingPrice ?? p.price ?? 0) * (p.quantity ?? 1)}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusTemplate>\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book you appointment. Please\n try again later'}}\n </p>\n\n <!-- Video Call link, when already present on the confirmed group (a paid Video Call's\n link only appears once payment verification completes, handled elsewhere - see\n verify-payment.component.ts, not this screen). -->\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && selectedMode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\" *ngFor=\"let line of resolvedLines\">\n <span class=\"detail-label\">{{line.services.length ? (line.services[0].name) : 'Products'}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <ng-container *ngIf=\"!isAdminContext; else adminDoneActions\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </ng-container>\n <ng-template #adminDoneActions>\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToAppointmentsList()\">Back to Appointments List</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"bookAnother()\">Book Another</button>\n </ng-template>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.hover_effect{position:absolute;width:100%;top:0;left:0;height:100%}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.date-picker-container{border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;display:flex;align-items:center;justify-content:space-between;transition:var(--transition-smooth);background-color:var(--slate-50);cursor:pointer}.date-picker-container:hover{border-color:var(--slate-400);background-color:#fff}.date-input{font-size:.95rem;font-weight:600;color:var(--slate-800)!important;background:transparent;border:none;outline:none;cursor:pointer;width:100%}.date-picker-container mat-icon{color:var(--color-primary)!important;font-size:20px!important;width:20px!important;height:20px!important}.datepicker-popover{position:absolute;z-index:1000;margin-top:4px;border-radius:var(--border-radius-lg);overflow:hidden;box-shadow:var(--shadow-xl);background:#fff;border:1px solid var(--slate-200);width:320px}::ng-deep .datepicker-calendar{border-radius:var(--border-radius-lg)!important;width:100%!important}::ng-deep .mat-calendar-header{background:var(--color-accent-gradient)!important;color:#fff!important;padding:.5rem!important}::ng-deep .mat-calendar-content{padding:8px!important}::ng-deep .mat-calendar-controls{margin:0!important}::ng-deep .mat-calendar-period-button{color:#fff!important;font-weight:700!important;font-size:1rem!important}::ng-deep .mat-calendar-arrow{fill:#fff!important}::ng-deep .mat-calendar-previous-button,::ng-deep .mat-calendar-next-button{color:#fff!important}::ng-deep .mat-calendar-body-cell{font-size:13px!important}::ng-deep .mat-calendar-body-cell-content{font-weight:600!important;color:var(--slate-800)!important;border-radius:8px!important}::ng-deep .mat-calendar-body-selected{background:var(--color-accent-gradient)!important;color:#fff!important;box-shadow:0 4px 10px #23086033!important}::ng-deep .mat-calendar-body-today:not(.mat-calendar-body-selected){border:2px solid var(--color-primary)!important;color:var(--color-primary)!important}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.datepicker-popover{width:100%;left:0}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}h1{font-size:24px!important;font-weight:600!important}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i3.SlicePipe, name: "slice" }, { kind: "pipe", type: i3.TitleCasePipe, name: "titlecase" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i9$2.MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection", "_userDragDrop"], exportAs: ["matCalendar"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i9.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: LettersOnlyDirective, selector: "[simpoLettersOnly]" }, { kind: "directive", type: NumbersOnlyDirective, selector: "[simpoNumbersOnly]" }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "directive", type: HoverDirective, selector: "[simpoHover]", outputs: ["hovering"] }, { kind: "component", type: HoverElementsComponent, selector: "simpo-hover-elements", inputs: ["data", "index", "editOptions", "isMerged", "isEcommerce"], outputs: ["edit"] }, { kind: "directive", type: BackgroundDirective, selector: "[simpoBackground]", inputs: ["simpoBackground", "scrollValue"] }] }); }
|
|
25955
25979
|
}
|
|
25956
25980
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppointmentBookingComponent, decorators: [{
|
|
25957
25981
|
type: Component,
|
|
25958
|
-
args: [{ selector: 'simpo-appointment-booking', standalone: true, imports: [CdkDragPlaceholder, CommonModule, MatIcon, MatFormFieldModule, MatDatepickerModule, FormsModule, MatNativeDateModule, MatInputModule, MatDialogModule, LettersOnlyDirective, NumbersOnlyDirective, ToastModule], providers: [MessageService], template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\">\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"back-btn d-flex justify-content-center align-items-center cursor-pointer gap-2 mb-3\"\n (click)=\"goBack()\">\n <mat-icon>keyboard_backspace</mat-icon><span *ngIf=\"screenWidth > 475\">Back to Home</span>\n </div>\n <div class=\"header-title\">\n <h1>Book New Appointment</h1>\n <p>{{businessName ?? \"N/A\" }}</p>\n </div>\n </div>\n\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width]=\"barWidth + '%'\"></div>\n </div>\n </div>\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <ng-container *ngIf=\"selectedTab === 'modeSelection'\">\n <ng-container *ngTemplateOutlet=\"modeSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'serviceListing'\">\n <ng-container *ngIf=\"!skeletonLoader\">\n <ng-container *ngTemplateOutlet=\"serviceListing\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'locationListing'\">\n <ng-container *ngTemplateOutlet=\"locationListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'staffListing'\">\n <ng-container *ngTemplateOutlet=\"staffListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'dateSelection'\">\n <ng-container *ngTemplateOutlet=\"dateSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='contactDetails'\">\n <ng-container *ngTemplateOutlet=\"contactDetails\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='paymentTab'\">\n <ng-container *ngTemplateOutlet=\"paymentTab\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='statusTemplate'\">\n <ng-container *ngTemplateOutlet=\"statusTemplate\"></ng-container>\n </ng-container>\n </div>\n <div class=\"main_footer d-flex justify-content-center align-items-center\"\n *ngIf=\"selectedTab!=='statusTemplate' && selectedTab!=='modeSelection'\">\n <div class=\"footer-buttons\"\n [ngStyle]=\"{'justify-content': selectedTab != 'serviceListing' ? 'space-between' : 'end'}\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"previousStep()\"\n *ngIf=\"selectedTab != 'serviceListing'\">Back</span>\n <button class=\"continue-btn\" [disabled]=\"!activeButton\" (click)=\"nextStep()\"\n *ngIf=\"selectedTab!='paymentTab'\">{{!loader ? 'Continue' : 'Loading...'}}</button>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center\"\n *ngIf=\"selectedTab==='paymentTab'\" (click)=\"confirmBooking()\" [disabled]=\"isProcessing\"\n [ngClass]=\"{'pay-now-btn' : bookingGroup?.totalCollectedAtBooking > 0 || !bookingGroup,'complete_booking' : bookingGroup && !bookingGroup?.totalCollectedAtBooking}\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n\n<ng-template #modeSelection>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>How would you like this?</h2>\n <p>Choose how you'd like to be served</p>\n <div class=\"services-grid\">\n <div class=\"service-card\" (click)=\"selectMode('STORE_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>storefront</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Visit our Store</div>\n </div>\n </div>\n <div class=\"service-description\">Come to us at one of our locations</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('HOME_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>home</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">We come to you</div>\n </div>\n </div>\n <div class=\"service-description\">A professional visits your address</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('VIDEO_CALL')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>videocam</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Video consultation</div>\n </div>\n </div>\n <div class=\"service-description\">Connect over a video call</div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #serviceListing>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>Select a Service</h2>\n <p>Choose the service(s) you'd like to book<span *ngIf=\"cartServices.length > 0\"> \u2014 {{cartServices.length}} selected</span></p>\n <p *ngIf=\"productCartItems.length > 0\" class=\"cart-hint\">{{productCartItems.length}} product(s) already in your cart \u2014 you can continue without picking a service.</p>\n\n <div class=\"services-grid\">\n <ng-container *ngFor=\"let service of serviceData\">\n <div class=\"\" (click)=\"selectService(service)\"\n [ngClass]=\"{ 'service-card-selected' : service?.selected, 'service-card': !service?.selected }\">\n <div class=\" service-header\">\n <div class=\"service-icon\"><mat-icon>person_outline</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">{{service?.name ? service?.name : 'N/A'}}</div>\n </div>\n <div>\n <div class=\"service-price\">\u20B9{{service?.priceDetails?.price ?\n service?.priceDetails?.price : 'N/A' }}</div>\n <div class=\"service-duration\">{{service?.duration ? service?.duration : 'N/A'}} min\n </div>\n </div>\n </div>\n <div class=\"service-description\" *ngIf=\"service?.description\">\n {{service?.description ? service?.description : 'N/A'}}\n </div>\n <div class=\"home-visit\" *ngIf=\"selectedMode === 'STORE_VISIT' && service?.homeAppointmentAvailable\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/982126c1758628863129furniture_16406103.png\">Home\n Visit Available</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #locationListing>\n <div class=\"location_section\">\n <div class=\"header flex-column align-items-start\">\n <h1>Choose Location</h1>\n <p>Select where you'd like to receive the service</p>\n </div>\n\n <div class=\"location-list\">\n <ng-container *ngFor=\"let location of locationData\">\n <div (click)=\"selectLocation(location)\"\n [ngClass]=\"{ 'location-card-selected' : location?.selected, 'location-card': !location?.selected }\">\n <div class=\"location-content\">\n <div class=\"location-info\">\n <div class=\"location-icon\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/427226c1758629157758store_3171510.png\">\n </div>\n <div class=\"location-details\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <h3>{{location?.storeName ? location?.storeName : 'N/A'}}</h3>\n </div>\n <p>{{location?.addressDetails?.addressLine}}, {{location?.addressDetails?.city}},\n {{location?.addressDetails?.state}} {{location?.pincode}}</p>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #staffListing>\n <div class=\"w-60 overflow-hidden staff-listing\">\n <div class=\"d-flex w-100 h-100\">\n <div class=\"w-100\">\n <div class=\"staff-header mb-3\">\n <h1>Select Staff Member</h1>\n <p class=\"staff-subtitle mb-0\">Choose your preferred professional</p>\n </div>\n\n <div class=\"search-container mb-4\">\n <div class=\"search-input-wrapper d-flex align-items-center\">\n <mat-icon class=\"search-icon me-2\">search</mat-icon>\n <input type=\"text\" class=\"search-input border-0 flex-grow-1\" placeholder=\"Search staff member by name...\" [(ngModel)]=\"staffSearchQuery\">\n <mat-icon class=\"clear-icon cursor-pointer ms-2\" *ngIf=\"staffSearchQuery\" (click)=\"staffSearchQuery = ''\">close</mat-icon>\n </div>\n </div>\n\n <!-- Pure product-only line: one flat staff list, same as the old single-service flow -->\n <div class=\"staff-list\" *ngIf=\"cartServices.length === 0\">\n <ng-container *ngFor=\"let staff of filteredStaff\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForProductOnlyLine(staff)\"\n [ngClass]=\"{ 'staff-card-selected' : staff?.selected, 'staff-card': !staff?.selected }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.staffName.slice(0,2).toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.staffName ? staff?.staffName : 'N/A') | titlecase}}</h3>\n <p class=\"staff-specialty\">{{(businessName && businessName !== 'N/A') ? businessName : 'Booking Specialist'}}</p>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"staff?.selected\">\n <mat-icon *ngIf=\"staff?.selected\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Bundled cart: one pool per line that resolution couldn't collapse to a single provider -->\n <ng-container *ngIf=\"cartServices.length > 0\">\n <div class=\"staff-line-group mb-4\" *ngFor=\"let line of resolvedLines\">\n <ng-container *ngIf=\"line.candidateStaffPool?.length\">\n <h4 class=\"mb-2\">For {{line.services.length}} service(s): {{ (line.services | slice:0:3).length ? '' : '' }}<span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></h4>\n <div class=\"staff-list mb-3\">\n <ng-container *ngFor=\"let staff of line.candidateStaffPool\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForLine(line, staff)\"\n [ngClass]=\"{ 'staff-card-selected' : line.selectedStaffId === staff.id, 'staff-card': line.selectedStaffId !== staff.id }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.name?.slice(0,2)?.toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.name ? staff?.name : 'N/A') | titlecase}}</h3>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"line.selectedStaffId === staff.id\">\n <mat-icon *ngIf=\"line.selectedStaffId === staff.id\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateSelection>\n <div class=\"w-60 date_section\">\n <div class=\"row justify-content-center h-100\">\n <div class=\"col-12 h-100\">\n <div class=\"datetime-header mb-2\">\n <h1>Select Date & Time</h1>\n <p class=\"datetime-subtitle mb-0\">Choose when you'd like your appointment</p>\n </div>\n\n <div class=\"d-flex gap-4 main_container\">\n <div [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\">\n <div class=\"section-card card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Select Date</h3>\n\n <div class=\"date-picker-container d-flex align-items-center justify-content-between\"\n (click)=\"$event.stopPropagation()\">\n <input type=\"text\" class=\"date-input border-0 rounded-2\" placeholder=\"dd-mm-yyyy\"\n [value]=\"selectedDateStr\" readonly (click)=\"toggleCalendar($event)\">\n\n <mat-icon class=\"ms-2\" (click)=\"toggleCalendar($event)\">calendar_today</mat-icon>\n </div>\n <div class=\"position-relative\" (click)=\"$event.stopPropagation()\">\n <div class=\"datepicker-popover\" *ngIf=\"showCalendar\">\n <mat-calendar [(selected)]=\"selectedDate\" [dateFilter]=\"dateFilter\"\n (selectedChange)=\"onDateSelected($event)\" class=\"datepicker-calendar\">\n </mat-calendar>\n </div>\n </div>\n </div>\n </div>\n\n <!-- One slot-picker per resolved line, side by side when there's more than one (design doc \u00A73b) -->\n <div class=\"time_selection\" [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\" *ngIf=\"resolvedLines.length <= 1\">\n <div class=\"section-card card h-100 rounded-3 p-4\">\n <h3 class=\"section-title\">Available Times</h3>\n <div class=\"row g-2 mb-4 overflow-scroll\">\n <ng-container *ngIf=\"!skeletonLoader && resolvedLines[0]\">\n <div class=\"col-4\" *ngFor=\"let time of resolvedLines[0].slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(resolvedLines[0], time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Multi-line case: each line gets its own full-width card with a staff header -->\n <div class=\"d-flex gap-4 main_container flex-wrap\" *ngIf=\"resolvedLines.length > 1\">\n <div class=\"w-100\" *ngFor=\"let line of resolvedLines\">\n <div class=\"section-card card rounded-3 p-4\">\n <h3 class=\"section-title\">Professional: {{line.staffName || line.selectedStaffName}}</h3>\n <p class=\"mb-2\" *ngIf=\"line.services.length\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></p>\n <div class=\"row g-2 mb-2 overflow-scroll\">\n <ng-container *ngIf=\"!line.slotsLoading\">\n <div class=\"col-4\" *ngFor=\"let time of line.slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(line, time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #contactDetails>\n <div class=\"w-60 contact_section\">\n <div class=\"contact-header mb-2\">\n <h1>Contact Details</h1>\n <p class=\"contact-subtitle mb-0\">Provide your contact information</p>\n </div>\n\n <div class=\"d-flex gap-3 details_container flex-column w-100\">\n <div class=\"d-flex gap-4\">\n <div [ngClass]=\"{'w-50' : selectedMode === 'HOME_VISIT', 'w-100' : selectedMode !== 'HOME_VISIT'}\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Personal Information</h3>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Full Name\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"text\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.name\"\n (ngModelChange)=\"checkRequiredValues()\" simpoLettersOnly>\n </div>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Email Address\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"email\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.email\"\n (ngModelChange)=\"checkRequiredValues()\"\n pattern=\"^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$\" #emailField=\"ngModel\"\n name=\"email\" required>\n </div>\n\n <div class=\"mb-0\">\n <label class=\"form-label d-flex align-items-center\">\n Phone Number\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"tel\" class=\"form-control rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.phoneNumber\"\n (ngModelChange)=\"checkRequiredValues()\" simpoNumbersOnly\n [ngClass]=\"{'mobile_number' : appointmentPayload.customerDetail.phoneNumber.length != 10}\">\n </div>\n </div>\n </div>\n <!-- Home Visit address. Customer context: same saved-address flow as\n checkout/BookAppointmentComponent. Admin context (isAdminBooking): no\n logged-in customer account to read a saved address book from, so staff type\n the address manually instead. -->\n <div class=\"w-50\" *ngIf=\"selectedMode === 'HOME_VISIT'\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Home Visit Details</h3>\n\n <ng-container *ngIf=\"!isAdminBooking; else manualHomeVisitAddress\">\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n </ng-container>\n\n <ng-template #manualHomeVisitAddress>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Name</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.receiverName\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Phone</label>\n <input type=\"tel\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.receiverPhone\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 1</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine1\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 2 (optional)</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine2\">\n </div>\n <div class=\"d-flex gap-2 mb-3\">\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">City</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.city\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">State</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.state\">\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Pincode</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.zipCode\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n </ng-template>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Special Instructions</label>\n <textarea class=\"form-control form-textarea rounded-2\"\n placeholder=\"Any special instructions for the professional (optional)\"\n [(ngModel)]=\"instructions\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"policies-container\"\n *ngIf=\"cartServices[0]?.cancellationPolicy?.length > 0 || cartServices[0]?.reschedulePolicy?.length\">\n <h2 class=\"policies-title\">Policies & Terms</h2>\n\n <div class=\"policy-items-container d-flex flex-column gap-3\">\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showCancellationPolicy = !showCancellationPolicy\">\n <h3 class=\"policy-title\">Cancellation Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showCancellationPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showCancellationPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showCancellationPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.cancellationPolicy\">•\n {{policy}}</span>\n </div>\n\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showReducingPolicy = !showReducingPolicy\">\n <h3 class=\"policy-title\">Rescheduling Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showReducingPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showReducingPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showReducingPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.reschedulePolicy\">• {{policy}}</span>\n </div>\n </div>\n\n <div class=\"acceptance-section\">\n <input type=\"checkbox\" class=\"custom-checkbox\" [(ngModel)]=\"termsAndConditions\"\n (ngModelChange)=\"checkRequiredValues()\">\n <p class=\"acceptance-text\" style=\"margin-bottom:0px !important\">\n I understand and accept the cancellation & rescheduling policies.\n </p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #paymentTab>\n <div class=\"w-60 payment_section\">\n <div class=\"w-100 h-100\">\n <div class=\"w-100 d-flex justify-content-center align-items-center flex-column\">\n <div class=\"payment-header mb-3 w-100\">\n <h1 style=\"font-size:24px;font-weight: 600;\">Booking Summary</h1>\n <p class=\"payment-subtitle mb-0\">Review your booking before confirming</p>\n </div>\n\n <div class=\"booking-summary-card\" [ngClass]=\"{'w-100' : screenWidth < 475,'w-50':screenWidth > 475}\">\n <div *ngFor=\"let line of resolvedLines; let i = index\">\n <h2 class=\"summary-title\" *ngIf=\"resolvedLines.length > 1\">Line {{i + 1}}</h2>\n <div class=\"summary-row\" *ngIf=\"line.services.length\">\n <div class=\"summary-label\">Service(s)</div>\n <div class=\"summary-value\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></div>\n </div>\n <div class=\"summary-row\" *ngIf=\"line.staffName || line.selectedStaffName\">\n <div class=\"summary-label\">Professional</div>\n <div class=\"summary-value\">{{line.staffName || line.selectedStaffName}}</div>\n </div>\n <div class=\"summary-row\" *ngIf=\"selectedMode === 'STORE_VISIT'\">\n <div class=\"summary-label\">Location</div>\n <div class=\"summary-value\">{{selectedLocation?.storeName ?? 'N/A'}}</div>\n </div>\n <div class=\"summary-row\">\n <div class=\"summary-label\">Date & Time</div>\n <div class=\"summary-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</div>\n </div>\n </div>\n\n <div *ngIf=\"productCartItems.length > 0\">\n <h2 class=\"summary-title\">Products</h2>\n <div class=\"summary-row\" *ngFor=\"let p of productCartItems\">\n <div class=\"summary-label\">{{p.itemName}} x{{p.quantity}}</div>\n <div class=\"summary-value\"><span class=\"currency-symbol\">\u20B9</span>{{(p.sellingPrice ?? p.price ?? 0) * (p.quantity ?? 1)}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusTemplate>\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book you appointment. Please\n try again later'}}\n </p>\n\n <!-- Video Call link, when already present on the confirmed group (a paid Video Call's\n link only appears once payment verification completes, handled elsewhere - see\n verify-payment.component.ts, not this screen). -->\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && selectedMode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\" *ngFor=\"let line of resolvedLines\">\n <span class=\"detail-label\">{{line.services.length ? (line.services[0].name) : 'Products'}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <ng-container *ngIf=\"!isAdminContext; else adminDoneActions\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </ng-container>\n <ng-template #adminDoneActions>\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToAppointmentsList()\">Back to Appointments List</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"bookAnother()\">Book Another</button>\n </ng-template>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.date-picker-container{border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;display:flex;align-items:center;justify-content:space-between;transition:var(--transition-smooth);background-color:var(--slate-50);cursor:pointer}.date-picker-container:hover{border-color:var(--slate-400);background-color:#fff}.date-input{font-size:.95rem;font-weight:600;color:var(--slate-800)!important;background:transparent;border:none;outline:none;cursor:pointer;width:100%}.date-picker-container mat-icon{color:var(--color-primary)!important;font-size:20px!important;width:20px!important;height:20px!important}.datepicker-popover{position:absolute;z-index:1000;margin-top:4px;border-radius:var(--border-radius-lg);overflow:hidden;box-shadow:var(--shadow-xl);background:#fff;border:1px solid var(--slate-200);width:320px}::ng-deep .datepicker-calendar{border-radius:var(--border-radius-lg)!important;width:100%!important}::ng-deep .mat-calendar-header{background:var(--color-accent-gradient)!important;color:#fff!important;padding:.5rem!important}::ng-deep .mat-calendar-content{padding:8px!important}::ng-deep .mat-calendar-controls{margin:0!important}::ng-deep .mat-calendar-period-button{color:#fff!important;font-weight:700!important;font-size:1rem!important}::ng-deep .mat-calendar-arrow{fill:#fff!important}::ng-deep .mat-calendar-previous-button,::ng-deep .mat-calendar-next-button{color:#fff!important}::ng-deep .mat-calendar-body-cell{font-size:13px!important}::ng-deep .mat-calendar-body-cell-content{font-weight:600!important;color:var(--slate-800)!important;border-radius:8px!important}::ng-deep .mat-calendar-body-selected{background:var(--color-accent-gradient)!important;color:#fff!important;box-shadow:0 4px 10px #23086033!important}::ng-deep .mat-calendar-body-today:not(.mat-calendar-body-selected){border:2px solid var(--color-primary)!important;color:var(--color-primary)!important}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.datepicker-popover{width:100%;left:0}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}h1{font-size:24px!important;font-weight:600!important}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}\n"] }]
|
|
25982
|
+
args: [{ selector: 'simpo-appointment-booking', standalone: true, imports: [CdkDragPlaceholder, CommonModule, MatIcon, MatFormFieldModule, MatDatepickerModule, FormsModule, MatNativeDateModule, MatInputModule, MatDialogModule, LettersOnlyDirective, NumbersOnlyDirective, ToastModule, HoverDirective, HoverElementsComponent, BackgroundDirective], providers: [MessageService], template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\" simpoHover (hovering)=\"showEditTabs($event)\"\n [simpoBackground]=\"backgroundInfo\" [style.--color-accent-gradient]=\"accentColor\">\n <div [ngClass]=\"{'hover_effect': edit}\" *ngIf=\"showEditors\">\n <simpo-hover-elements [data]=\"data\" [index]=\"index\" [editOptions]=\"edit\"></simpo-hover-elements>\n </div>\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"back-btn d-flex justify-content-center align-items-center cursor-pointer gap-2 mb-3\"\n (click)=\"goBack()\">\n <mat-icon>keyboard_backspace</mat-icon><span *ngIf=\"screenWidth > 475\">Back to Home</span>\n </div>\n <div class=\"header-title\">\n <h1>Book New Appointment</h1>\n <p>{{businessName ?? \"N/A\" }}</p>\n </div>\n </div>\n\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width]=\"barWidth + '%'\"></div>\n </div>\n </div>\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <ng-container *ngIf=\"selectedTab === 'modeSelection'\">\n <ng-container *ngTemplateOutlet=\"modeSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'serviceListing'\">\n <ng-container *ngIf=\"!skeletonLoader\">\n <ng-container *ngTemplateOutlet=\"serviceListing\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'locationListing'\">\n <ng-container *ngTemplateOutlet=\"locationListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'staffListing'\">\n <ng-container *ngTemplateOutlet=\"staffListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'dateSelection'\">\n <ng-container *ngTemplateOutlet=\"dateSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='contactDetails'\">\n <ng-container *ngTemplateOutlet=\"contactDetails\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='paymentTab'\">\n <ng-container *ngTemplateOutlet=\"paymentTab\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='statusTemplate'\">\n <ng-container *ngTemplateOutlet=\"statusTemplate\"></ng-container>\n </ng-container>\n </div>\n <div class=\"main_footer d-flex justify-content-center align-items-center\"\n *ngIf=\"selectedTab!=='statusTemplate' && selectedTab!=='modeSelection'\">\n <div class=\"footer-buttons\"\n [ngStyle]=\"{'justify-content': selectedTab != 'serviceListing' ? 'space-between' : 'end'}\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"previousStep()\"\n *ngIf=\"selectedTab != 'serviceListing'\">Back</span>\n <button class=\"continue-btn\" [disabled]=\"!activeButton\" (click)=\"nextStep()\"\n *ngIf=\"selectedTab!='paymentTab'\">{{!loader ? 'Continue' : 'Loading...'}}</button>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center\"\n *ngIf=\"selectedTab==='paymentTab'\" (click)=\"confirmBooking()\" [disabled]=\"isProcessing\"\n [ngClass]=\"{'pay-now-btn' : bookingGroup?.totalCollectedAtBooking > 0 || !bookingGroup,'complete_booking' : bookingGroup && !bookingGroup?.totalCollectedAtBooking}\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n\n<ng-template #modeSelection>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>How would you like this?</h2>\n <p>Choose how you'd like to be served</p>\n <div class=\"services-grid\">\n <div class=\"service-card\" (click)=\"selectMode('STORE_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>storefront</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Visit our Store</div>\n </div>\n </div>\n <div class=\"service-description\">Come to us at one of our locations</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('HOME_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>home</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">We come to you</div>\n </div>\n </div>\n <div class=\"service-description\">A professional visits your address</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('VIDEO_CALL')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>videocam</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Video consultation</div>\n </div>\n </div>\n <div class=\"service-description\">Connect over a video call</div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #serviceListing>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>Select a Service</h2>\n <p>Choose the service(s) you'd like to book<span *ngIf=\"cartServices.length > 0\"> \u2014 {{cartServices.length}} selected</span></p>\n <p *ngIf=\"productCartItems.length > 0\" class=\"cart-hint\">{{productCartItems.length}} product(s) already in your cart \u2014 you can continue without picking a service.</p>\n\n <div class=\"services-grid\">\n <ng-container *ngFor=\"let service of serviceData\">\n <div class=\"\" (click)=\"selectService(service)\"\n [ngClass]=\"{ 'service-card-selected' : service?.selected, 'service-card': !service?.selected }\">\n <div class=\" service-header\">\n <div class=\"service-icon\"><mat-icon>person_outline</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">{{service?.name ? service?.name : 'N/A'}}</div>\n </div>\n <div>\n <div class=\"service-price\">\u20B9{{service?.priceDetails?.price ?\n service?.priceDetails?.price : 'N/A' }}</div>\n <div class=\"service-duration\">{{service?.duration ? service?.duration : 'N/A'}} min\n </div>\n </div>\n </div>\n <div class=\"service-description\" *ngIf=\"service?.description\">\n {{service?.description ? service?.description : 'N/A'}}\n </div>\n <div class=\"home-visit\" *ngIf=\"selectedMode === 'STORE_VISIT' && service?.homeAppointmentAvailable\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/982126c1758628863129furniture_16406103.png\">Home\n Visit Available</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #locationListing>\n <div class=\"location_section\">\n <div class=\"header flex-column align-items-start\">\n <h1>Choose Location</h1>\n <p>Select where you'd like to receive the service</p>\n </div>\n\n <div class=\"location-list\">\n <ng-container *ngFor=\"let location of locationData\">\n <div (click)=\"selectLocation(location)\"\n [ngClass]=\"{ 'location-card-selected' : location?.selected, 'location-card': !location?.selected }\">\n <div class=\"location-content\">\n <div class=\"location-info\">\n <div class=\"location-icon\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/427226c1758629157758store_3171510.png\">\n </div>\n <div class=\"location-details\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <h3>{{location?.storeName ? location?.storeName : 'N/A'}}</h3>\n </div>\n <p>{{location?.addressDetails?.addressLine}}, {{location?.addressDetails?.city}},\n {{location?.addressDetails?.state}} {{location?.pincode}}</p>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #staffListing>\n <div class=\"w-60 overflow-hidden staff-listing\">\n <div class=\"d-flex w-100 h-100\">\n <div class=\"w-100\">\n <div class=\"staff-header mb-3\">\n <h1>Select Staff Member</h1>\n <p class=\"staff-subtitle mb-0\">Choose your preferred professional</p>\n </div>\n\n <div class=\"search-container mb-4\">\n <div class=\"search-input-wrapper d-flex align-items-center\">\n <mat-icon class=\"search-icon me-2\">search</mat-icon>\n <input type=\"text\" class=\"search-input border-0 flex-grow-1\" placeholder=\"Search staff member by name...\" [(ngModel)]=\"staffSearchQuery\">\n <mat-icon class=\"clear-icon cursor-pointer ms-2\" *ngIf=\"staffSearchQuery\" (click)=\"staffSearchQuery = ''\">close</mat-icon>\n </div>\n </div>\n\n <!-- Pure product-only line: one flat staff list, same as the old single-service flow -->\n <div class=\"staff-list\" *ngIf=\"cartServices.length === 0\">\n <ng-container *ngFor=\"let staff of filteredStaff\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForProductOnlyLine(staff)\"\n [ngClass]=\"{ 'staff-card-selected' : staff?.selected, 'staff-card': !staff?.selected }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.staffName.slice(0,2).toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.staffName ? staff?.staffName : 'N/A') | titlecase}}</h3>\n <p class=\"staff-specialty\">{{(businessName && businessName !== 'N/A') ? businessName : 'Booking Specialist'}}</p>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"staff?.selected\">\n <mat-icon *ngIf=\"staff?.selected\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Bundled cart: one pool per line that resolution couldn't collapse to a single provider -->\n <ng-container *ngIf=\"cartServices.length > 0\">\n <div class=\"staff-line-group mb-4\" *ngFor=\"let line of resolvedLines\">\n <ng-container *ngIf=\"line.candidateStaffPool?.length\">\n <h4 class=\"mb-2\">For {{line.services.length}} service(s): {{ (line.services | slice:0:3).length ? '' : '' }}<span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></h4>\n <div class=\"staff-list mb-3\">\n <ng-container *ngFor=\"let staff of line.candidateStaffPool\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForLine(line, staff)\"\n [ngClass]=\"{ 'staff-card-selected' : line.selectedStaffId === staff.id, 'staff-card': line.selectedStaffId !== staff.id }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.name?.slice(0,2)?.toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.name ? staff?.name : 'N/A') | titlecase}}</h3>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"line.selectedStaffId === staff.id\">\n <mat-icon *ngIf=\"line.selectedStaffId === staff.id\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateSelection>\n <div class=\"w-60 date_section\">\n <div class=\"row justify-content-center h-100\">\n <div class=\"col-12 h-100\">\n <div class=\"datetime-header mb-2\">\n <h1>Select Date & Time</h1>\n <p class=\"datetime-subtitle mb-0\">Choose when you'd like your appointment</p>\n </div>\n\n <div class=\"d-flex gap-4 main_container\">\n <div [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\">\n <div class=\"section-card card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Select Date</h3>\n\n <div class=\"date-picker-container d-flex align-items-center justify-content-between\"\n (click)=\"$event.stopPropagation()\">\n <input type=\"text\" class=\"date-input border-0 rounded-2\" placeholder=\"dd-mm-yyyy\"\n [value]=\"selectedDateStr\" readonly (click)=\"toggleCalendar($event)\">\n\n <mat-icon class=\"ms-2\" (click)=\"toggleCalendar($event)\">calendar_today</mat-icon>\n </div>\n <div class=\"position-relative\" (click)=\"$event.stopPropagation()\">\n <div class=\"datepicker-popover\" *ngIf=\"showCalendar\">\n <mat-calendar [(selected)]=\"selectedDate\" [dateFilter]=\"dateFilter\"\n (selectedChange)=\"onDateSelected($event)\" class=\"datepicker-calendar\">\n </mat-calendar>\n </div>\n </div>\n </div>\n </div>\n\n <!-- One slot-picker per resolved line, side by side when there's more than one (design doc \u00A73b) -->\n <div class=\"time_selection\" [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\" *ngIf=\"resolvedLines.length <= 1\">\n <div class=\"section-card card h-100 rounded-3 p-4\">\n <h3 class=\"section-title\">Available Times</h3>\n <div class=\"row g-2 mb-4 overflow-scroll\">\n <ng-container *ngIf=\"!skeletonLoader && resolvedLines[0]\">\n <div class=\"col-4\" *ngFor=\"let time of resolvedLines[0].slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(resolvedLines[0], time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Multi-line case: each line gets its own full-width card with a staff header -->\n <div class=\"d-flex gap-4 main_container flex-wrap\" *ngIf=\"resolvedLines.length > 1\">\n <div class=\"w-100\" *ngFor=\"let line of resolvedLines\">\n <div class=\"section-card card rounded-3 p-4\">\n <h3 class=\"section-title\">Professional: {{line.staffName || line.selectedStaffName}}</h3>\n <p class=\"mb-2\" *ngIf=\"line.services.length\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></p>\n <div class=\"row g-2 mb-2 overflow-scroll\">\n <ng-container *ngIf=\"!line.slotsLoading\">\n <div class=\"col-4\" *ngFor=\"let time of line.slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(line, time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #contactDetails>\n <div class=\"w-60 contact_section\">\n <div class=\"contact-header mb-2\">\n <h1>Contact Details</h1>\n <p class=\"contact-subtitle mb-0\">Provide your contact information</p>\n </div>\n\n <div class=\"d-flex gap-3 details_container flex-column w-100\">\n <div class=\"d-flex gap-4\">\n <div [ngClass]=\"{'w-50' : selectedMode === 'HOME_VISIT', 'w-100' : selectedMode !== 'HOME_VISIT'}\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Personal Information</h3>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Full Name\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"text\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.name\"\n (ngModelChange)=\"checkRequiredValues()\" simpoLettersOnly>\n </div>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Email Address\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"email\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.email\"\n (ngModelChange)=\"checkRequiredValues()\"\n pattern=\"^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$\" #emailField=\"ngModel\"\n name=\"email\" required>\n </div>\n\n <div class=\"mb-0\">\n <label class=\"form-label d-flex align-items-center\">\n Phone Number\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"tel\" class=\"form-control rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.phoneNumber\"\n (ngModelChange)=\"checkRequiredValues()\" simpoNumbersOnly\n [ngClass]=\"{'mobile_number' : appointmentPayload.customerDetail.phoneNumber.length != 10}\">\n </div>\n </div>\n </div>\n <!-- Home Visit address. Customer context: same saved-address flow as\n checkout/BookAppointmentComponent. Admin context (isAdminBooking): no\n logged-in customer account to read a saved address book from, so staff type\n the address manually instead. -->\n <div class=\"w-50\" *ngIf=\"selectedMode === 'HOME_VISIT'\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Home Visit Details</h3>\n\n <ng-container *ngIf=\"!isAdminBooking; else manualHomeVisitAddress\">\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n </ng-container>\n\n <ng-template #manualHomeVisitAddress>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Name</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.receiverName\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Phone</label>\n <input type=\"tel\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.receiverPhone\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 1</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine1\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 2 (optional)</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine2\">\n </div>\n <div class=\"d-flex gap-2 mb-3\">\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">City</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.city\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">State</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.state\">\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Pincode</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.zipCode\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n </ng-template>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Special Instructions</label>\n <textarea class=\"form-control form-textarea rounded-2\"\n placeholder=\"Any special instructions for the professional (optional)\"\n [(ngModel)]=\"instructions\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"policies-container\"\n *ngIf=\"cartServices[0]?.cancellationPolicy?.length > 0 || cartServices[0]?.reschedulePolicy?.length\">\n <h2 class=\"policies-title\">Policies & Terms</h2>\n\n <div class=\"policy-items-container d-flex flex-column gap-3\">\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showCancellationPolicy = !showCancellationPolicy\">\n <h3 class=\"policy-title\">Cancellation Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showCancellationPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showCancellationPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showCancellationPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.cancellationPolicy\">•\n {{policy}}</span>\n </div>\n\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showReducingPolicy = !showReducingPolicy\">\n <h3 class=\"policy-title\">Rescheduling Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showReducingPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showReducingPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showReducingPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.reschedulePolicy\">• {{policy}}</span>\n </div>\n </div>\n\n <div class=\"acceptance-section\">\n <input type=\"checkbox\" class=\"custom-checkbox\" [(ngModel)]=\"termsAndConditions\"\n (ngModelChange)=\"checkRequiredValues()\">\n <p class=\"acceptance-text\" style=\"margin-bottom:0px !important\">\n I understand and accept the cancellation & rescheduling policies.\n </p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #paymentTab>\n <div class=\"w-60 payment_section\">\n <div class=\"w-100 h-100\">\n <div class=\"w-100 d-flex justify-content-center align-items-center flex-column\">\n <div class=\"payment-header mb-3 w-100\">\n <h1 style=\"font-size:24px;font-weight: 600;\">Booking Summary</h1>\n <p class=\"payment-subtitle mb-0\">Review your booking before confirming</p>\n </div>\n\n <div class=\"booking-summary-card\" [ngClass]=\"{'w-100' : screenWidth < 475,'w-50':screenWidth > 475}\">\n <div *ngFor=\"let line of resolvedLines; let i = index\">\n <h2 class=\"summary-title\" *ngIf=\"resolvedLines.length > 1\">Line {{i + 1}}</h2>\n <div class=\"summary-row\" *ngIf=\"line.services.length\">\n <div class=\"summary-label\">Service(s)</div>\n <div class=\"summary-value\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></div>\n </div>\n <div class=\"summary-row\" *ngIf=\"line.staffName || line.selectedStaffName\">\n <div class=\"summary-label\">Professional</div>\n <div class=\"summary-value\">{{line.staffName || line.selectedStaffName}}</div>\n </div>\n <div class=\"summary-row\" *ngIf=\"selectedMode === 'STORE_VISIT'\">\n <div class=\"summary-label\">Location</div>\n <div class=\"summary-value\">{{selectedLocation?.storeName ?? 'N/A'}}</div>\n </div>\n <div class=\"summary-row\">\n <div class=\"summary-label\">Date & Time</div>\n <div class=\"summary-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</div>\n </div>\n </div>\n\n <div *ngIf=\"productCartItems.length > 0\">\n <h2 class=\"summary-title\">Products</h2>\n <div class=\"summary-row\" *ngFor=\"let p of productCartItems\">\n <div class=\"summary-label\">{{p.itemName}} x{{p.quantity}}</div>\n <div class=\"summary-value\"><span class=\"currency-symbol\">\u20B9</span>{{(p.sellingPrice ?? p.price ?? 0) * (p.quantity ?? 1)}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusTemplate>\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book you appointment. Please\n try again later'}}\n </p>\n\n <!-- Video Call link, when already present on the confirmed group (a paid Video Call's\n link only appears once payment verification completes, handled elsewhere - see\n verify-payment.component.ts, not this screen). -->\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && selectedMode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\" *ngFor=\"let line of resolvedLines\">\n <span class=\"detail-label\">{{line.services.length ? (line.services[0].name) : 'Products'}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <ng-container *ngIf=\"!isAdminContext; else adminDoneActions\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </ng-container>\n <ng-template #adminDoneActions>\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToAppointmentsList()\">Back to Appointments List</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"bookAnother()\">Book Another</button>\n </ng-template>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.hover_effect{position:absolute;width:100%;top:0;left:0;height:100%}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.date-picker-container{border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;display:flex;align-items:center;justify-content:space-between;transition:var(--transition-smooth);background-color:var(--slate-50);cursor:pointer}.date-picker-container:hover{border-color:var(--slate-400);background-color:#fff}.date-input{font-size:.95rem;font-weight:600;color:var(--slate-800)!important;background:transparent;border:none;outline:none;cursor:pointer;width:100%}.date-picker-container mat-icon{color:var(--color-primary)!important;font-size:20px!important;width:20px!important;height:20px!important}.datepicker-popover{position:absolute;z-index:1000;margin-top:4px;border-radius:var(--border-radius-lg);overflow:hidden;box-shadow:var(--shadow-xl);background:#fff;border:1px solid var(--slate-200);width:320px}::ng-deep .datepicker-calendar{border-radius:var(--border-radius-lg)!important;width:100%!important}::ng-deep .mat-calendar-header{background:var(--color-accent-gradient)!important;color:#fff!important;padding:.5rem!important}::ng-deep .mat-calendar-content{padding:8px!important}::ng-deep .mat-calendar-controls{margin:0!important}::ng-deep .mat-calendar-period-button{color:#fff!important;font-weight:700!important;font-size:1rem!important}::ng-deep .mat-calendar-arrow{fill:#fff!important}::ng-deep .mat-calendar-previous-button,::ng-deep .mat-calendar-next-button{color:#fff!important}::ng-deep .mat-calendar-body-cell{font-size:13px!important}::ng-deep .mat-calendar-body-cell-content{font-weight:600!important;color:var(--slate-800)!important;border-radius:8px!important}::ng-deep .mat-calendar-body-selected{background:var(--color-accent-gradient)!important;color:#fff!important;box-shadow:0 4px 10px #23086033!important}::ng-deep .mat-calendar-body-today:not(.mat-calendar-body-selected){border:2px solid var(--color-primary)!important;color:var(--color-primary)!important}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.datepicker-popover{width:100%;left:0}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}h1{font-size:24px!important;font-weight:600!important}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}\n"] }]
|
|
25959
25983
|
}], ctorParameters: () => [{ type: RestService }, { type: EventsService }, { type: i2$2.Router }, { type: i6$1.MessageService }, { type: BookingProductCartService }, { type: StorageServiceService }, { type: i3$2.MatDialog }, { type: i3$2.MatDialogRef, decorators: [{
|
|
25960
25984
|
type: Optional
|
|
25961
25985
|
}] }], propDecorators: { data: [{
|
|
@@ -25994,6 +26018,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
25994
26018
|
* wizard (service bookings) is unaffected and still opens as a dialog.
|
|
25995
26019
|
*/
|
|
25996
26020
|
class BookAppointmentComponent extends BaseSection {
|
|
26021
|
+
/** Editor-configurable background - falls back to undefined (letting the component's own CSS
|
|
26022
|
+
* defaults show through unchanged) for existing pages saved before this section supported
|
|
26023
|
+
* custom colors. */
|
|
26024
|
+
get backgroundInfo() {
|
|
26025
|
+
return this.data?.styles?.background;
|
|
26026
|
+
}
|
|
26027
|
+
/** Overrides this component's own --color-accent-gradient CSS variable (scoped to its :host,
|
|
26028
|
+
* see book-appointment.component.css) when a business has picked a custom accent color - null
|
|
26029
|
+
* when unset, so the [style.--color-accent-gradient] binding removes the inline override
|
|
26030
|
+
* entirely and the CSS default shows through, rather than forcing an empty value. */
|
|
26031
|
+
get accentColor() {
|
|
26032
|
+
return this.data?.styles?.background?.accentColor || null;
|
|
26033
|
+
}
|
|
25997
26034
|
constructor(route, router, restService, _eventService, messageService, storageService, bookingProductCartService, matDialog) {
|
|
25998
26035
|
super();
|
|
25999
26036
|
this.route = route;
|
|
@@ -26307,11 +26344,11 @@ class BookAppointmentComponent extends BaseSection {
|
|
|
26307
26344
|
});
|
|
26308
26345
|
}
|
|
26309
26346
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BookAppointmentComponent, deps: [{ token: i2$2.ActivatedRoute }, { token: i2$2.Router }, { token: RestService }, { token: EventsService }, { token: i6$1.MessageService }, { token: StorageServiceService }, { token: BookingProductCartService }, { token: i3$2.MatDialog }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26310
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: BookAppointmentComponent, isStandalone: true, selector: "simpo-book-appointment", inputs: { data: "data", index: "index", edit: "edit", delete: "delete", customClass: "customClass" }, providers: [MessageService], usesInheritance: true, ngImport: i0, template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\">\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"header-title\">\n <h1>{{bannerTitle}}</h1>\n <p>{{bannerDesc}}</p>\n </div>\n </div>\n </div>\n\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <div class=\"wiz-container\">\n\n <div class=\"step-indicator\" *ngIf=\"step !== 'done'\">\n <div class=\"step-dot\" [class.active]=\"true\">1</div>\n <div class=\"step-label\" [class.active]=\"step==='form'\">Date, time & details</div>\n <div class=\"step-divider\"></div>\n <div class=\"step-dot\" [class.active]=\"step==='review'\">2</div>\n <div class=\"step-label\" [class.active]=\"step==='review'\">Review & confirm</div>\n </div>\n\n <ng-container *ngIf=\"step === 'form'\">\n <div class=\"single-grid\">\n <div class=\"single-left\">\n\n <div class=\"section-card card\">\n <div class=\"week-header\">\n <div>\n <h3 class=\"section-title mb-0\">Select a Date</h3>\n <p class=\"subtitle mb-0\">{{weekRangeLabel}}</p>\n </div>\n <div class=\"week-arrows\">\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"prevWeek()\" [disabled]=\"weekOffset <= 0\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"nextWeek()\" [disabled]=\"weekOffset >= maxWeekOffset\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"week-strip\">\n <button type=\"button\" class=\"week-day\" *ngFor=\"let d of weekDays\" [class.selected]=\"d.selected\"\n (click)=\"pickDay(d)\">\n <div class=\"week-day-dow\">{{d.dow}}</div>\n <div class=\"week-day-num\">{{d.num}}</div>\n </button>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title mb-0\">Select a Time</h3>\n <p class=\"subtitle\" *ngIf=\"selectedDateStr\">Available slots for {{selectedDateStr}}</p>\n <p class=\"subtitle mb-0\" *ngIf=\"!selectedDateStr\">Pick a date to see available times.</p>\n <div class=\"row g-2 overflow-scroll\" *ngIf=\"selectedDateStr\">\n <ng-container *ngIf=\"!slotsLoading; else slotsLoadingTpl\">\n <div class=\"col-4\" *ngFor=\"let time of slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlot(time)\">{{time?.value}}</div>\n </div>\n <p class=\"mb-0\" *ngIf=\"slots.length === 0\">No slots available for this date.</p>\n </ng-container>\n <ng-template #slotsLoadingTpl>\n <p class=\"mb-0\">Loading available times...</p>\n </ng-template>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title\">Booking Details</h3>\n <div class=\"booking-for-line\">\n Booking for <strong>{{userDetails?.contact?.name}}</strong>\n <ng-container *ngIf=\"userDetails?.contact?.mobile\"> \u00B7 {{userDetails?.contact?.mobile}}</ng-container>\n <ng-container *ngIf=\"userDetails?.contact?.email\"> \u00B7 {{userDetails?.contact?.email}}</ng-container>\n </div>\n\n <ng-container *ngIf=\"mode === 'HOME_VISIT'\">\n <p class=\"policies-title mt-3 mb-2\" style=\"font-size:1rem;\">Shipping Address</p>\n\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Instructions (optional)</label>\n <textarea class=\"form-control form-textarea rounded-2\" [(ngModel)]=\"instructions\"></textarea>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"single-right section-card card\">\n <h3 class=\"section-title\">Your Shortlisted Designs</h3>\n <div class=\"design-row\" *ngFor=\"let it of productCartItems\">\n <div class=\"design-thumb\"></div>\n <div class=\"design-info\">\n <div class=\"design-name\">{{it.itemName}}</div>\n <div class=\"design-price\">\u20B9{{(it.sellingPrice ?? it.price ?? 0) * (it.quantity ?? 1)}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"add-more-btn\" (click)=\"goToListing()\">+ Add More Designs</button>\n\n <div class=\"summary-divider\"></div>\n\n <div class=\"summary-line\">\n <div class=\"summary-label\">Service:</div>\n <div class=\"free-label\">FREE</div>\n </div>\n <div class=\"summary-line\" *ngIf=\"mode === 'HOME_VISIT' && homeVisitCharge > 0\">\n <div class=\"summary-label\">Home visit charge</div>\n <div class=\"summary-value\">\u20B9{{homeVisitCharge}}</div>\n </div>\n\n <button class=\"continue-btn w-100 mt-2\" [disabled]=\"invalid()\" (click)=\"goToReview()\">Review Booking</button>\n <p class=\"footnote\">You will review everything on the next screen before it is confirmed.</p>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'review'\">\n <div class=\"review-card card\">\n <div class=\"review-header\">Review your booking</div>\n <div class=\"review-row\" *ngFor=\"let rc of reviewRows\">\n <div class=\"review-k\">{{rc.k}}</div>\n <div class=\"review-v\">{{rc.v}}</div>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'done'\">\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book your appointment. Please\n try again later'}}\n </p>\n\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && mode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\">\n <span class=\"detail-label\">{{productCartItems.length ? 'Products' : (mode === 'HOME_VISIT' ? 'Home Visit' : 'Video Call')}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"main_footer d-flex justify-content-center align-items-center\" *ngIf=\"step === 'review'\">\n <div class=\"footer-buttons\" style=\"justify-content:space-between\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"backToForm()\">Back</span>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center complete_booking\"\n (click)=\"confirmBooking()\" [disabled]=\"isProcessing\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}h1{font-size:24px!important;font-weight:600!important}.wiz-container{width:100%;max-width:1120px}.step-indicator{display:flex;align-items:center;gap:10px;padding-bottom:18px}.step-dot{width:26px;height:26px;border-radius:50%;background:var(--slate-200);color:var(--slate-500)!important;font-size:.8rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.step-dot.active{background:var(--color-accent-gradient);color:#fff!important}.step-label{font-size:12.5px;color:var(--slate-400)!important;font-weight:600}.step-label.active{color:var(--slate-900)!important}.step-divider{width:40px;height:1px;background:var(--slate-200)}.single-grid{display:grid;grid-template-columns:1fr 360px;gap:1.5rem;align-items:start}.single-left{display:flex;flex-direction:column;gap:1.5rem}.single-right{align-self:flex-start;position:sticky;top:10px}.week-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:14px}.week-arrows{display:flex;gap:8px}.week-arrow-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--slate-200);background:#fff;color:var(--slate-700)!important;cursor:pointer;display:flex;align-items:center;justify-content:center}.week-arrow-btn:disabled{color:var(--slate-300)!important;cursor:not-allowed}.week-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:10px}.week-day{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem .25rem;cursor:pointer;transition:var(--transition-smooth);text-align:center}.week-day:hover{border-color:var(--slate-400)}.week-day.selected{background:var(--color-accent-gradient);border-color:transparent}.week-day.selected .week-day-dow,.week-day.selected .week-day-num{color:#fff!important}.week-day-dow{font-size:.75rem;font-weight:600;color:var(--slate-500)!important;text-transform:uppercase}.week-day-num{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-top:2px}.booking-for-line{font-size:.9rem;color:var(--slate-600)!important;padding:.85rem 1rem;background:var(--slate-50);border-radius:var(--border-radius-md);margin-bottom:.5rem}.booking-for-line strong{color:var(--slate-900)!important}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.design-row{display:flex;gap:13px;align-items:center;padding-bottom:1rem}.design-thumb{width:56px;height:56px;border-radius:8px;background:var(--slate-100);flex:none}.design-info{flex:1}.design-name{font-size:13.5px;color:var(--slate-900)!important;line-height:1.35}.design-price{font-size:13.5px;font-weight:600;color:var(--slate-900)!important;margin-top:3px}.add-more-btn{width:100%;height:44px;border:1.5px dashed var(--slate-300);border-radius:8px;background:none;color:var(--color-primary)!important;font-size:13px;font-weight:600;cursor:pointer;margin-bottom:1rem}.summary-divider{height:1px;background:var(--slate-100);margin-bottom:1rem}.summary-line{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.free-label{font-size:13.5px;font-weight:600;color:var(--color-success)!important}.footnote{font-size:11.5px;line-height:1.5;color:var(--slate-500)!important;text-align:center;margin:.75rem 0 0}.review-card{max-width:560px;margin:0 auto;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);overflow:hidden}.review-header{padding:14px 18px;background:var(--slate-50);border-bottom:1px solid var(--slate-100);font-size:14.5px;font-weight:700;color:var(--slate-900)!important}.review-row{display:flex;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slate-100);font-size:13.5px}.review-row:last-child{border-bottom:none}.review-k{color:var(--slate-500)!important;flex-shrink:0}.review-v{color:var(--slate-900)!important;font-weight:500;text-align:right}@media screen and (max-width: 475px){.single-grid{grid-template-columns:1fr}.single-right{position:static}.week-strip{gap:6px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }] }); }
|
|
26347
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: BookAppointmentComponent, isStandalone: true, selector: "simpo-book-appointment", inputs: { data: "data", index: "index", edit: "edit", delete: "delete", customClass: "customClass" }, providers: [MessageService], usesInheritance: true, ngImport: i0, template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\" simpoHover (hovering)=\"showEditTabs($event)\"\n [simpoBackground]=\"backgroundInfo\" [style.--color-accent-gradient]=\"accentColor\">\n <div [ngClass]=\"{'hover_effect': edit}\" *ngIf=\"showEditors\">\n <simpo-hover-elements [data]=\"data\" [index]=\"index\" [editOptions]=\"edit\"></simpo-hover-elements>\n </div>\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"header-title\">\n <h1>{{bannerTitle}}</h1>\n <p>{{bannerDesc}}</p>\n </div>\n </div>\n </div>\n\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <div class=\"wiz-container\">\n\n <div class=\"step-indicator\" *ngIf=\"step !== 'done'\">\n <div class=\"step-dot\" [class.active]=\"true\">1</div>\n <div class=\"step-label\" [class.active]=\"step==='form'\">Date, time & details</div>\n <div class=\"step-divider\"></div>\n <div class=\"step-dot\" [class.active]=\"step==='review'\">2</div>\n <div class=\"step-label\" [class.active]=\"step==='review'\">Review & confirm</div>\n </div>\n\n <ng-container *ngIf=\"step === 'form'\">\n <div class=\"single-grid\">\n <div class=\"single-left\">\n\n <div class=\"section-card card\">\n <div class=\"week-header\">\n <div>\n <h3 class=\"section-title mb-0\">Select a Date</h3>\n <p class=\"subtitle mb-0\">{{weekRangeLabel}}</p>\n </div>\n <div class=\"week-arrows\">\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"prevWeek()\" [disabled]=\"weekOffset <= 0\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"nextWeek()\" [disabled]=\"weekOffset >= maxWeekOffset\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"week-strip\">\n <button type=\"button\" class=\"week-day\" *ngFor=\"let d of weekDays\" [class.selected]=\"d.selected\"\n (click)=\"pickDay(d)\">\n <div class=\"week-day-dow\">{{d.dow}}</div>\n <div class=\"week-day-num\">{{d.num}}</div>\n </button>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title mb-0\">Select a Time</h3>\n <p class=\"subtitle\" *ngIf=\"selectedDateStr\">Available slots for {{selectedDateStr}}</p>\n <p class=\"subtitle mb-0\" *ngIf=\"!selectedDateStr\">Pick a date to see available times.</p>\n <div class=\"row g-2 overflow-scroll\" *ngIf=\"selectedDateStr\">\n <ng-container *ngIf=\"!slotsLoading; else slotsLoadingTpl\">\n <div class=\"col-4\" *ngFor=\"let time of slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlot(time)\">{{time?.value}}</div>\n </div>\n <p class=\"mb-0\" *ngIf=\"slots.length === 0\">No slots available for this date.</p>\n </ng-container>\n <ng-template #slotsLoadingTpl>\n <p class=\"mb-0\">Loading available times...</p>\n </ng-template>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title\">Booking Details</h3>\n <div class=\"booking-for-line\">\n Booking for <strong>{{userDetails?.contact?.name}}</strong>\n <ng-container *ngIf=\"userDetails?.contact?.mobile\"> \u00B7 {{userDetails?.contact?.mobile}}</ng-container>\n <ng-container *ngIf=\"userDetails?.contact?.email\"> \u00B7 {{userDetails?.contact?.email}}</ng-container>\n </div>\n\n <ng-container *ngIf=\"mode === 'HOME_VISIT'\">\n <p class=\"policies-title mt-3 mb-2\" style=\"font-size:1rem;\">Shipping Address</p>\n\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Instructions (optional)</label>\n <textarea class=\"form-control form-textarea rounded-2\" [(ngModel)]=\"instructions\"></textarea>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"single-right section-card card\">\n <h3 class=\"section-title\">Your Shortlisted Designs</h3>\n <div class=\"design-row\" *ngFor=\"let it of productCartItems\">\n <div class=\"design-thumb\"></div>\n <div class=\"design-info\">\n <div class=\"design-name\">{{it.itemName}}</div>\n <div class=\"design-price\">\u20B9{{(it.sellingPrice ?? it.price ?? 0) * (it.quantity ?? 1)}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"add-more-btn\" (click)=\"goToListing()\">+ Add More Designs</button>\n\n <div class=\"summary-divider\"></div>\n\n <div class=\"summary-line\" *ngIf=\"mode !== 'HOME_VISIT' || homeVisitCharge <= 0\">\n <div class=\"summary-label\">Service:</div>\n <div class=\"free-label\">FREE</div>\n </div>\n <div class=\"summary-line\" *ngIf=\"mode === 'HOME_VISIT' && homeVisitCharge > 0\">\n <div class=\"summary-label\">Home visit charge</div>\n <div class=\"summary-value\">\u20B9{{homeVisitCharge}}</div>\n </div>\n\n <button class=\"continue-btn w-100 mt-2\" [disabled]=\"invalid()\" (click)=\"goToReview()\">Review Booking</button>\n <p class=\"footnote\">You will review everything on the next screen before it is confirmed.</p>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'review'\">\n <div class=\"review-card card\">\n <div class=\"review-header\">Review your booking</div>\n <div class=\"review-row\" *ngFor=\"let rc of reviewRows\">\n <div class=\"review-k\">{{rc.k}}</div>\n <div class=\"review-v\">{{rc.v}}</div>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'done'\">\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book your appointment. Please\n try again later'}}\n </p>\n\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && mode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\">\n <span class=\"detail-label\">{{productCartItems.length ? 'Products' : (mode === 'HOME_VISIT' ? 'Home Visit' : 'Video Call')}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"main_footer d-flex justify-content-center align-items-center\" *ngIf=\"step === 'review'\">\n <div class=\"footer-buttons\" style=\"justify-content:space-between\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"backToForm()\">Back</span>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center complete_booking\"\n (click)=\"confirmBooking()\" [disabled]=\"isProcessing\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.hover_effect{position:absolute;width:100%;top:0;left:0;height:100%}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}h1{font-size:24px!important;font-weight:600!important}.wiz-container{width:100%;max-width:1120px}.step-indicator{display:flex;align-items:center;gap:10px;padding-bottom:18px}.step-dot{width:26px;height:26px;border-radius:50%;background:var(--slate-200);color:var(--slate-500)!important;font-size:.8rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.step-dot.active{background:var(--color-accent-gradient);color:#fff!important}.step-label{font-size:12.5px;color:var(--slate-400)!important;font-weight:600}.step-label.active{color:var(--slate-900)!important}.step-divider{width:40px;height:1px;background:var(--slate-200)}.single-grid{display:grid;grid-template-columns:1fr 360px;gap:1.5rem;align-items:start}.single-left{display:flex;flex-direction:column;gap:1.5rem}.single-right{align-self:flex-start;position:sticky;top:10px}.week-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:14px}.week-arrows{display:flex;gap:8px}.week-arrow-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--slate-200);background:#fff;color:var(--slate-700)!important;cursor:pointer;display:flex;align-items:center;justify-content:center}.week-arrow-btn:disabled{color:var(--slate-300)!important;cursor:not-allowed}.week-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:10px}.week-day{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem .25rem;cursor:pointer;transition:var(--transition-smooth);text-align:center}.week-day:hover{border-color:var(--slate-400)}.week-day.selected{background:var(--color-accent-gradient);border-color:transparent}.week-day.selected .week-day-dow,.week-day.selected .week-day-num{color:#fff!important}.week-day-dow{font-size:.75rem;font-weight:600;color:var(--slate-500)!important;text-transform:uppercase}.week-day-num{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-top:2px}.booking-for-line{font-size:.9rem;color:var(--slate-600)!important;padding:.85rem 1rem;background:var(--slate-50);border-radius:var(--border-radius-md);margin-bottom:.5rem}.booking-for-line strong{color:var(--slate-900)!important}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.design-row{display:flex;gap:13px;align-items:center;padding-bottom:1rem}.design-thumb{width:56px;height:56px;border-radius:8px;background:var(--slate-100);flex:none}.design-info{flex:1}.design-name{font-size:13.5px;color:var(--slate-900)!important;line-height:1.35}.design-price{font-size:13.5px;font-weight:600;color:var(--slate-900)!important;margin-top:3px}.add-more-btn{width:100%;height:44px;border:1.5px dashed var(--slate-300);border-radius:8px;background:none;color:var(--color-primary)!important;font-size:13px;font-weight:600;cursor:pointer;margin-bottom:1rem}.summary-divider{height:1px;background:var(--slate-100);margin-bottom:1rem}.summary-line{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.free-label{font-size:13.5px;font-weight:600;color:var(--color-success)!important}.footnote{font-size:11.5px;line-height:1.5;color:var(--slate-500)!important;text-align:center;margin:.75rem 0 0}.review-card{max-width:560px;margin:0 auto;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);overflow:hidden}.review-header{padding:14px 18px;background:var(--slate-50);border-bottom:1px solid var(--slate-100);font-size:14.5px;font-weight:700;color:var(--slate-900)!important}.review-row{display:flex;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slate-100);font-size:13.5px}.review-row:last-child{border-bottom:none}.review-k{color:var(--slate-500)!important;flex-shrink:0}.review-v{color:var(--slate-900)!important;font-weight:500;text-align:right}@media screen and (max-width: 475px){.single-grid{grid-template-columns:1fr}.single-right{position:static}.week-strip{gap:6px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "directive", type: HoverDirective, selector: "[simpoHover]", outputs: ["hovering"] }, { kind: "component", type: HoverElementsComponent, selector: "simpo-hover-elements", inputs: ["data", "index", "editOptions", "isMerged", "isEcommerce"], outputs: ["edit"] }, { kind: "directive", type: BackgroundDirective, selector: "[simpoBackground]", inputs: ["simpoBackground", "scrollValue"] }] }); }
|
|
26311
26348
|
}
|
|
26312
26349
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BookAppointmentComponent, decorators: [{
|
|
26313
26350
|
type: Component,
|
|
26314
|
-
args: [{ selector: 'simpo-book-appointment', standalone: true, imports: [CommonModule, MatIcon, MatIconModule, FormsModule, MatDialogModule, ToastModule], providers: [MessageService], template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\">\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"header-title\">\n <h1>{{bannerTitle}}</h1>\n <p>{{bannerDesc}}</p>\n </div>\n </div>\n </div>\n\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <div class=\"wiz-container\">\n\n <div class=\"step-indicator\" *ngIf=\"step !== 'done'\">\n <div class=\"step-dot\" [class.active]=\"true\">1</div>\n <div class=\"step-label\" [class.active]=\"step==='form'\">Date, time & details</div>\n <div class=\"step-divider\"></div>\n <div class=\"step-dot\" [class.active]=\"step==='review'\">2</div>\n <div class=\"step-label\" [class.active]=\"step==='review'\">Review & confirm</div>\n </div>\n\n <ng-container *ngIf=\"step === 'form'\">\n <div class=\"single-grid\">\n <div class=\"single-left\">\n\n <div class=\"section-card card\">\n <div class=\"week-header\">\n <div>\n <h3 class=\"section-title mb-0\">Select a Date</h3>\n <p class=\"subtitle mb-0\">{{weekRangeLabel}}</p>\n </div>\n <div class=\"week-arrows\">\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"prevWeek()\" [disabled]=\"weekOffset <= 0\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"nextWeek()\" [disabled]=\"weekOffset >= maxWeekOffset\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"week-strip\">\n <button type=\"button\" class=\"week-day\" *ngFor=\"let d of weekDays\" [class.selected]=\"d.selected\"\n (click)=\"pickDay(d)\">\n <div class=\"week-day-dow\">{{d.dow}}</div>\n <div class=\"week-day-num\">{{d.num}}</div>\n </button>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title mb-0\">Select a Time</h3>\n <p class=\"subtitle\" *ngIf=\"selectedDateStr\">Available slots for {{selectedDateStr}}</p>\n <p class=\"subtitle mb-0\" *ngIf=\"!selectedDateStr\">Pick a date to see available times.</p>\n <div class=\"row g-2 overflow-scroll\" *ngIf=\"selectedDateStr\">\n <ng-container *ngIf=\"!slotsLoading; else slotsLoadingTpl\">\n <div class=\"col-4\" *ngFor=\"let time of slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlot(time)\">{{time?.value}}</div>\n </div>\n <p class=\"mb-0\" *ngIf=\"slots.length === 0\">No slots available for this date.</p>\n </ng-container>\n <ng-template #slotsLoadingTpl>\n <p class=\"mb-0\">Loading available times...</p>\n </ng-template>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title\">Booking Details</h3>\n <div class=\"booking-for-line\">\n Booking for <strong>{{userDetails?.contact?.name}}</strong>\n <ng-container *ngIf=\"userDetails?.contact?.mobile\"> \u00B7 {{userDetails?.contact?.mobile}}</ng-container>\n <ng-container *ngIf=\"userDetails?.contact?.email\"> \u00B7 {{userDetails?.contact?.email}}</ng-container>\n </div>\n\n <ng-container *ngIf=\"mode === 'HOME_VISIT'\">\n <p class=\"policies-title mt-3 mb-2\" style=\"font-size:1rem;\">Shipping Address</p>\n\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Instructions (optional)</label>\n <textarea class=\"form-control form-textarea rounded-2\" [(ngModel)]=\"instructions\"></textarea>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"single-right section-card card\">\n <h3 class=\"section-title\">Your Shortlisted Designs</h3>\n <div class=\"design-row\" *ngFor=\"let it of productCartItems\">\n <div class=\"design-thumb\"></div>\n <div class=\"design-info\">\n <div class=\"design-name\">{{it.itemName}}</div>\n <div class=\"design-price\">\u20B9{{(it.sellingPrice ?? it.price ?? 0) * (it.quantity ?? 1)}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"add-more-btn\" (click)=\"goToListing()\">+ Add More Designs</button>\n\n <div class=\"summary-divider\"></div>\n\n <div class=\"summary-line\">\n <div class=\"summary-label\">Service:</div>\n <div class=\"free-label\">FREE</div>\n </div>\n <div class=\"summary-line\" *ngIf=\"mode === 'HOME_VISIT' && homeVisitCharge > 0\">\n <div class=\"summary-label\">Home visit charge</div>\n <div class=\"summary-value\">\u20B9{{homeVisitCharge}}</div>\n </div>\n\n <button class=\"continue-btn w-100 mt-2\" [disabled]=\"invalid()\" (click)=\"goToReview()\">Review Booking</button>\n <p class=\"footnote\">You will review everything on the next screen before it is confirmed.</p>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'review'\">\n <div class=\"review-card card\">\n <div class=\"review-header\">Review your booking</div>\n <div class=\"review-row\" *ngFor=\"let rc of reviewRows\">\n <div class=\"review-k\">{{rc.k}}</div>\n <div class=\"review-v\">{{rc.v}}</div>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'done'\">\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book your appointment. Please\n try again later'}}\n </p>\n\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && mode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\">\n <span class=\"detail-label\">{{productCartItems.length ? 'Products' : (mode === 'HOME_VISIT' ? 'Home Visit' : 'Video Call')}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"main_footer d-flex justify-content-center align-items-center\" *ngIf=\"step === 'review'\">\n <div class=\"footer-buttons\" style=\"justify-content:space-between\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"backToForm()\">Back</span>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center complete_booking\"\n (click)=\"confirmBooking()\" [disabled]=\"isProcessing\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}h1{font-size:24px!important;font-weight:600!important}.wiz-container{width:100%;max-width:1120px}.step-indicator{display:flex;align-items:center;gap:10px;padding-bottom:18px}.step-dot{width:26px;height:26px;border-radius:50%;background:var(--slate-200);color:var(--slate-500)!important;font-size:.8rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.step-dot.active{background:var(--color-accent-gradient);color:#fff!important}.step-label{font-size:12.5px;color:var(--slate-400)!important;font-weight:600}.step-label.active{color:var(--slate-900)!important}.step-divider{width:40px;height:1px;background:var(--slate-200)}.single-grid{display:grid;grid-template-columns:1fr 360px;gap:1.5rem;align-items:start}.single-left{display:flex;flex-direction:column;gap:1.5rem}.single-right{align-self:flex-start;position:sticky;top:10px}.week-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:14px}.week-arrows{display:flex;gap:8px}.week-arrow-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--slate-200);background:#fff;color:var(--slate-700)!important;cursor:pointer;display:flex;align-items:center;justify-content:center}.week-arrow-btn:disabled{color:var(--slate-300)!important;cursor:not-allowed}.week-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:10px}.week-day{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem .25rem;cursor:pointer;transition:var(--transition-smooth);text-align:center}.week-day:hover{border-color:var(--slate-400)}.week-day.selected{background:var(--color-accent-gradient);border-color:transparent}.week-day.selected .week-day-dow,.week-day.selected .week-day-num{color:#fff!important}.week-day-dow{font-size:.75rem;font-weight:600;color:var(--slate-500)!important;text-transform:uppercase}.week-day-num{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-top:2px}.booking-for-line{font-size:.9rem;color:var(--slate-600)!important;padding:.85rem 1rem;background:var(--slate-50);border-radius:var(--border-radius-md);margin-bottom:.5rem}.booking-for-line strong{color:var(--slate-900)!important}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.design-row{display:flex;gap:13px;align-items:center;padding-bottom:1rem}.design-thumb{width:56px;height:56px;border-radius:8px;background:var(--slate-100);flex:none}.design-info{flex:1}.design-name{font-size:13.5px;color:var(--slate-900)!important;line-height:1.35}.design-price{font-size:13.5px;font-weight:600;color:var(--slate-900)!important;margin-top:3px}.add-more-btn{width:100%;height:44px;border:1.5px dashed var(--slate-300);border-radius:8px;background:none;color:var(--color-primary)!important;font-size:13px;font-weight:600;cursor:pointer;margin-bottom:1rem}.summary-divider{height:1px;background:var(--slate-100);margin-bottom:1rem}.summary-line{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.free-label{font-size:13.5px;font-weight:600;color:var(--color-success)!important}.footnote{font-size:11.5px;line-height:1.5;color:var(--slate-500)!important;text-align:center;margin:.75rem 0 0}.review-card{max-width:560px;margin:0 auto;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);overflow:hidden}.review-header{padding:14px 18px;background:var(--slate-50);border-bottom:1px solid var(--slate-100);font-size:14.5px;font-weight:700;color:var(--slate-900)!important}.review-row{display:flex;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slate-100);font-size:13.5px}.review-row:last-child{border-bottom:none}.review-k{color:var(--slate-500)!important;flex-shrink:0}.review-v{color:var(--slate-900)!important;font-weight:500;text-align:right}@media screen and (max-width: 475px){.single-grid{grid-template-columns:1fr}.single-right{position:static}.week-strip{gap:6px}}\n"] }]
|
|
26351
|
+
args: [{ selector: 'simpo-book-appointment', standalone: true, imports: [CommonModule, MatIcon, MatIconModule, FormsModule, MatDialogModule, ToastModule, HoverDirective, HoverElementsComponent, BackgroundDirective], providers: [MessageService], template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\" simpoHover (hovering)=\"showEditTabs($event)\"\n [simpoBackground]=\"backgroundInfo\" [style.--color-accent-gradient]=\"accentColor\">\n <div [ngClass]=\"{'hover_effect': edit}\" *ngIf=\"showEditors\">\n <simpo-hover-elements [data]=\"data\" [index]=\"index\" [editOptions]=\"edit\"></simpo-hover-elements>\n </div>\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"header-title\">\n <h1>{{bannerTitle}}</h1>\n <p>{{bannerDesc}}</p>\n </div>\n </div>\n </div>\n\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <div class=\"wiz-container\">\n\n <div class=\"step-indicator\" *ngIf=\"step !== 'done'\">\n <div class=\"step-dot\" [class.active]=\"true\">1</div>\n <div class=\"step-label\" [class.active]=\"step==='form'\">Date, time & details</div>\n <div class=\"step-divider\"></div>\n <div class=\"step-dot\" [class.active]=\"step==='review'\">2</div>\n <div class=\"step-label\" [class.active]=\"step==='review'\">Review & confirm</div>\n </div>\n\n <ng-container *ngIf=\"step === 'form'\">\n <div class=\"single-grid\">\n <div class=\"single-left\">\n\n <div class=\"section-card card\">\n <div class=\"week-header\">\n <div>\n <h3 class=\"section-title mb-0\">Select a Date</h3>\n <p class=\"subtitle mb-0\">{{weekRangeLabel}}</p>\n </div>\n <div class=\"week-arrows\">\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"prevWeek()\" [disabled]=\"weekOffset <= 0\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"nextWeek()\" [disabled]=\"weekOffset >= maxWeekOffset\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"week-strip\">\n <button type=\"button\" class=\"week-day\" *ngFor=\"let d of weekDays\" [class.selected]=\"d.selected\"\n (click)=\"pickDay(d)\">\n <div class=\"week-day-dow\">{{d.dow}}</div>\n <div class=\"week-day-num\">{{d.num}}</div>\n </button>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title mb-0\">Select a Time</h3>\n <p class=\"subtitle\" *ngIf=\"selectedDateStr\">Available slots for {{selectedDateStr}}</p>\n <p class=\"subtitle mb-0\" *ngIf=\"!selectedDateStr\">Pick a date to see available times.</p>\n <div class=\"row g-2 overflow-scroll\" *ngIf=\"selectedDateStr\">\n <ng-container *ngIf=\"!slotsLoading; else slotsLoadingTpl\">\n <div class=\"col-4\" *ngFor=\"let time of slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlot(time)\">{{time?.value}}</div>\n </div>\n <p class=\"mb-0\" *ngIf=\"slots.length === 0\">No slots available for this date.</p>\n </ng-container>\n <ng-template #slotsLoadingTpl>\n <p class=\"mb-0\">Loading available times...</p>\n </ng-template>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title\">Booking Details</h3>\n <div class=\"booking-for-line\">\n Booking for <strong>{{userDetails?.contact?.name}}</strong>\n <ng-container *ngIf=\"userDetails?.contact?.mobile\"> \u00B7 {{userDetails?.contact?.mobile}}</ng-container>\n <ng-container *ngIf=\"userDetails?.contact?.email\"> \u00B7 {{userDetails?.contact?.email}}</ng-container>\n </div>\n\n <ng-container *ngIf=\"mode === 'HOME_VISIT'\">\n <p class=\"policies-title mt-3 mb-2\" style=\"font-size:1rem;\">Shipping Address</p>\n\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Instructions (optional)</label>\n <textarea class=\"form-control form-textarea rounded-2\" [(ngModel)]=\"instructions\"></textarea>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"single-right section-card card\">\n <h3 class=\"section-title\">Your Shortlisted Designs</h3>\n <div class=\"design-row\" *ngFor=\"let it of productCartItems\">\n <div class=\"design-thumb\"></div>\n <div class=\"design-info\">\n <div class=\"design-name\">{{it.itemName}}</div>\n <div class=\"design-price\">\u20B9{{(it.sellingPrice ?? it.price ?? 0) * (it.quantity ?? 1)}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"add-more-btn\" (click)=\"goToListing()\">+ Add More Designs</button>\n\n <div class=\"summary-divider\"></div>\n\n <div class=\"summary-line\" *ngIf=\"mode !== 'HOME_VISIT' || homeVisitCharge <= 0\">\n <div class=\"summary-label\">Service:</div>\n <div class=\"free-label\">FREE</div>\n </div>\n <div class=\"summary-line\" *ngIf=\"mode === 'HOME_VISIT' && homeVisitCharge > 0\">\n <div class=\"summary-label\">Home visit charge</div>\n <div class=\"summary-value\">\u20B9{{homeVisitCharge}}</div>\n </div>\n\n <button class=\"continue-btn w-100 mt-2\" [disabled]=\"invalid()\" (click)=\"goToReview()\">Review Booking</button>\n <p class=\"footnote\">You will review everything on the next screen before it is confirmed.</p>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'review'\">\n <div class=\"review-card card\">\n <div class=\"review-header\">Review your booking</div>\n <div class=\"review-row\" *ngFor=\"let rc of reviewRows\">\n <div class=\"review-k\">{{rc.k}}</div>\n <div class=\"review-v\">{{rc.v}}</div>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'done'\">\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book your appointment. Please\n try again later'}}\n </p>\n\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && mode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\">\n <span class=\"detail-label\">{{productCartItems.length ? 'Products' : (mode === 'HOME_VISIT' ? 'Home Visit' : 'Video Call')}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"main_footer d-flex justify-content-center align-items-center\" *ngIf=\"step === 'review'\">\n <div class=\"footer-buttons\" style=\"justify-content:space-between\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"backToForm()\">Back</span>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center complete_booking\"\n (click)=\"confirmBooking()\" [disabled]=\"isProcessing\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.hover_effect{position:absolute;width:100%;top:0;left:0;height:100%}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}h1{font-size:24px!important;font-weight:600!important}.wiz-container{width:100%;max-width:1120px}.step-indicator{display:flex;align-items:center;gap:10px;padding-bottom:18px}.step-dot{width:26px;height:26px;border-radius:50%;background:var(--slate-200);color:var(--slate-500)!important;font-size:.8rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.step-dot.active{background:var(--color-accent-gradient);color:#fff!important}.step-label{font-size:12.5px;color:var(--slate-400)!important;font-weight:600}.step-label.active{color:var(--slate-900)!important}.step-divider{width:40px;height:1px;background:var(--slate-200)}.single-grid{display:grid;grid-template-columns:1fr 360px;gap:1.5rem;align-items:start}.single-left{display:flex;flex-direction:column;gap:1.5rem}.single-right{align-self:flex-start;position:sticky;top:10px}.week-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:14px}.week-arrows{display:flex;gap:8px}.week-arrow-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--slate-200);background:#fff;color:var(--slate-700)!important;cursor:pointer;display:flex;align-items:center;justify-content:center}.week-arrow-btn:disabled{color:var(--slate-300)!important;cursor:not-allowed}.week-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:10px}.week-day{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem .25rem;cursor:pointer;transition:var(--transition-smooth);text-align:center}.week-day:hover{border-color:var(--slate-400)}.week-day.selected{background:var(--color-accent-gradient);border-color:transparent}.week-day.selected .week-day-dow,.week-day.selected .week-day-num{color:#fff!important}.week-day-dow{font-size:.75rem;font-weight:600;color:var(--slate-500)!important;text-transform:uppercase}.week-day-num{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-top:2px}.booking-for-line{font-size:.9rem;color:var(--slate-600)!important;padding:.85rem 1rem;background:var(--slate-50);border-radius:var(--border-radius-md);margin-bottom:.5rem}.booking-for-line strong{color:var(--slate-900)!important}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.design-row{display:flex;gap:13px;align-items:center;padding-bottom:1rem}.design-thumb{width:56px;height:56px;border-radius:8px;background:var(--slate-100);flex:none}.design-info{flex:1}.design-name{font-size:13.5px;color:var(--slate-900)!important;line-height:1.35}.design-price{font-size:13.5px;font-weight:600;color:var(--slate-900)!important;margin-top:3px}.add-more-btn{width:100%;height:44px;border:1.5px dashed var(--slate-300);border-radius:8px;background:none;color:var(--color-primary)!important;font-size:13px;font-weight:600;cursor:pointer;margin-bottom:1rem}.summary-divider{height:1px;background:var(--slate-100);margin-bottom:1rem}.summary-line{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.free-label{font-size:13.5px;font-weight:600;color:var(--color-success)!important}.footnote{font-size:11.5px;line-height:1.5;color:var(--slate-500)!important;text-align:center;margin:.75rem 0 0}.review-card{max-width:560px;margin:0 auto;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);overflow:hidden}.review-header{padding:14px 18px;background:var(--slate-50);border-bottom:1px solid var(--slate-100);font-size:14.5px;font-weight:700;color:var(--slate-900)!important}.review-row{display:flex;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slate-100);font-size:13.5px}.review-row:last-child{border-bottom:none}.review-k{color:var(--slate-500)!important;flex-shrink:0}.review-v{color:var(--slate-900)!important;font-weight:500;text-align:right}@media screen and (max-width: 475px){.single-grid{grid-template-columns:1fr}.single-right{position:static}.week-strip{gap:6px}}\n"] }]
|
|
26315
26352
|
}], ctorParameters: () => [{ type: i2$2.ActivatedRoute }, { type: i2$2.Router }, { type: RestService }, { type: EventsService }, { type: i6$1.MessageService }, { type: StorageServiceService }, { type: BookingProductCartService }, { type: i3$2.MatDialog }], propDecorators: { data: [{
|
|
26316
26353
|
type: Input
|
|
26317
26354
|
}], index: [{
|