simpo-component-library 3.7.6 → 3.7.7

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.
@@ -3303,6 +3303,11 @@ class RestService {
3303
3303
  getBookingGroup(groupId) {
3304
3304
  return this.http.get(this.APPOINTMENT_URL + `booking/group/${groupId}`);
3305
3305
  }
3306
+ /** Fetched on click, not pre-cached on the booking - ecommerce generates/caches the invoice PDF
3307
+ * the first time it's asked for, so there's nothing to gain by fetching it earlier. */
3308
+ getBookingInvoiceUrl(groupId) {
3309
+ return this.http.get(this.APPOINTMENT_URL + `booking/group/${groupId}/invoice-url`);
3310
+ }
3306
3311
  generatePaymentToken(groupId) {
3307
3312
  return this.http.post(this.APPOINTMENT_URL + `payment/token?groupId=${groupId}`, {});
3308
3313
  }
@@ -23023,6 +23028,27 @@ class MyBookingsComponent {
23023
23028
  pendingAmount(b) {
23024
23029
  return Math.max(0, this.totalDue(b) - (b.totalCollectedAtBooking ?? 0));
23025
23030
  }
23031
+ /** Fetched on click, not pre-cached - ecommerce generates/caches the invoice PDF the first time
23032
+ * it's asked for, so there's nothing to gain by fetching it earlier. Same S3 PDF url pattern
23033
+ * ecommerce's own order-details.component.ts reads invoiceUrl/receiptUrl from, just resolved
23034
+ * live here instead of being present on the row already. */
23035
+ downloadInvoice() {
23036
+ if (!this.selected?.invoiceId)
23037
+ return;
23038
+ this.restService.getBookingInvoiceUrl(this.selected.groupId).subscribe({
23039
+ next: (url) => {
23040
+ if (url) {
23041
+ window.open(url, '_blank');
23042
+ }
23043
+ else {
23044
+ this.messageService.add({ severity: 'error', summary: 'Error', detail: 'Invoice not available yet' });
23045
+ }
23046
+ },
23047
+ error: (error) => {
23048
+ this.messageService.add({ severity: 'error', summary: 'Error', detail: error?.error?.detail ?? 'Unable to fetch invoice' });
23049
+ },
23050
+ });
23051
+ }
23026
23052
  get canCancelSelected() {
23027
23053
  return !!this.selected && (this.selected.status === 'HOLD' || this.selected.status === 'BOOKED' || this.selected.status === 'PENDING');
23028
23054
  }
@@ -23268,11 +23294,11 @@ class MyBookingsComponent {
23268
23294
  });
23269
23295
  }
23270
23296
  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 }, { token: EventsService }], target: i0.ɵɵFactoryTarget.Component }); }
23271
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MyBookingsComponent, isStandalone: true, selector: "simpo-my-bookings", inputs: { data: "data" }, providers: [MessageService], viewQueries: [{ propertyName: "reschDayStripRef", first: true, predicate: ["reschDayStrip"], descendants: true }], 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\" *ngIf=\"servicePriceTotal(selected) > 0\">\n <div class=\"mb-detail-k\">Service price</div>\n <div class=\"mb-detail-v\">\u20B9{{servicePriceTotal(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.homeVisitCharge\">\n <div class=\"mb-detail-k\">Home visit charge</div>\n <div class=\"mb-detail-v\">\u20B9{{selected.homeVisitCharge}}</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 <div class=\"mb-policy\" *ngIf=\"canRescheduleSelected\">\n <div class=\"mb-policy-title\">Reschedule policy</div>\n <div class=\"mb-policy-text\">You can reschedule this booking up to {{rescheduleCutoffHours}} hour{{rescheduleCutoffHours === 1 ? '' : 's'}} before the appointment time.</div>\n </div>\n <div class=\"mb-policy\" *ngIf=\"canCancelSelected && cancellationPolicy\">\n <div class=\"mb-policy-title\">{{cancellationPolicy.title}}</div>\n <div class=\"mb-policy-text\">{{cancellationPolicy.policyDetails}}</div>\n </div>\n\n <div class=\"mb-actions-row\" *ngIf=\"selected.status === 'BOOKED' || canCancelSelected\">\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n *ngIf=\"selected.status === 'BOOKED'\"\n [disabled]=\"!canRescheduleSelected\"\n [title]=\"!canRescheduleSelected ? selected.rescheduleBlockedReason : ''\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openReschedulePanel()\"\n >Reschedule booking</button>\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n *ngIf=\"canAddServiceSelected\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openAddServicePanel()\"\n >Add service</button>\n <button\n type=\"button\"\n class=\"mb-cancel-btn\"\n *ngIf=\"canCancelSelected\"\n [disabled]=\"cancelling\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openCancelConfirm()\"\n >\n {{cancelling ? 'Cancelling\u2026' : 'Cancel booking'}}\n </button>\n </div>\n\n <div class=\"mb-cancelled-note\" *ngIf=\"selected.status === 'CANCELLED'\">This booking has been cancelled.</div>\n </div>\n </ng-container>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"reschedulePanelOpen\" (click)=\"closeReschedulePanel()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Choose a new date &amp; time</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeReschedulePanel()\">&times;</button>\n </div>\n\n <div class=\"mb-resch-body\">\n <div class=\"mb-resch-daystrip-row\">\n <button type=\"button\" class=\"mb-resch-nav\" (click)=\"scrollReschDays(-1)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 18l-6-6 6-6\"></path></svg>\n </button>\n <div class=\"mb-resch-daystrip\" #reschDayStrip>\n <button\n type=\"button\"\n class=\"mb-resch-day\"\n *ngFor=\"let day of reschDays\"\n [class.active]=\"day.iso === reschSelectedIso\"\n [style.background]=\"day.iso === reschSelectedIso ? styles?.background?.accentColor : null\"\n [style.borderColor]=\"day.iso === reschSelectedIso ? styles?.background?.accentColor : null\"\n (click)=\"selectReschDay(day)\"\n >\n <span class=\"mb-resch-day-dow\" [style.color]=\"day.iso === reschSelectedIso ? contrastColor : null\">{{day.dow}}</span>\n <span class=\"mb-resch-day-num\" [style.color]=\"day.iso === reschSelectedIso ? contrastColor : null\">{{day.num}}</span>\n </button>\n </div>\n <button type=\"button\" class=\"mb-resch-nav\" (click)=\"scrollReschDays(1)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 18l6-6-6-6\"></path></svg>\n </button>\n </div>\n\n <div class=\"mb-resch-slots-loading\" *ngIf=\"reschLoadingSlots\">Loading available times\u2026</div>\n <div class=\"mb-resch-slots-empty\" *ngIf=\"!reschLoadingSlots && reschNoSlots\">No slots available on this date. Try another date.</div>\n <div class=\"mb-resch-slots\" *ngIf=\"!reschLoadingSlots && reschSlots.length\">\n <button\n type=\"button\"\n class=\"mb-resch-slot\"\n *ngFor=\"let slot of reschSlots\"\n [class.active]=\"slot === reschSelectedTime\"\n [style.background]=\"slot === reschSelectedTime ? styles?.background?.accentColor : null\"\n [style.borderColor]=\"slot === reschSelectedTime ? styles?.background?.accentColor : null\"\n [style.color]=\"slot === reschSelectedTime ? contrastColor : null\"\n (click)=\"selectReschTime(slot)\"\n >{{slot}}</button>\n </div>\n\n <div class=\"mb-resch-error\" *ngIf=\"reschError\">{{reschError}}</div>\n </div>\n\n <div class=\"mb-resch-footer\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeReschedulePanel()\">Cancel</button>\n <button\n type=\"button\"\n class=\"mb-resch-confirm\"\n [disabled]=\"reschInvalid\"\n [style.background]=\"reschInvalid ? null : styles?.background?.accentColor\"\n [style.color]=\"reschInvalid ? null : contrastColor\"\n (click)=\"confirmReschedule()\"\n >\n {{reschConfirming ? 'Confirming\u2026' : 'Confirm new slot'}}\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"cancelConfirmOpen\" (click)=\"closeCancelConfirm()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Cancel this booking?</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeCancelConfirm()\">&times;</button>\n </div>\n <div class=\"mb-resch-body\">\n <div class=\"mb-policy-text\">This can't be undone.</div>\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 </div>\n <div class=\"mb-resch-footer\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeCancelConfirm()\">Keep booking</button>\n <button type=\"button\" class=\"mb-resch-confirm\" [disabled]=\"cancelling\" (click)=\"cancelBooking()\">\n {{cancelling ? 'Cancelling\u2026' : 'Yes, cancel booking'}}\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"addServicePanelOpen\" (click)=\"closeAddServicePanel()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Add service(s)</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeAddServicePanel()\">&times;</button>\n </div>\n\n <div class=\"mb-resch-body\">\n <div class=\"mb-resch-slots-loading\" *ngIf=\"addServiceLoading\">Loading services\u2026</div>\n <div class=\"mb-resch-slots-empty\" *ngIf=\"!addServiceLoading && addServiceOptions.length === 0\">\n No services available to add right now.\n </div>\n\n <div class=\"mb-addsvc-list\" *ngIf=\"!addServiceLoading && addServiceOptions.length\">\n <button\n type=\"button\"\n class=\"mb-addsvc-row\"\n [class.selected]=\"isAddServiceSelected(service)\"\n *ngFor=\"let service of addServiceOptions\"\n [disabled]=\"addServiceSubmitting\"\n (click)=\"toggleAddService(service)\"\n >\n <input type=\"checkbox\" class=\"mb-addsvc-checkbox\" [checked]=\"isAddServiceSelected(service)\" (click)=\"$event.stopPropagation()\" (change)=\"toggleAddService(service)\" />\n <div class=\"f1\">\n <div class=\"mb-addsvc-name\">\n {{service.name}}\n <span class=\"mb-addsvc-meta\" *ngIf=\"service.duration\">{{service.duration}} min</span>\n </div>\n </div>\n <div class=\"mb-addsvc-price\" *ngIf=\"service.priceDetails?.totalPrice\">\u20B9{{service.priceDetails.totalPrice}}</div>\n </button>\n </div>\n\n <div class=\"mb-addsvc-total\" *ngIf=\"addServiceSelected.length && addServiceTotalDeposit > 0\">\n Deposit due now: \u20B9{{addServiceTotalDeposit}}\n </div>\n\n <div class=\"mb-resch-error\" *ngIf=\"addServiceError\">{{addServiceError}}</div>\n </div>\n\n <div class=\"mb-resch-footer\" *ngIf=\"!addServiceLoading && addServiceOptions.length\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeAddServicePanel()\">Cancel</button>\n <button\n type=\"button\"\n class=\"mb-resch-confirm\"\n [disabled]=\"!addServiceSelected.length || addServiceSubmitting\"\n [style.background]=\"!addServiceSelected.length ? null : styles?.background?.accentColor\"\n [style.color]=\"!addServiceSelected.length ? null : contrastColor\"\n (click)=\"addService()\"\n >\n {{addServiceSubmitting ? 'Adding\u2026' : 'Add ' + (addServiceSelected.length || '') + ' service' + (addServiceSelected.length === 1 ? '' : 's')}}\n </button>\n </div>\n </div>\n </div>\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}.status-ongoing{background:#e3f2fd;color:#1565c0}.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;border-radius:8px;background:#fff;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}.mb-actions-row{display:flex;gap:12px}.mb-actions-row .mb-reschedule-btn,.mb-actions-row .mb-cancel-btn{flex:1}.mb-reschedule-btn{height:46px;border:1.5px solid;border-radius:8px;background:#fff;font-size:13.5px;font-weight:600;cursor:pointer}.mb-reschedule-btn:disabled{opacity:.5;cursor:not-allowed}.mb-resch-backdrop{position:fixed;inset:0;background:#1b243673;display:flex;align-items:center;justify-content:center;padding:16px;z-index:1000}.mb-resch-panel{width:100%;max-width:440px;max-height:85vh;border-radius:14px;background:#fff;box-shadow:0 20px 50px #14141e40;display:flex;flex-direction:column;overflow:hidden}.mb-resch-header{display:flex;align-items:center;justify-content:space-between;padding:18px 20px;border-bottom:1px solid #F0ECE7;flex:none}.mb-resch-body{padding:18px 20px;overflow-y:auto}.mb-resch-footer{display:flex;gap:10px;padding:14px 20px;border-top:1px solid #F0ECE7;flex:none}.mb-resch-footer .mb-resch-cancel,.mb-resch-footer .mb-resch-confirm{flex:1}.mb-resch-cancel{height:46px;border:1.5px solid #E2E2E9;border-radius:8px;background:#fff;color:#5f6b7c;font-size:13.5px;font-weight:600;cursor:pointer}.mb-resch-title{font-size:14px;font-weight:600;color:#1b2436}.mb-resch-close{border:none;background:none;font-size:18px;color:#8a94a3;cursor:pointer;line-height:1;width:max-content}.mb-resch-daystrip-row{display:flex;align-items:center;gap:4px;margin-bottom:14px}.mb-resch-daystrip{display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-behavior:smooth}.mb-resch-daystrip::-webkit-scrollbar{height:5px}.mb-resch-daystrip::-webkit-scrollbar-thumb{background:#eee9e3;border-radius:999px}.mb-resch-nav{flex:none;width:26px!important;height:26px;border:1px solid #EEE9E3;border-radius:999px;background:#fff;color:#8a94a3;cursor:pointer;display:flex;align-items:center;justify-content:center}.mb-resch-nav:hover{border-color:#7c3a11;color:#7c3a11}.mb-resch-day{flex:none;display:flex;flex-direction:column;align-items:center;gap:2px;width:50px!important;padding:8px 0;border:1px solid #EEE9E3;border-radius:10px;background:#fff;cursor:pointer}.mb-resch-day:hover{border-color:#7c3a11}.mb-resch-day-dow{font-size:10.5px;color:#8a94a3;text-transform:uppercase}.mb-resch-day-num{font-size:13.5px;font-weight:600;color:#1b2436}.mb-resch-slots-loading,.mb-resch-slots-empty{font-size:12.5px;color:#8a94a3;margin-bottom:14px}.mb-resch-slots{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.mb-resch-slot{padding:9px 6px;border:1px solid #EEE9E3;border-radius:8px;background:#fff;font-size:12.5px!important;color:#1b2436;cursor:pointer}.mb-resch-error{margin-top:14px;font-size:12.5px;color:#b4432e}.mb-addsvc-list{display:flex;flex-direction:column;gap:8px}.mb-addsvc-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 12px;border:1px solid #EEE9E3;border-radius:8px;background:#fff;cursor:pointer;text-align:left;width:100%}.mb-addsvc-row.selected{background:#f6f2fc;border-color:#6d28d9}.mb-addsvc-row:disabled{opacity:.6;cursor:default}.mb-addsvc-checkbox{flex:none;width:16px;height:16px;cursor:pointer}.mb-addsvc-row .f1{flex:1}.mb-addsvc-name{font-size:13px;color:#1b2436}.mb-addsvc-meta{display:block;font-size:11.5px;color:#8a94a3;margin-top:2px}.mb-addsvc-price{font-size:13px;font-weight:600;color:#1b2436;flex:none}.mb-addsvc-total{margin-top:12px;font-size:12.5px;font-weight:600;color:#1b2436}.mb-resch-confirm{height:46px;border:none;border-radius:8px;background:#94a3b8;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer}.mb-resch-confirm:disabled{opacity:.5;cursor:not-allowed}\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"] }] }); }
23297
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MyBookingsComponent, isStandalone: true, selector: "simpo-my-bookings", inputs: { data: "data" }, providers: [MessageService], viewQueries: [{ propertyName: "reschDayStripRef", first: true, predicate: ["reschDayStrip"], descendants: true }], 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\" *ngIf=\"servicePriceTotal(selected) > 0\">\n <div class=\"mb-detail-k\">Service price</div>\n <div class=\"mb-detail-v\">\u20B9{{servicePriceTotal(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.homeVisitCharge\">\n <div class=\"mb-detail-k\">Home visit charge</div>\n <div class=\"mb-detail-v\">\u20B9{{selected.homeVisitCharge}}</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 <div class=\"mb-policy\" *ngIf=\"canRescheduleSelected\">\n <div class=\"mb-policy-title\">Reschedule policy</div>\n <div class=\"mb-policy-text\">You can reschedule this booking up to {{rescheduleCutoffHours}} hour{{rescheduleCutoffHours === 1 ? '' : 's'}} before the appointment time.</div>\n </div>\n <div class=\"mb-policy\" *ngIf=\"canCancelSelected && cancellationPolicy\">\n <div class=\"mb-policy-title\">{{cancellationPolicy.title}}</div>\n <div class=\"mb-policy-text\">{{cancellationPolicy.policyDetails}}</div>\n </div>\n\n <div class=\"mb-actions-row\" *ngIf=\"selected.status === 'BOOKED' || canCancelSelected\">\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n *ngIf=\"selected.status === 'BOOKED'\"\n [disabled]=\"!canRescheduleSelected\"\n [title]=\"!canRescheduleSelected ? selected.rescheduleBlockedReason : ''\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openReschedulePanel()\"\n >Reschedule booking</button>\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n *ngIf=\"canAddServiceSelected\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openAddServicePanel()\"\n >Add service</button>\n <button\n type=\"button\"\n class=\"mb-cancel-btn\"\n *ngIf=\"canCancelSelected\"\n [disabled]=\"cancelling\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openCancelConfirm()\"\n >\n {{cancelling ? 'Cancelling\u2026' : 'Cancel booking'}}\n </button>\n </div>\n\n <div class=\"mb-actions-row\" *ngIf=\"selected.invoiceId && selected.status === 'COMPLETED'\">\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"downloadInvoice()\"\n >Download invoice</button>\n </div>\n\n <div class=\"mb-cancelled-note\" *ngIf=\"selected.status === 'CANCELLED'\">This booking has been cancelled.</div>\n </div>\n </ng-container>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"reschedulePanelOpen\" (click)=\"closeReschedulePanel()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Choose a new date &amp; time</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeReschedulePanel()\">&times;</button>\n </div>\n\n <div class=\"mb-resch-body\">\n <div class=\"mb-resch-daystrip-row\">\n <button type=\"button\" class=\"mb-resch-nav\" (click)=\"scrollReschDays(-1)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 18l-6-6 6-6\"></path></svg>\n </button>\n <div class=\"mb-resch-daystrip\" #reschDayStrip>\n <button\n type=\"button\"\n class=\"mb-resch-day\"\n *ngFor=\"let day of reschDays\"\n [class.active]=\"day.iso === reschSelectedIso\"\n [style.background]=\"day.iso === reschSelectedIso ? styles?.background?.accentColor : null\"\n [style.borderColor]=\"day.iso === reschSelectedIso ? styles?.background?.accentColor : null\"\n (click)=\"selectReschDay(day)\"\n >\n <span class=\"mb-resch-day-dow\" [style.color]=\"day.iso === reschSelectedIso ? contrastColor : null\">{{day.dow}}</span>\n <span class=\"mb-resch-day-num\" [style.color]=\"day.iso === reschSelectedIso ? contrastColor : null\">{{day.num}}</span>\n </button>\n </div>\n <button type=\"button\" class=\"mb-resch-nav\" (click)=\"scrollReschDays(1)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 18l6-6-6-6\"></path></svg>\n </button>\n </div>\n\n <div class=\"mb-resch-slots-loading\" *ngIf=\"reschLoadingSlots\">Loading available times\u2026</div>\n <div class=\"mb-resch-slots-empty\" *ngIf=\"!reschLoadingSlots && reschNoSlots\">No slots available on this date. Try another date.</div>\n <div class=\"mb-resch-slots\" *ngIf=\"!reschLoadingSlots && reschSlots.length\">\n <button\n type=\"button\"\n class=\"mb-resch-slot\"\n *ngFor=\"let slot of reschSlots\"\n [class.active]=\"slot === reschSelectedTime\"\n [style.background]=\"slot === reschSelectedTime ? styles?.background?.accentColor : null\"\n [style.borderColor]=\"slot === reschSelectedTime ? styles?.background?.accentColor : null\"\n [style.color]=\"slot === reschSelectedTime ? contrastColor : null\"\n (click)=\"selectReschTime(slot)\"\n >{{slot}}</button>\n </div>\n\n <div class=\"mb-resch-error\" *ngIf=\"reschError\">{{reschError}}</div>\n </div>\n\n <div class=\"mb-resch-footer\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeReschedulePanel()\">Cancel</button>\n <button\n type=\"button\"\n class=\"mb-resch-confirm\"\n [disabled]=\"reschInvalid\"\n [style.background]=\"reschInvalid ? null : styles?.background?.accentColor\"\n [style.color]=\"reschInvalid ? null : contrastColor\"\n (click)=\"confirmReschedule()\"\n >\n {{reschConfirming ? 'Confirming\u2026' : 'Confirm new slot'}}\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"cancelConfirmOpen\" (click)=\"closeCancelConfirm()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Cancel this booking?</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeCancelConfirm()\">&times;</button>\n </div>\n <div class=\"mb-resch-body\">\n <div class=\"mb-policy-text\">This can't be undone.</div>\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 </div>\n <div class=\"mb-resch-footer\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeCancelConfirm()\">Keep booking</button>\n <button type=\"button\" class=\"mb-resch-confirm\" [disabled]=\"cancelling\" (click)=\"cancelBooking()\">\n {{cancelling ? 'Cancelling\u2026' : 'Yes, cancel booking'}}\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"addServicePanelOpen\" (click)=\"closeAddServicePanel()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Add service(s)</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeAddServicePanel()\">&times;</button>\n </div>\n\n <div class=\"mb-resch-body\">\n <div class=\"mb-resch-slots-loading\" *ngIf=\"addServiceLoading\">Loading services\u2026</div>\n <div class=\"mb-resch-slots-empty\" *ngIf=\"!addServiceLoading && addServiceOptions.length === 0\">\n No services available to add right now.\n </div>\n\n <div class=\"mb-addsvc-list\" *ngIf=\"!addServiceLoading && addServiceOptions.length\">\n <button\n type=\"button\"\n class=\"mb-addsvc-row\"\n [class.selected]=\"isAddServiceSelected(service)\"\n *ngFor=\"let service of addServiceOptions\"\n [disabled]=\"addServiceSubmitting\"\n (click)=\"toggleAddService(service)\"\n >\n <input type=\"checkbox\" class=\"mb-addsvc-checkbox\" [checked]=\"isAddServiceSelected(service)\" (click)=\"$event.stopPropagation()\" (change)=\"toggleAddService(service)\" />\n <div class=\"f1\">\n <div class=\"mb-addsvc-name\">\n {{service.name}}\n <span class=\"mb-addsvc-meta\" *ngIf=\"service.duration\">{{service.duration}} min</span>\n </div>\n </div>\n <div class=\"mb-addsvc-price\" *ngIf=\"service.priceDetails?.totalPrice\">\u20B9{{service.priceDetails.totalPrice}}</div>\n </button>\n </div>\n\n <div class=\"mb-addsvc-total\" *ngIf=\"addServiceSelected.length && addServiceTotalDeposit > 0\">\n Deposit due now: \u20B9{{addServiceTotalDeposit}}\n </div>\n\n <div class=\"mb-resch-error\" *ngIf=\"addServiceError\">{{addServiceError}}</div>\n </div>\n\n <div class=\"mb-resch-footer\" *ngIf=\"!addServiceLoading && addServiceOptions.length\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeAddServicePanel()\">Cancel</button>\n <button\n type=\"button\"\n class=\"mb-resch-confirm\"\n [disabled]=\"!addServiceSelected.length || addServiceSubmitting\"\n [style.background]=\"!addServiceSelected.length ? null : styles?.background?.accentColor\"\n [style.color]=\"!addServiceSelected.length ? null : contrastColor\"\n (click)=\"addService()\"\n >\n {{addServiceSubmitting ? 'Adding\u2026' : 'Add ' + (addServiceSelected.length || '') + ' service' + (addServiceSelected.length === 1 ? '' : 's')}}\n </button>\n </div>\n </div>\n </div>\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}.status-ongoing{background:#e3f2fd;color:#1565c0}.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;border-radius:8px;background:#fff;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}.mb-actions-row{display:flex;gap:12px}.mb-actions-row .mb-reschedule-btn,.mb-actions-row .mb-cancel-btn{flex:1}.mb-reschedule-btn{height:46px;border:1.5px solid;border-radius:8px;background:#fff;font-size:13.5px;font-weight:600;cursor:pointer}.mb-reschedule-btn:disabled{opacity:.5;cursor:not-allowed}.mb-resch-backdrop{position:fixed;inset:0;background:#1b243673;display:flex;align-items:center;justify-content:center;padding:16px;z-index:1000}.mb-resch-panel{width:100%;max-width:440px;max-height:85vh;border-radius:14px;background:#fff;box-shadow:0 20px 50px #14141e40;display:flex;flex-direction:column;overflow:hidden}.mb-resch-header{display:flex;align-items:center;justify-content:space-between;padding:18px 20px;border-bottom:1px solid #F0ECE7;flex:none}.mb-resch-body{padding:18px 20px;overflow-y:auto}.mb-resch-footer{display:flex;gap:10px;padding:14px 20px;border-top:1px solid #F0ECE7;flex:none}.mb-resch-footer .mb-resch-cancel,.mb-resch-footer .mb-resch-confirm{flex:1}.mb-resch-cancel{height:46px;border:1.5px solid #E2E2E9;border-radius:8px;background:#fff;color:#5f6b7c;font-size:13.5px;font-weight:600;cursor:pointer}.mb-resch-title{font-size:14px;font-weight:600;color:#1b2436}.mb-resch-close{border:none;background:none;font-size:18px;color:#8a94a3;cursor:pointer;line-height:1;width:max-content}.mb-resch-daystrip-row{display:flex;align-items:center;gap:4px;margin-bottom:14px}.mb-resch-daystrip{display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-behavior:smooth}.mb-resch-daystrip::-webkit-scrollbar{height:5px}.mb-resch-daystrip::-webkit-scrollbar-thumb{background:#eee9e3;border-radius:999px}.mb-resch-nav{flex:none;width:26px!important;height:26px;border:1px solid #EEE9E3;border-radius:999px;background:#fff;color:#8a94a3;cursor:pointer;display:flex;align-items:center;justify-content:center}.mb-resch-nav:hover{border-color:#7c3a11;color:#7c3a11}.mb-resch-day{flex:none;display:flex;flex-direction:column;align-items:center;gap:2px;width:50px!important;padding:8px 0;border:1px solid #EEE9E3;border-radius:10px;background:#fff;cursor:pointer}.mb-resch-day:hover{border-color:#7c3a11}.mb-resch-day-dow{font-size:10.5px;color:#8a94a3;text-transform:uppercase}.mb-resch-day-num{font-size:13.5px;font-weight:600;color:#1b2436}.mb-resch-slots-loading,.mb-resch-slots-empty{font-size:12.5px;color:#8a94a3;margin-bottom:14px}.mb-resch-slots{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.mb-resch-slot{padding:9px 6px;border:1px solid #EEE9E3;border-radius:8px;background:#fff;font-size:12.5px!important;color:#1b2436;cursor:pointer}.mb-resch-error{margin-top:14px;font-size:12.5px;color:#b4432e}.mb-addsvc-list{display:flex;flex-direction:column;gap:8px}.mb-addsvc-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 12px;border:1px solid #EEE9E3;border-radius:8px;background:#fff;cursor:pointer;text-align:left;width:100%}.mb-addsvc-row.selected{background:#f6f2fc;border-color:#6d28d9}.mb-addsvc-row:disabled{opacity:.6;cursor:default}.mb-addsvc-checkbox{flex:none;width:16px;height:16px;cursor:pointer}.mb-addsvc-row .f1{flex:1}.mb-addsvc-name{font-size:13px;color:#1b2436}.mb-addsvc-meta{display:block;font-size:11.5px;color:#8a94a3;margin-top:2px}.mb-addsvc-price{font-size:13px;font-weight:600;color:#1b2436;flex:none}.mb-addsvc-total{margin-top:12px;font-size:12.5px;font-weight:600;color:#1b2436}.mb-resch-confirm{height:46px;border:none;border-radius:8px;background:#94a3b8;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer}.mb-resch-confirm:disabled{opacity:.5;cursor:not-allowed}\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"] }] }); }
23272
23298
  }
23273
23299
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MyBookingsComponent, decorators: [{
23274
23300
  type: Component,
23275
- 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\" *ngIf=\"servicePriceTotal(selected) > 0\">\n <div class=\"mb-detail-k\">Service price</div>\n <div class=\"mb-detail-v\">\u20B9{{servicePriceTotal(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.homeVisitCharge\">\n <div class=\"mb-detail-k\">Home visit charge</div>\n <div class=\"mb-detail-v\">\u20B9{{selected.homeVisitCharge}}</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 <div class=\"mb-policy\" *ngIf=\"canRescheduleSelected\">\n <div class=\"mb-policy-title\">Reschedule policy</div>\n <div class=\"mb-policy-text\">You can reschedule this booking up to {{rescheduleCutoffHours}} hour{{rescheduleCutoffHours === 1 ? '' : 's'}} before the appointment time.</div>\n </div>\n <div class=\"mb-policy\" *ngIf=\"canCancelSelected && cancellationPolicy\">\n <div class=\"mb-policy-title\">{{cancellationPolicy.title}}</div>\n <div class=\"mb-policy-text\">{{cancellationPolicy.policyDetails}}</div>\n </div>\n\n <div class=\"mb-actions-row\" *ngIf=\"selected.status === 'BOOKED' || canCancelSelected\">\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n *ngIf=\"selected.status === 'BOOKED'\"\n [disabled]=\"!canRescheduleSelected\"\n [title]=\"!canRescheduleSelected ? selected.rescheduleBlockedReason : ''\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openReschedulePanel()\"\n >Reschedule booking</button>\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n *ngIf=\"canAddServiceSelected\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openAddServicePanel()\"\n >Add service</button>\n <button\n type=\"button\"\n class=\"mb-cancel-btn\"\n *ngIf=\"canCancelSelected\"\n [disabled]=\"cancelling\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openCancelConfirm()\"\n >\n {{cancelling ? 'Cancelling\u2026' : 'Cancel booking'}}\n </button>\n </div>\n\n <div class=\"mb-cancelled-note\" *ngIf=\"selected.status === 'CANCELLED'\">This booking has been cancelled.</div>\n </div>\n </ng-container>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"reschedulePanelOpen\" (click)=\"closeReschedulePanel()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Choose a new date &amp; time</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeReschedulePanel()\">&times;</button>\n </div>\n\n <div class=\"mb-resch-body\">\n <div class=\"mb-resch-daystrip-row\">\n <button type=\"button\" class=\"mb-resch-nav\" (click)=\"scrollReschDays(-1)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 18l-6-6 6-6\"></path></svg>\n </button>\n <div class=\"mb-resch-daystrip\" #reschDayStrip>\n <button\n type=\"button\"\n class=\"mb-resch-day\"\n *ngFor=\"let day of reschDays\"\n [class.active]=\"day.iso === reschSelectedIso\"\n [style.background]=\"day.iso === reschSelectedIso ? styles?.background?.accentColor : null\"\n [style.borderColor]=\"day.iso === reschSelectedIso ? styles?.background?.accentColor : null\"\n (click)=\"selectReschDay(day)\"\n >\n <span class=\"mb-resch-day-dow\" [style.color]=\"day.iso === reschSelectedIso ? contrastColor : null\">{{day.dow}}</span>\n <span class=\"mb-resch-day-num\" [style.color]=\"day.iso === reschSelectedIso ? contrastColor : null\">{{day.num}}</span>\n </button>\n </div>\n <button type=\"button\" class=\"mb-resch-nav\" (click)=\"scrollReschDays(1)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 18l6-6-6-6\"></path></svg>\n </button>\n </div>\n\n <div class=\"mb-resch-slots-loading\" *ngIf=\"reschLoadingSlots\">Loading available times\u2026</div>\n <div class=\"mb-resch-slots-empty\" *ngIf=\"!reschLoadingSlots && reschNoSlots\">No slots available on this date. Try another date.</div>\n <div class=\"mb-resch-slots\" *ngIf=\"!reschLoadingSlots && reschSlots.length\">\n <button\n type=\"button\"\n class=\"mb-resch-slot\"\n *ngFor=\"let slot of reschSlots\"\n [class.active]=\"slot === reschSelectedTime\"\n [style.background]=\"slot === reschSelectedTime ? styles?.background?.accentColor : null\"\n [style.borderColor]=\"slot === reschSelectedTime ? styles?.background?.accentColor : null\"\n [style.color]=\"slot === reschSelectedTime ? contrastColor : null\"\n (click)=\"selectReschTime(slot)\"\n >{{slot}}</button>\n </div>\n\n <div class=\"mb-resch-error\" *ngIf=\"reschError\">{{reschError}}</div>\n </div>\n\n <div class=\"mb-resch-footer\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeReschedulePanel()\">Cancel</button>\n <button\n type=\"button\"\n class=\"mb-resch-confirm\"\n [disabled]=\"reschInvalid\"\n [style.background]=\"reschInvalid ? null : styles?.background?.accentColor\"\n [style.color]=\"reschInvalid ? null : contrastColor\"\n (click)=\"confirmReschedule()\"\n >\n {{reschConfirming ? 'Confirming\u2026' : 'Confirm new slot'}}\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"cancelConfirmOpen\" (click)=\"closeCancelConfirm()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Cancel this booking?</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeCancelConfirm()\">&times;</button>\n </div>\n <div class=\"mb-resch-body\">\n <div class=\"mb-policy-text\">This can't be undone.</div>\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 </div>\n <div class=\"mb-resch-footer\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeCancelConfirm()\">Keep booking</button>\n <button type=\"button\" class=\"mb-resch-confirm\" [disabled]=\"cancelling\" (click)=\"cancelBooking()\">\n {{cancelling ? 'Cancelling\u2026' : 'Yes, cancel booking'}}\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"addServicePanelOpen\" (click)=\"closeAddServicePanel()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Add service(s)</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeAddServicePanel()\">&times;</button>\n </div>\n\n <div class=\"mb-resch-body\">\n <div class=\"mb-resch-slots-loading\" *ngIf=\"addServiceLoading\">Loading services\u2026</div>\n <div class=\"mb-resch-slots-empty\" *ngIf=\"!addServiceLoading && addServiceOptions.length === 0\">\n No services available to add right now.\n </div>\n\n <div class=\"mb-addsvc-list\" *ngIf=\"!addServiceLoading && addServiceOptions.length\">\n <button\n type=\"button\"\n class=\"mb-addsvc-row\"\n [class.selected]=\"isAddServiceSelected(service)\"\n *ngFor=\"let service of addServiceOptions\"\n [disabled]=\"addServiceSubmitting\"\n (click)=\"toggleAddService(service)\"\n >\n <input type=\"checkbox\" class=\"mb-addsvc-checkbox\" [checked]=\"isAddServiceSelected(service)\" (click)=\"$event.stopPropagation()\" (change)=\"toggleAddService(service)\" />\n <div class=\"f1\">\n <div class=\"mb-addsvc-name\">\n {{service.name}}\n <span class=\"mb-addsvc-meta\" *ngIf=\"service.duration\">{{service.duration}} min</span>\n </div>\n </div>\n <div class=\"mb-addsvc-price\" *ngIf=\"service.priceDetails?.totalPrice\">\u20B9{{service.priceDetails.totalPrice}}</div>\n </button>\n </div>\n\n <div class=\"mb-addsvc-total\" *ngIf=\"addServiceSelected.length && addServiceTotalDeposit > 0\">\n Deposit due now: \u20B9{{addServiceTotalDeposit}}\n </div>\n\n <div class=\"mb-resch-error\" *ngIf=\"addServiceError\">{{addServiceError}}</div>\n </div>\n\n <div class=\"mb-resch-footer\" *ngIf=\"!addServiceLoading && addServiceOptions.length\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeAddServicePanel()\">Cancel</button>\n <button\n type=\"button\"\n class=\"mb-resch-confirm\"\n [disabled]=\"!addServiceSelected.length || addServiceSubmitting\"\n [style.background]=\"!addServiceSelected.length ? null : styles?.background?.accentColor\"\n [style.color]=\"!addServiceSelected.length ? null : contrastColor\"\n (click)=\"addService()\"\n >\n {{addServiceSubmitting ? 'Adding\u2026' : 'Add ' + (addServiceSelected.length || '') + ' service' + (addServiceSelected.length === 1 ? '' : 's')}}\n </button>\n </div>\n </div>\n </div>\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}.status-ongoing{background:#e3f2fd;color:#1565c0}.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;border-radius:8px;background:#fff;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}.mb-actions-row{display:flex;gap:12px}.mb-actions-row .mb-reschedule-btn,.mb-actions-row .mb-cancel-btn{flex:1}.mb-reschedule-btn{height:46px;border:1.5px solid;border-radius:8px;background:#fff;font-size:13.5px;font-weight:600;cursor:pointer}.mb-reschedule-btn:disabled{opacity:.5;cursor:not-allowed}.mb-resch-backdrop{position:fixed;inset:0;background:#1b243673;display:flex;align-items:center;justify-content:center;padding:16px;z-index:1000}.mb-resch-panel{width:100%;max-width:440px;max-height:85vh;border-radius:14px;background:#fff;box-shadow:0 20px 50px #14141e40;display:flex;flex-direction:column;overflow:hidden}.mb-resch-header{display:flex;align-items:center;justify-content:space-between;padding:18px 20px;border-bottom:1px solid #F0ECE7;flex:none}.mb-resch-body{padding:18px 20px;overflow-y:auto}.mb-resch-footer{display:flex;gap:10px;padding:14px 20px;border-top:1px solid #F0ECE7;flex:none}.mb-resch-footer .mb-resch-cancel,.mb-resch-footer .mb-resch-confirm{flex:1}.mb-resch-cancel{height:46px;border:1.5px solid #E2E2E9;border-radius:8px;background:#fff;color:#5f6b7c;font-size:13.5px;font-weight:600;cursor:pointer}.mb-resch-title{font-size:14px;font-weight:600;color:#1b2436}.mb-resch-close{border:none;background:none;font-size:18px;color:#8a94a3;cursor:pointer;line-height:1;width:max-content}.mb-resch-daystrip-row{display:flex;align-items:center;gap:4px;margin-bottom:14px}.mb-resch-daystrip{display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-behavior:smooth}.mb-resch-daystrip::-webkit-scrollbar{height:5px}.mb-resch-daystrip::-webkit-scrollbar-thumb{background:#eee9e3;border-radius:999px}.mb-resch-nav{flex:none;width:26px!important;height:26px;border:1px solid #EEE9E3;border-radius:999px;background:#fff;color:#8a94a3;cursor:pointer;display:flex;align-items:center;justify-content:center}.mb-resch-nav:hover{border-color:#7c3a11;color:#7c3a11}.mb-resch-day{flex:none;display:flex;flex-direction:column;align-items:center;gap:2px;width:50px!important;padding:8px 0;border:1px solid #EEE9E3;border-radius:10px;background:#fff;cursor:pointer}.mb-resch-day:hover{border-color:#7c3a11}.mb-resch-day-dow{font-size:10.5px;color:#8a94a3;text-transform:uppercase}.mb-resch-day-num{font-size:13.5px;font-weight:600;color:#1b2436}.mb-resch-slots-loading,.mb-resch-slots-empty{font-size:12.5px;color:#8a94a3;margin-bottom:14px}.mb-resch-slots{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.mb-resch-slot{padding:9px 6px;border:1px solid #EEE9E3;border-radius:8px;background:#fff;font-size:12.5px!important;color:#1b2436;cursor:pointer}.mb-resch-error{margin-top:14px;font-size:12.5px;color:#b4432e}.mb-addsvc-list{display:flex;flex-direction:column;gap:8px}.mb-addsvc-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 12px;border:1px solid #EEE9E3;border-radius:8px;background:#fff;cursor:pointer;text-align:left;width:100%}.mb-addsvc-row.selected{background:#f6f2fc;border-color:#6d28d9}.mb-addsvc-row:disabled{opacity:.6;cursor:default}.mb-addsvc-checkbox{flex:none;width:16px;height:16px;cursor:pointer}.mb-addsvc-row .f1{flex:1}.mb-addsvc-name{font-size:13px;color:#1b2436}.mb-addsvc-meta{display:block;font-size:11.5px;color:#8a94a3;margin-top:2px}.mb-addsvc-price{font-size:13px;font-weight:600;color:#1b2436;flex:none}.mb-addsvc-total{margin-top:12px;font-size:12.5px;font-weight:600;color:#1b2436}.mb-resch-confirm{height:46px;border:none;border-radius:8px;background:#94a3b8;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer}.mb-resch-confirm:disabled{opacity:.5;cursor:not-allowed}\n"] }]
23301
+ 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\" *ngIf=\"servicePriceTotal(selected) > 0\">\n <div class=\"mb-detail-k\">Service price</div>\n <div class=\"mb-detail-v\">\u20B9{{servicePriceTotal(selected)}}</div>\n </div>\n <div class=\"mb-detail-row\" *ngIf=\"selected.homeVisitCharge\">\n <div class=\"mb-detail-k\">Home visit charge</div>\n <div class=\"mb-detail-v\">\u20B9{{selected.homeVisitCharge}}</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 <div class=\"mb-policy\" *ngIf=\"canRescheduleSelected\">\n <div class=\"mb-policy-title\">Reschedule policy</div>\n <div class=\"mb-policy-text\">You can reschedule this booking up to {{rescheduleCutoffHours}} hour{{rescheduleCutoffHours === 1 ? '' : 's'}} before the appointment time.</div>\n </div>\n <div class=\"mb-policy\" *ngIf=\"canCancelSelected && cancellationPolicy\">\n <div class=\"mb-policy-title\">{{cancellationPolicy.title}}</div>\n <div class=\"mb-policy-text\">{{cancellationPolicy.policyDetails}}</div>\n </div>\n\n <div class=\"mb-actions-row\" *ngIf=\"selected.status === 'BOOKED' || canCancelSelected\">\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n *ngIf=\"selected.status === 'BOOKED'\"\n [disabled]=\"!canRescheduleSelected\"\n [title]=\"!canRescheduleSelected ? selected.rescheduleBlockedReason : ''\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openReschedulePanel()\"\n >Reschedule booking</button>\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n *ngIf=\"canAddServiceSelected\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openAddServicePanel()\"\n >Add service</button>\n <button\n type=\"button\"\n class=\"mb-cancel-btn\"\n *ngIf=\"canCancelSelected\"\n [disabled]=\"cancelling\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"openCancelConfirm()\"\n >\n {{cancelling ? 'Cancelling\u2026' : 'Cancel booking'}}\n </button>\n </div>\n\n <div class=\"mb-actions-row\" *ngIf=\"selected.invoiceId && selected.status === 'COMPLETED'\">\n <button\n type=\"button\"\n class=\"mb-reschedule-btn\"\n [style.borderColor]=\"styles?.background?.accentColor\"\n [style.color]=\"styles?.background?.accentColor\"\n (click)=\"downloadInvoice()\"\n >Download invoice</button>\n </div>\n\n <div class=\"mb-cancelled-note\" *ngIf=\"selected.status === 'CANCELLED'\">This booking has been cancelled.</div>\n </div>\n </ng-container>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"reschedulePanelOpen\" (click)=\"closeReschedulePanel()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Choose a new date &amp; time</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeReschedulePanel()\">&times;</button>\n </div>\n\n <div class=\"mb-resch-body\">\n <div class=\"mb-resch-daystrip-row\">\n <button type=\"button\" class=\"mb-resch-nav\" (click)=\"scrollReschDays(-1)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 18l-6-6 6-6\"></path></svg>\n </button>\n <div class=\"mb-resch-daystrip\" #reschDayStrip>\n <button\n type=\"button\"\n class=\"mb-resch-day\"\n *ngFor=\"let day of reschDays\"\n [class.active]=\"day.iso === reschSelectedIso\"\n [style.background]=\"day.iso === reschSelectedIso ? styles?.background?.accentColor : null\"\n [style.borderColor]=\"day.iso === reschSelectedIso ? styles?.background?.accentColor : null\"\n (click)=\"selectReschDay(day)\"\n >\n <span class=\"mb-resch-day-dow\" [style.color]=\"day.iso === reschSelectedIso ? contrastColor : null\">{{day.dow}}</span>\n <span class=\"mb-resch-day-num\" [style.color]=\"day.iso === reschSelectedIso ? contrastColor : null\">{{day.num}}</span>\n </button>\n </div>\n <button type=\"button\" class=\"mb-resch-nav\" (click)=\"scrollReschDays(1)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 18l6-6-6-6\"></path></svg>\n </button>\n </div>\n\n <div class=\"mb-resch-slots-loading\" *ngIf=\"reschLoadingSlots\">Loading available times\u2026</div>\n <div class=\"mb-resch-slots-empty\" *ngIf=\"!reschLoadingSlots && reschNoSlots\">No slots available on this date. Try another date.</div>\n <div class=\"mb-resch-slots\" *ngIf=\"!reschLoadingSlots && reschSlots.length\">\n <button\n type=\"button\"\n class=\"mb-resch-slot\"\n *ngFor=\"let slot of reschSlots\"\n [class.active]=\"slot === reschSelectedTime\"\n [style.background]=\"slot === reschSelectedTime ? styles?.background?.accentColor : null\"\n [style.borderColor]=\"slot === reschSelectedTime ? styles?.background?.accentColor : null\"\n [style.color]=\"slot === reschSelectedTime ? contrastColor : null\"\n (click)=\"selectReschTime(slot)\"\n >{{slot}}</button>\n </div>\n\n <div class=\"mb-resch-error\" *ngIf=\"reschError\">{{reschError}}</div>\n </div>\n\n <div class=\"mb-resch-footer\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeReschedulePanel()\">Cancel</button>\n <button\n type=\"button\"\n class=\"mb-resch-confirm\"\n [disabled]=\"reschInvalid\"\n [style.background]=\"reschInvalid ? null : styles?.background?.accentColor\"\n [style.color]=\"reschInvalid ? null : contrastColor\"\n (click)=\"confirmReschedule()\"\n >\n {{reschConfirming ? 'Confirming\u2026' : 'Confirm new slot'}}\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"cancelConfirmOpen\" (click)=\"closeCancelConfirm()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Cancel this booking?</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeCancelConfirm()\">&times;</button>\n </div>\n <div class=\"mb-resch-body\">\n <div class=\"mb-policy-text\">This can't be undone.</div>\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 </div>\n <div class=\"mb-resch-footer\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeCancelConfirm()\">Keep booking</button>\n <button type=\"button\" class=\"mb-resch-confirm\" [disabled]=\"cancelling\" (click)=\"cancelBooking()\">\n {{cancelling ? 'Cancelling\u2026' : 'Yes, cancel booking'}}\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mb-resch-backdrop\" *ngIf=\"addServicePanelOpen\" (click)=\"closeAddServicePanel()\">\n <div class=\"mb-resch-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"mb-resch-header\">\n <div class=\"mb-resch-title\">Add service(s)</div>\n <button type=\"button\" class=\"mb-resch-close\" (click)=\"closeAddServicePanel()\">&times;</button>\n </div>\n\n <div class=\"mb-resch-body\">\n <div class=\"mb-resch-slots-loading\" *ngIf=\"addServiceLoading\">Loading services\u2026</div>\n <div class=\"mb-resch-slots-empty\" *ngIf=\"!addServiceLoading && addServiceOptions.length === 0\">\n No services available to add right now.\n </div>\n\n <div class=\"mb-addsvc-list\" *ngIf=\"!addServiceLoading && addServiceOptions.length\">\n <button\n type=\"button\"\n class=\"mb-addsvc-row\"\n [class.selected]=\"isAddServiceSelected(service)\"\n *ngFor=\"let service of addServiceOptions\"\n [disabled]=\"addServiceSubmitting\"\n (click)=\"toggleAddService(service)\"\n >\n <input type=\"checkbox\" class=\"mb-addsvc-checkbox\" [checked]=\"isAddServiceSelected(service)\" (click)=\"$event.stopPropagation()\" (change)=\"toggleAddService(service)\" />\n <div class=\"f1\">\n <div class=\"mb-addsvc-name\">\n {{service.name}}\n <span class=\"mb-addsvc-meta\" *ngIf=\"service.duration\">{{service.duration}} min</span>\n </div>\n </div>\n <div class=\"mb-addsvc-price\" *ngIf=\"service.priceDetails?.totalPrice\">\u20B9{{service.priceDetails.totalPrice}}</div>\n </button>\n </div>\n\n <div class=\"mb-addsvc-total\" *ngIf=\"addServiceSelected.length && addServiceTotalDeposit > 0\">\n Deposit due now: \u20B9{{addServiceTotalDeposit}}\n </div>\n\n <div class=\"mb-resch-error\" *ngIf=\"addServiceError\">{{addServiceError}}</div>\n </div>\n\n <div class=\"mb-resch-footer\" *ngIf=\"!addServiceLoading && addServiceOptions.length\">\n <button type=\"button\" class=\"mb-resch-cancel\" (click)=\"closeAddServicePanel()\">Cancel</button>\n <button\n type=\"button\"\n class=\"mb-resch-confirm\"\n [disabled]=\"!addServiceSelected.length || addServiceSubmitting\"\n [style.background]=\"!addServiceSelected.length ? null : styles?.background?.accentColor\"\n [style.color]=\"!addServiceSelected.length ? null : contrastColor\"\n (click)=\"addService()\"\n >\n {{addServiceSubmitting ? 'Adding\u2026' : 'Add ' + (addServiceSelected.length || '') + ' service' + (addServiceSelected.length === 1 ? '' : 's')}}\n </button>\n </div>\n </div>\n </div>\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}.status-ongoing{background:#e3f2fd;color:#1565c0}.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;border-radius:8px;background:#fff;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}.mb-actions-row{display:flex;gap:12px}.mb-actions-row .mb-reschedule-btn,.mb-actions-row .mb-cancel-btn{flex:1}.mb-reschedule-btn{height:46px;border:1.5px solid;border-radius:8px;background:#fff;font-size:13.5px;font-weight:600;cursor:pointer}.mb-reschedule-btn:disabled{opacity:.5;cursor:not-allowed}.mb-resch-backdrop{position:fixed;inset:0;background:#1b243673;display:flex;align-items:center;justify-content:center;padding:16px;z-index:1000}.mb-resch-panel{width:100%;max-width:440px;max-height:85vh;border-radius:14px;background:#fff;box-shadow:0 20px 50px #14141e40;display:flex;flex-direction:column;overflow:hidden}.mb-resch-header{display:flex;align-items:center;justify-content:space-between;padding:18px 20px;border-bottom:1px solid #F0ECE7;flex:none}.mb-resch-body{padding:18px 20px;overflow-y:auto}.mb-resch-footer{display:flex;gap:10px;padding:14px 20px;border-top:1px solid #F0ECE7;flex:none}.mb-resch-footer .mb-resch-cancel,.mb-resch-footer .mb-resch-confirm{flex:1}.mb-resch-cancel{height:46px;border:1.5px solid #E2E2E9;border-radius:8px;background:#fff;color:#5f6b7c;font-size:13.5px;font-weight:600;cursor:pointer}.mb-resch-title{font-size:14px;font-weight:600;color:#1b2436}.mb-resch-close{border:none;background:none;font-size:18px;color:#8a94a3;cursor:pointer;line-height:1;width:max-content}.mb-resch-daystrip-row{display:flex;align-items:center;gap:4px;margin-bottom:14px}.mb-resch-daystrip{display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-behavior:smooth}.mb-resch-daystrip::-webkit-scrollbar{height:5px}.mb-resch-daystrip::-webkit-scrollbar-thumb{background:#eee9e3;border-radius:999px}.mb-resch-nav{flex:none;width:26px!important;height:26px;border:1px solid #EEE9E3;border-radius:999px;background:#fff;color:#8a94a3;cursor:pointer;display:flex;align-items:center;justify-content:center}.mb-resch-nav:hover{border-color:#7c3a11;color:#7c3a11}.mb-resch-day{flex:none;display:flex;flex-direction:column;align-items:center;gap:2px;width:50px!important;padding:8px 0;border:1px solid #EEE9E3;border-radius:10px;background:#fff;cursor:pointer}.mb-resch-day:hover{border-color:#7c3a11}.mb-resch-day-dow{font-size:10.5px;color:#8a94a3;text-transform:uppercase}.mb-resch-day-num{font-size:13.5px;font-weight:600;color:#1b2436}.mb-resch-slots-loading,.mb-resch-slots-empty{font-size:12.5px;color:#8a94a3;margin-bottom:14px}.mb-resch-slots{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.mb-resch-slot{padding:9px 6px;border:1px solid #EEE9E3;border-radius:8px;background:#fff;font-size:12.5px!important;color:#1b2436;cursor:pointer}.mb-resch-error{margin-top:14px;font-size:12.5px;color:#b4432e}.mb-addsvc-list{display:flex;flex-direction:column;gap:8px}.mb-addsvc-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 12px;border:1px solid #EEE9E3;border-radius:8px;background:#fff;cursor:pointer;text-align:left;width:100%}.mb-addsvc-row.selected{background:#f6f2fc;border-color:#6d28d9}.mb-addsvc-row:disabled{opacity:.6;cursor:default}.mb-addsvc-checkbox{flex:none;width:16px;height:16px;cursor:pointer}.mb-addsvc-row .f1{flex:1}.mb-addsvc-name{font-size:13px;color:#1b2436}.mb-addsvc-meta{display:block;font-size:11.5px;color:#8a94a3;margin-top:2px}.mb-addsvc-price{font-size:13px;font-weight:600;color:#1b2436;flex:none}.mb-addsvc-total{margin-top:12px;font-size:12.5px;font-weight:600;color:#1b2436}.mb-resch-confirm{height:46px;border:none;border-radius:8px;background:#94a3b8;color:#fff;font-size:13.5px;font-weight:600;cursor:pointer}.mb-resch-confirm:disabled{opacity:.5;cursor:not-allowed}\n"] }]
23276
23302
  }], ctorParameters: () => [{ type: RestService }, { type: StorageServiceService }, { type: i6$1.MessageService }, { type: EventsService }], propDecorators: { data: [{
23277
23303
  type: Input
23278
23304
  }], reschDayStripRef: [{