Changeset 3780965
- Timestamp:
- 11/02/2026 11:50:24 PM (4 hours ago)
- Location:
- yatoon-booking-system
- Files:
-
- 22 edited
-
tags/4.10.2/admin/views/bookings.php (modified) (3 diffs)
-
tags/4.10.2/assets/css/manage-booking.css (modified) (1 diff)
-
tags/4.10.2/assets/css/manage-booking.min.css (modified) (1 diff)
-
tags/4.10.2/assets/js/frontend-checkout.js (modified) (1 diff)
-
tags/4.10.2/assets/js/frontend-checkout.min.js (modified) (1 diff)
-
tags/4.10.2/assets/js/frontend-payments.js (modified) (3 diffs)
-
tags/4.10.2/assets/js/frontend-payments.min.js (modified) (1 diff)
-
tags/4.10.2/assets/js/yatoon-asset-manifest.json (modified) (1 diff)
-
tags/4.10.2/changelog.txt (modified) (1 diff)
-
tags/4.10.2/includes/class-yatoon-commerce.php (modified) (3 diffs)
-
tags/4.10.2/readme.txt (modified) (1 diff)
-
trunk/admin/views/bookings.php (modified) (3 diffs)
-
trunk/assets/css/manage-booking.css (modified) (1 diff)
-
trunk/assets/css/manage-booking.min.css (modified) (1 diff)
-
trunk/assets/js/frontend-checkout.js (modified) (1 diff)
-
trunk/assets/js/frontend-checkout.min.js (modified) (1 diff)
-
trunk/assets/js/frontend-payments.js (modified) (3 diffs)
-
trunk/assets/js/frontend-payments.min.js (modified) (1 diff)
-
trunk/assets/js/yatoon-asset-manifest.json (modified) (1 diff)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/includes/class-yatoon-commerce.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
yatoon-booking-system/tags/4.10.2/admin/views/bookings.php
r3780403 r3780965 367 367 if ( $summary_end && ( ! $get || $summary_end > $get ) ) { $get = $summary_end; } 368 368 } 369 // 4.10.2: label each expanded row with its day when the group covers more than one day (cancelled rows included). 370 $yatoon_group_days = array(); 371 foreach ( $gbks as $yatoon_day_row ) { 372 $yatoon_day_start = yatoon_booking_display_dt( $yatoon_day_row, 'start_time', $_sbs_local_tz, $_sbs_utc_tz ); 373 if ( $yatoon_day_start ) { $yatoon_group_days[ $yatoon_day_start->format( 'Y-m-d' ) ] = true; } 374 } 375 $yatoon_group_multi_day = count( $yatoon_group_days ) > 1; 369 376 $total_price = array_sum(array_column($summary_bookings, 'total_price')); 370 377 $group_statuses = array_unique( array_map( static fn( $b ) => (string) $b->status, $summary_bookings ) ); … … 432 439 <td><span style="font-size:12px;"><?php echo esc_html( $staff_names ); ?></span></td> 433 440 <td> 441 <?php // 4.10.2: a cart can hold appointments on different days; show the date range, not one long block. ?> 442 <?php if ( $gst->format( 'Y-m-d' ) === $get->format( 'Y-m-d' ) ) : ?> 434 443 <strong><?php echo esc_html( $gst->format('M j, Y') ); ?></strong><br> 435 444 <small><?php echo esc_html( $gst->format('g:i A') ); ?> - <?php echo esc_html( $get->format('g:i A') ); ?></small> 445 <?php else : ?> 446 <strong><?php echo esc_html( $gst->format( 'Y' ) === $get->format( 'Y' ) ? $gst->format( 'M j' ) . ' – ' . $get->format( 'M j, Y' ) : $gst->format( 'M j, Y' ) . ' – ' . $get->format( 'M j, Y' ) ); ?></strong><br> 447 <small><?php esc_html_e( 'Several days. Expand for each time.', 'yatoon-booking-system' ); ?></small> 448 <?php endif; ?> 436 449 </td> 437 450 <td><?php echo esc_html( $yatoon_admin_money( $total_price ) ); if ( $cancelled_count ) { echo '<br><small>' . esc_html( $active_bookings ? __( 'Excludes cancelled items', 'yatoon-booking-system' ) : __( 'Cancelled service total', 'yatoon-booking-system' ) ) . '</small>'; } echo wp_kses_post(YATOON_Gift_Cards::summary_html($summary_bookings)); ?></td> … … 493 506 <td><?php echo esc_html($yatoon_booking_row->staff_name ?: 'N/A'); ?></td> 494 507 <td> 495 <small style="color:#0369a1;font-weight:600;"><?php echo esc_html( $yatoon_booking_start_time->format('g:i A') ); ?></small>508 <small style="color:#0369a1;font-weight:600;"><?php echo esc_html( ( $yatoon_group_multi_day ? $yatoon_booking_start_time->format( 'M j' ) . ' · ' : '' ) . $yatoon_booking_start_time->format('g:i A') ); ?></small> 496 509 <small> - <?php echo esc_html( $yatoon_booking_end_time->format('g:i A') ); ?></small> 497 510 </td> -
yatoon-booking-system/tags/4.10.2/assets/css/manage-booking.css
r3729808 r3780965 737 737 .yatoon-manage-wrap .yatoon-rebook-btn { width:100%; } 738 738 } 739 /* Customer appointment management language menu. */ 740 .yatoon-manage-wrap .sbs-header-language{margin:0;position:relative;font-family:inherit} 741 .yatoon-manage-wrap .sbs-language-picker{position:relative;margin:0;padding:0;border:0} 742 .yatoon-manage-wrap .sbs-language-trigger{display:flex;align-items:center;gap:6px;min-height:40px;padding:7px 9px;border:0;border-radius:999px;background:transparent;color:#111827;font-family:inherit;font-size:13px;font-weight:600;line-height:1.4;cursor:pointer;list-style:none} 743 .yatoon-manage-wrap .sbs-language-trigger::-webkit-details-marker{display:none}.yatoon-manage-wrap .sbs-language-trigger::marker{content:''}.yatoon-manage-wrap .sbs-language-trigger::before,.yatoon-manage-wrap .sbs-language-trigger::after{content:none!important} 744 .yatoon-manage-wrap .sbs-language-flag{display:inline-flex!important;flex:0 0 21px;width:21px!important;height:21px!important;overflow:hidden;border-radius:50%;border:1px solid rgba(128,128,128,.22);box-sizing:border-box} 745 .yatoon-manage-wrap .sbs-language-flag svg{display:block;width:100%!important;height:100%!important;max-width:none!important} 746 .yatoon-manage-wrap .sbs-language-chevron{width:12px;height:12px;flex:0 0 12px}.yatoon-manage-wrap .sbs-language-picker[open] .sbs-language-chevron{transform:rotate(180deg)} 747 .yatoon-manage-wrap .sbs-language-panel{position:absolute;z-index:10004;right:0;top:calc(100% + 5px);box-sizing:border-box;width:min(220px,calc(100vw - 40px));max-height:65vh;overflow:auto;padding:5px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;box-shadow:0 8px 28px rgba(0,0,0,.16)} 748 .yatoon-manage-wrap .sbs-language-picker:not([open]) .sbs-language-panel{display:none!important} 749 .yatoon-manage-wrap .sbs-language-choice{display:flex!important;align-items:center;gap:9px;width:100%;min-height:42px;margin:0;padding:9px;border:0!important;border-radius:8px;background:transparent!important;color:#111827!important;box-shadow:none!important;font-family:inherit;font-size:13px;font-weight:500;line-height:1.4;text-align:left;text-transform:none;cursor:pointer} 750 .yatoon-manage-wrap .sbs-language-choice:hover,.yatoon-manage-wrap .sbs-language-choice[aria-current=true],.yatoon-manage-wrap .sbs-language-trigger:hover{background:#f3f4f6!important}.yatoon-manage-wrap .sbs-language-check{margin-left:auto}.yatoon-manage-wrap .sbs-language-trigger:focus-visible,.yatoon-manage-wrap .sbs-language-choice:focus-visible{outline:2px solid #2563eb;outline-offset:2px} -
yatoon-booking-system/tags/4.10.2/assets/css/manage-booking.min.css
r3767282 r3780965 1 1 /*! Yatoon Booking System 4.9.0 */.yatoon-manage-wrap{--yatoon-primary-light:#fdf2f8;--yatoon-text:#1f2937;--yatoon-radius:12px;color:var(--yatoon-text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;margin:0 auto;max-width:520px;padding:20px 16px 40px}.yatoon-manage-card{background:#fff;border:1px solid var(--yatoon-border);box-shadow:0 4px 24px rgba(0,0,0,.07)}.yatoon-manage-header{background:var(--yatoon-primary);color:#fff;padding:24px 28px 20px}.yatoon-manage-header h2{font-size:20px;font-weight:700}.yatoon-manage-subtitle{opacity:.85}.yatoon-manage-details{border-bottom:1px solid var(--yatoon-border);padding:20px 28px}.yatoon-manage-row{align-items:baseline;border-bottom:1px solid #f3f4f6;padding:7px 0}.ymr-label{flex:0 0 90px;letter-spacing:.04em;text-transform:uppercase}.yatoon-manage-actions{gap:12px;padding:24px 28px 4px}.yatoon-btn{border:2px solid transparent;border-radius:8px;font-size:14px;font-weight:600;padding:10px 20px;transition:all .15s}.yatoon-btn:disabled{opacity:.6}.yatoon-btn-primary:hover:not(:disabled){filter:brightness(1.1)}.yatoon-btn-outline{background:transparent;border-color:var(--yatoon-primary)}.yatoon-btn-ghost{background:transparent;border-color:var(--yatoon-border)}.yatoon-btn-ghost:hover:not(:disabled){background:#f9fafb}.yatoon-btn-sm{padding:7px 14px}.yatoon-reschedule-panel{background:#fafafa;border-top:1px solid var(--yatoon-border);padding:20px 28px}.yatoon-reschedule-panel h3{font-size:15px}.yatoon-reschedule-date-row{align-items:center;display:flex;flex-wrap:wrap;gap:10px;margin-bottom:16px}.yatoon-reschedule-date-row label{color:var(--yatoon-muted);font-size:13px;font-weight:600}.yatoon-reschedule-date-row input[type=date]{border:1.5px solid var(--yatoon-border);border-radius:7px;outline:none;padding:8px 10px}.yatoon-slots-list{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px}.yatoon-slot-chip{background:#fff;border:1.5px solid var(--yatoon-border);border-radius:20px;cursor:pointer;font-weight:600;padding:8px 14px;transition:all .15s}.yatoon-reschedule-confirm-row{display:flex;gap:10px;margin-top:4px}.yatoon-change-services-help{color:var(--yatoon-muted);font-size:13px;line-height:1.45;margin:-4px 0 14px}.yatoon-change-services-status{border-radius:10px;font-size:14px;line-height:1.5;margin:12px 0;padding:12px 14px}.yatoon-change-services-panel .yatoon-reschedule-confirm-row{flex-wrap:wrap}.yatoon-change-services-panel .yatoon-reschedule-confirm-row .yatoon-btn{flex:1 1 150px}.yatoon-service-change-row{align-items:center;display:grid;gap:10px;grid-template-columns:92px minmax(0,1fr);margin-bottom:12px}.yatoon-service-change-row label{color:var(--yatoon-muted);font-size:13px;font-weight:700}.yatoon-service-change-select,.yatoon-service-change-staff{background:#fff;border:1px solid var(--yatoon-border);border-radius:10px;color:var(--yatoon-text);font-size:14px;min-height:42px;padding:8px 10px;width:100%}.yatoon-service-change-staff-note{color:var(--yatoon-muted);font-size:12px;grid-column:2;margin-top:-4px}.yatoon-service-remove-row{background:#fff;border:1px solid var(--yatoon-border);border-radius:999px;color:#dc2626;cursor:pointer;font-weight:700;grid-column:2;min-height:38px;padding:7px 12px}.yatoon-manage-notice{border-radius:8px;margin:16px 28px;padding:12px 16px}.yatoon-notice-success{background:#d1fae5;color:#065f46}.yatoon-notice-warning{background:#fef3c7;color:#92400e}.yatoon-notice-info{color:#1e40af}.yatoon-manage-error{background:#fee2e2;border-radius:8px;color:#991b1b;padding:14px 18px}.yatoon-manage-footer{border-top:1px solid var(--yatoon-border);padding:16px 28px;text-align:center}.yatoon-after-cancel-actions{display:flex;flex-wrap:wrap;gap:10px;padding:0 28px 18px}.yatoon-after-cancel-actions .yatoon-btn{flex:1 1 180px;justify-content:center}@media (max-width:480px){.yatoon-manage-wrap{padding:12px 8px 32px}.yatoon-manage-actions,.yatoon-manage-details,.yatoon-manage-header,.yatoon-manage-notice,.yatoon-reschedule-panel{padding-left:18px;padding-right:18px}.yatoon-manage-actions{flex-direction:column}.yatoon-after-cancel-actions{flex-direction:column;padding-left:18px;padding-right:18px}.yatoon-btn{justify-content:center}.yatoon-service-change-row{grid-template-columns:1fr}.yatoon-service-change-staff-note,.yatoon-service-remove-row{grid-column:1}}.yatoon-manage-footer .yatoon-manage-return{color:var(--yatoon-text);display:inline-flex;text-decoration:none}.yatoon-manage-footer .yatoon-manage-return:hover{text-decoration:none}.yatoon-manage-wrap{--yatoon-border:#e5e7eb;--yatoon-radius:16px}.yatoon-manage-card{box-shadow:0 14px 36px rgba(15,23,42,.08)}.yatoon-manage-header h2{letter-spacing:0}.ymr-value{color:#111827}.yatoon-btn{border-width:1px;min-height:42px}.yatoon-btn-primary{box-shadow:0 10px 22px rgba(236,72,153,.16)}.yatoon-btn-ghost,.yatoon-btn-outline{background:#fff}.yatoon-reschedule-panel{background:#f8fafc}.yatoon-reschedule-date-row input[type=date]{border-width:1px;min-height:40px}.yatoon-reschedule-date-row input[type=date]:focus{box-shadow:0 0 0 3px rgba(236,72,153,.12)}.yatoon-slot-chip{border-width:1px}.yatoon-manage-wrap{--yatoon-primary:#ec4899;--yatoon-primary-light:rgba(236,72,153,.1);--yatoon-text:#111827;--yatoon-muted:#6b7280;--yatoon-border:rgba(0,0,0,.08);--yatoon-surface:#fff;--yatoon-surface2:#f8fafc;--yatoon-radius:20px;--yatoon-ease:cubic-bezier(.4,0,.2,1);-webkit-font-smoothing:antialiased;font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,Helvetica Neue,Arial,sans-serif}.yatoon-manage-card{background:var(--yatoon-surface);border:1px solid rgba(0,0,0,.08);border-radius:var(--yatoon-radius);box-shadow:0 16px 48px rgba(15,23,42,.11),inset 0 1px 0 hsla(0,0%,100%,.9);overflow:hidden}.yatoon-manage-header{background:#111827;padding:28px 30px 22px}.yatoon-manage-header h2{border:none;color:#fff;font-size:22px;font-weight:900;letter-spacing:-.03em;margin:0 0 4px}.yatoon-manage-subtitle{color:hsla(0,0%,100%,.65);font-size:13px;margin:0}.yatoon-manage-details{border-bottom:1px solid rgba(0,0,0,.06);padding:22px 30px}.yatoon-manage-row{align-items:flex-start;border-bottom:1px solid rgba(0,0,0,.05);display:flex;font-size:14px;gap:16px;justify-content:space-between;padding:8px 0;transition:background .15s}.yatoon-manage-row:last-child{border-bottom:none}.ymr-label{color:var(--yatoon-muted);flex:0 0 100px;font-size:12px;font-weight:700;letter-spacing:0;text-transform:none}.ymr-value{color:var(--yatoon-text);font-weight:600;text-align:right}.yatoon-manage-actions{display:flex;flex-wrap:wrap;gap:10px;padding:22px 30px 8px}.yatoon-btn{align-items:center;border:1px solid transparent;border-radius:999px;cursor:pointer;display:inline-flex;font-size:15px;font-weight:700;gap:6px;letter-spacing:-.01em;min-height:44px;padding:10px 22px;text-decoration:none;transition:all .18s var(--yatoon-ease)}.yatoon-btn:hover{transform:translateY(-1px)}.yatoon-btn:active{transform:scale(.97)}.yatoon-btn:disabled{cursor:not-allowed;opacity:.5;transform:none}.yatoon-btn-primary{background:var(--yatoon-primary);border-color:var(--yatoon-primary);box-shadow:0 6px 18px rgba(236,72,153,.25);color:#fff}.yatoon-btn-primary:hover:not(:disabled){box-shadow:0 10px 26px rgba(236,72,153,.32);filter:brightness(1.06)}.yatoon-btn-outline{background:var(--yatoon-surface);border-color:rgba(236,72,153,.3);color:var(--yatoon-primary)}.yatoon-btn-outline:hover:not(:disabled){background:var(--yatoon-primary-light);border-color:var(--yatoon-primary)}.yatoon-btn-ghost{background:var(--yatoon-surface);border-color:rgba(0,0,0,.12);box-shadow:0 1px 3px rgba(0,0,0,.06);color:var(--yatoon-muted)}.yatoon-btn-ghost:hover:not(:disabled){background:var(--yatoon-surface2);color:var(--yatoon-text)}.yatoon-btn-sm{font-size:13px;min-height:36px;padding:7px 16px}.yatoon-reschedule-panel{background:var(--yatoon-surface2);border-top:1px solid rgba(0,0,0,.07);padding:22px 30px}.yatoon-reschedule-panel h3{color:var(--yatoon-text);font-size:16px;font-weight:800;letter-spacing:-.015em;margin:0 0 16px}.yatoon-reschedule-date-row input[type=date]{background:var(--yatoon-surface);border:1px solid rgba(0,0,0,.14);border-radius:10px;font-size:14px;min-height:42px;transition:border-color .18s,box-shadow .18s}.yatoon-reschedule-date-row input[type=date]:focus{border-color:var(--yatoon-primary);box-shadow:0 0 0 4px rgba(236,72,153,.12);outline:none}.yatoon-slot-chip{background:var(--yatoon-surface);border:1px solid rgba(0,0,0,.1);border-radius:999px;box-shadow:0 1px 3px rgba(0,0,0,.06);color:var(--yatoon-text);font-size:13px;font-weight:700;padding:9px 16px;transition:all .15s var(--yatoon-ease)}.yatoon-slot-chip:hover{border-color:var(--yatoon-primary);box-shadow:0 3px 10px rgba(236,72,153,.15);color:var(--yatoon-primary);transform:translateY(-1px)}.yatoon-slot-chip.selected{background:var(--yatoon-primary);border-color:var(--yatoon-primary);box-shadow:0 4px 14px rgba(236,72,153,.28);color:#fff}.yatoon-manage-notice{border-radius:12px;font-size:14px;font-weight:500;line-height:1.5;margin:14px 30px;padding:13px 16px}.yatoon-notice-success{background:#dcfce7;border-left:3px solid #22c55e;color:#15803d}.yatoon-notice-error{background:#fee2e2;border-left:3px solid #ef4444;color:#991b1b}.yatoon-notice-warning{background:#fef9c3;border-left:3px solid #f59e0b;color:#a16207}.yatoon-notice-info{background:#eff6ff;border-left:3px solid #3b82f6;color:#1d4ed8}.yatoon-manage-footer{background:var(--yatoon-surface2);border-top:1px solid rgba(0,0,0,.06);color:var(--yatoon-muted);font-size:13px;padding:16px 30px}.yatoon-manage-footer a{color:var(--yatoon-primary);font-weight:600;text-decoration:none}.yatoon-manage-footer a:hover{text-decoration:underline}.yatoon-status-pending{color:#d97706;font-weight:700}.yatoon-status-confirmed{color:#059669;font-weight:700}.yatoon-status-completed{color:#6b7280;font-weight:700}.yatoon-status-cancelled,.yatoon-status-cancelled_by_customer{color:#dc2626;font-weight:700}.yatoon-cancel-choice{align-items:flex-start;cursor:pointer;display:inline-flex;gap:10px;justify-content:flex-end}.yatoon-cancel-choice input{flex:0 0 auto;margin-top:3px}.yatoon-cancel-choice span{display:block}@media (max-width:480px){.yatoon-manage-wrap{padding:10px 6px 28px}.yatoon-manage-actions,.yatoon-manage-details,.yatoon-manage-footer,.yatoon-manage-header,.yatoon-manage-notice,.yatoon-reschedule-panel{padding-left:18px;padding-right:18px}.yatoon-manage-actions{flex-direction:column}.yatoon-btn{justify-content:center}}#yatoon-after-cancel-actions.yatoon-after-cancel-actions{align-items:center;display:flex;flex-wrap:wrap;gap:10px;padding:0 30px 18px}#yatoon-after-cancel-actions.yatoon-after-cancel-actions .yatoon-btn{border-radius:14px;box-shadow:none;flex:1 1 180px;font-size:14px;height:auto;line-height:1.2;max-height:48px;min-height:44px;padding:10px 16px}#yatoon-manage-overlay :where(button,a,input,select,textarea,[tabindex]):focus-visible,.yatoon-manage-wrap :where(button,a,input,select,textarea):focus-visible{outline:3px solid #2563eb;outline-offset:3px}@media (prefers-reduced-motion:reduce){#yatoon-manage-overlay *,.yatoon-manage-wrap *{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important}}@media (max-width:480px){#yatoon-after-cancel-actions.yatoon-after-cancel-actions{flex-direction:column;padding-left:18px;padding-right:18px}#yatoon-after-cancel-actions.yatoon-after-cancel-actions .yatoon-btn{flex:0 0 auto;width:100%}}.yatoon-manage-wrap{box-sizing:border-box;min-width:0}.yatoon-manage-wrap .ymr-value{min-width:0;overflow-wrap:anywhere}.yatoon-manage-wrap .yatoon-manage-row{gap:14px}#yatoon-manage-overlay button,.yatoon-manage-wrap :is(.yatoon-btn,input:not([type=checkbox]),select,textarea){border-radius:12px;box-sizing:border-box;line-height:1.35;min-height:44px}.yatoon-manage-wrap .yatoon-btn{text-align:center;white-space:normal}@media(max-width:640px){.yatoon-manage-wrap :is(input:not([type=checkbox]),select,textarea){font-size:16px}.yatoon-manage-wrap .yatoon-manage-row{align-items:flex-start}.yatoon-manage-wrap .ymr-label{flex-basis:85px}}.yatoon-manage-wrap #yatoon-reschedule-btn{background:#15803d!important;border-color:#15803d!important;color:#fff!important}.yatoon-manage-wrap #yatoon-change-services-btn{background:#1d4ed8!important;border-color:#1d4ed8!important;color:#fff!important}.yatoon-manage-wrap #yatoon-cancel-btn{background:#b91c1c!important;border-color:#b91c1c!important;color:#fff!important}.yatoon-manage-wrap #yatoon-reschedule-btn:hover{background:#166534!important}.yatoon-manage-wrap #yatoon-change-services-btn:hover{background:#1e40af!important}.yatoon-manage-wrap #yatoon-cancel-btn:hover{background:#991b1b!important}.yatoon-manage-wrap .yatoon-slot-chip{background:#fff!important;border:1px solid #cbd5e1!important;color:#111827!important;min-height:44px}.yatoon-manage-wrap .yatoon-slot-chip:hover{background:#f1f5f9!important}.yatoon-manage-wrap .yatoon-slot-chip.selected{background:#fce7f3!important;border:2px solid #be185d!important;color:#111827!important}.yatoon-manage-wrap .yatoon-manage-rebook{margin:0;padding:0 30px 18px}.yatoon-manage-wrap .yatoon-rebook-btn{background:#15803d!important;border-color:#15803d!important;color:#fff!important;justify-content:center;min-height:44px!important;text-decoration:none!important}.yatoon-manage-wrap .yatoon-rebook-btn:hover{background:#166534!important}@media(max-width:480px){.yatoon-manage-wrap .yatoon-manage-rebook{padding-inline:18px}.yatoon-manage-wrap .yatoon-rebook-btn{width:100%}} 2 3 /* Customer appointment management language menu. */ 4 .yatoon-manage-wrap .sbs-header-language{margin:0;position:relative;font-family:inherit} 5 .yatoon-manage-wrap .sbs-language-picker{position:relative;margin:0;padding:0;border:0} 6 .yatoon-manage-wrap .sbs-language-trigger{display:flex;align-items:center;gap:6px;min-height:40px;padding:7px 9px;border:0;border-radius:999px;background:transparent;color:#111827;font-family:inherit;font-size:13px;font-weight:600;line-height:1.4;cursor:pointer;list-style:none} 7 .yatoon-manage-wrap .sbs-language-trigger::-webkit-details-marker{display:none}.yatoon-manage-wrap .sbs-language-trigger::marker{content:''}.yatoon-manage-wrap .sbs-language-trigger::before,.yatoon-manage-wrap .sbs-language-trigger::after{content:none!important} 8 .yatoon-manage-wrap .sbs-language-flag{display:inline-flex!important;flex:0 0 21px;width:21px!important;height:21px!important;overflow:hidden;border-radius:50%;border:1px solid rgba(128,128,128,.22);box-sizing:border-box} 9 .yatoon-manage-wrap .sbs-language-flag svg{display:block;width:100%!important;height:100%!important;max-width:none!important} 10 .yatoon-manage-wrap .sbs-language-chevron{width:12px;height:12px;flex:0 0 12px}.yatoon-manage-wrap .sbs-language-picker[open] .sbs-language-chevron{transform:rotate(180deg)} 11 .yatoon-manage-wrap .sbs-language-panel{position:absolute;z-index:10004;right:0;top:calc(100% + 5px);box-sizing:border-box;width:min(220px,calc(100vw - 40px));max-height:65vh;overflow:auto;padding:5px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;box-shadow:0 8px 28px rgba(0,0,0,.16)} 12 .yatoon-manage-wrap .sbs-language-picker:not([open]) .sbs-language-panel{display:none!important} 13 .yatoon-manage-wrap .sbs-language-choice{display:flex!important;align-items:center;gap:9px;width:100%;min-height:42px;margin:0;padding:9px;border:0!important;border-radius:8px;background:transparent!important;color:#111827!important;box-shadow:none!important;font-family:inherit;font-size:13px;font-weight:500;line-height:1.4;text-align:left;text-transform:none;cursor:pointer} 14 .yatoon-manage-wrap .sbs-language-choice:hover,.yatoon-manage-wrap .sbs-language-choice[aria-current=true],.yatoon-manage-wrap .sbs-language-trigger:hover{background:#f3f4f6!important}.yatoon-manage-wrap .sbs-language-check{margin-left:auto}.yatoon-manage-wrap .sbs-language-trigger:focus-visible,.yatoon-manage-wrap .sbs-language-choice:focus-visible{outline:2px solid #2563eb;outline-offset:2px} -
yatoon-booking-system/tags/4.10.2/assets/js/frontend-checkout.js
r3780403 r3780965 988 988 }) 989 989 .catch(function(error) { 990 // 4.10.2: the Stripe form could not open, so nothing was charged. 991 // On the first appointment, let the customer simply try again. 992 if (idx === 0 && error && error.data && error.data.preflight) { 993 self._showToast(error.message || __('Stripe payment could not be started.'), 'error'); 994 restoreSubmitButtons(); 995 return; 996 } 990 997 self._showBookingRecovery({reference:payload.client_reference,failedIndex:idx,message:error.message,uncertain:true}); 991 998 self._showToast(error && error.message ? error.message : __('Stripe payment could not be started.'), 'error'); -
yatoon-booking-system/tags/4.10.2/assets/js/frontend-checkout.min.js
r3780403 r3780965 1 !function(e,t){"use strict";const o=e.wp?.i18n?.__?t=>e.wp.i18n.__(t,"yatoon-booking-system"):e=>e,{ysSiteNow:n,ysSiteOffsetMin:s,ysFormatMoney:a,ysPriceVaries:i,ysMoneyFrom:r,ysCalcDeposit:c,validateBookingPhone:d,validateUSPhone:l,showFieldError:u,showPhoneError:m,validateCustomerName:g,validateCustomerEmail:f,ysFocusTrap:p}=e.YatoonBookingHelpers;class _{_paidCheckoutKey(e){return"yatoon-checkout:"+location.pathname+":"+e}_forgetPaidCheckout(e){if(e)try{sessionStorage.removeItem(this._paidCheckoutKey(e))}catch(e){}}_unresolvedPaidCheckout(e){const t=this._paidCheckoutKey("");try{for(let o=0;o<sessionStorage.length;o++){const n=sessionStorage.key(o);if(!n||0!==n.indexOf(t))continue;const s=n.slice(t.length);if(!s||s===e)continue;const a=JSON.parse(sessionStorage.getItem(n)||"null");if(a&&a.payment&&a.payment.id&&!a.resolved)return s}}catch(e){}return""}_showPaidRecoveryNotice(e,n){const s=this,a=t("#sbs-booking-recovery");a.length&&(a.addClass("sbs-booking-recovery-paid"),a.find("h3").first().text(o("Payment received, appointment not confirmed yet")),a.find(".sbs-booking-recovery-guidance").text(o('Your payment went through, but this appointment could not be confirmed. Please do not pay again. Use "Check payment and appointment status" to finish it, or contact the salon with the reference below so they can confirm another time or refund you.')),n&&!a.find(".sbs-paid-recovery-resolved").length&&t("<button/>",{type:"button",class:"sbs-paid-recovery-resolved",text:o("The salon has resolved this payment")}).appendTo(a.find(".sbs-booking-recovery-actions")).on("click",function(){try{const t=s._paidCheckoutKey(e),o=JSON.parse(sessionStorage.getItem(t)||"null");o&&(o.resolved=!0,sessionStorage.setItem(t,JSON.stringify(o)))}catch(e){}s._clearBookingRecovery(),s._saveSession()}))}submitBooking(){const n=this;if(this._handleBookingRecoveryAttempt())return;if(this._paymentsConfigured()&&"function"!=typeof this._ensurePaymentSdk){if(this._submissionChunkPromise)return;const e=t(".sbs-btn-submit").prop("disabled",!0).text(o("Loading secure payment..."));return void(this._submissionChunkPromise=this._loadFeatureChunk("payments").then(function(){n._submissionChunkPromise=null,e.prop("disabled",!1),n._applyConfirmBtn(),n.submitBooking()}).catch(function(t){n._submissionChunkPromise=null,e.prop("disabled",!1),n._applyConfirmBtn(),n._showToast(t.message||o("The secure payment component could not be loaded."),"error")}))}if(this._isSubmitting)return;if(this.designUploadInProgress)return void this._showToast(o("Please wait for the reference photo to finish uploading."),"info");if(!this._paymentsConfigured()&&(!this._turnstileTokenFetched||Date.now()>(this._turnstileTokenExpires||0))&&"function"==typeof e.yatoonGetTurnstileToken)return this._turnstileTokenFetched=!0,void e.yatoonGetTurnstileToken().then(function(t){e.yatoonTurnstileToken=t,n._turnstileTokenFetched=!0,n._turnstileTokenExpires=Date.now()+9e4,n.submitBooking()}).catch(function(){n._turnstileTokenFetched=!1,n._turnstileTokenExpires=0,n._showToast(o("Verification could not finish. Please try again."),"error")});const s=document.getElementById("sbs-otp-section"),a="undefined"!=typeof yatoonData&&"1"===yatoonData.verifyEmailOtp,i="undefined"!=typeof yatoonData&&"1"===yatoonData.verifySmsOtp;if(s&&(a||i)){const e=(document.getElementById("sbs-customer-email")||{}).value||"",t=(document.getElementById("sbs-customer-phone")||{}).value||"",a=e.trim()+"|"+t.trim();s.dataset.sentContact&&s.dataset.sentContact!==a&&(s.dataset.sent="",s.dataset.sentContact="");const r="1"===s.dataset.verified&&s.dataset.verifiedContact===a;"1"!==s.dataset.verified||r||(s.dataset.verified="",s.dataset.verifiedKey="");const c=function(e){const t=String(e||"").replace(/\D/g,"");return 11===t.length&&"1"===t.charAt(0)?t.slice(1):t},l=i?""!==c(s.dataset.verifiedPhone)&&c(t)===c(s.dataset.verifiedPhone):!!s.dataset.verifiedEmail&&e.trim().toLowerCase()===s.dataset.verifiedEmail.toLowerCase(),g=s.dataset.deviceVerified===a;if(!r&&!l&&!g){const r=f(e);if(r){u("sbs-customer-email",r);const e=document.getElementById("sbs-customer-email");return void(e&&e.scrollIntoView({behavior:"smooth",block:"center"}))}if(i){const e=d(t);if(e){m(e);const t=document.getElementById("sbs-phone-display")||document.getElementById("sbs-customer-phone");return void(t&&t.scrollIntoView({behavior:"smooth",block:"center"}))}}if(s.dataset.deviceChecked!==a)return void jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_otp_device_check",nonce:yatoonData.nonce,email:e,phone:t},function(e){s.dataset.deviceChecked=a,e&&e.success&&e.data&&e.data.verified&&(s.dataset.deviceVerified=a),n.submitBooking()}).fail(function(){s.dataset.deviceChecked=a,n.submitBooking()});const c=(document.getElementById("sbs-customer-name")||{}).value||"",l=i?"sms":"email";s.style.display="block";const g=document.getElementById("sbs-otp-remember");if(g&&"1"===g.dataset.regionAuto&&!g.dataset.regionChecked){g.dataset.regionChecked="1";let e="";try{e=Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch(t){e=""}const t=/^Europe\/(Moscow|Minsk|Kaliningrad|Samara|Volgograd|Kirov|Astrakhan|Saratov|Ulyanovsk|Simferopol|Istanbul|Kiev|Kyiv|Uzhgorod|Zaporozhye|Chisinau|Tirane|Skopje|Sarajevo|Belgrade|Podgorica)$/;(/^Europe\//.test(e)&&!t.test(e)||/^Atlantic\/(Reykjavik|Madeira|Azores|Canary)$/.test(e))&&(g.checked=!1)}if(document.getElementById("sbs-otp-prompt").textContent="sms"===l?o("We are sending a verification code to your phone. Please enter it below."):o("We are sending a verification code to")+" "+e+". "+o("Please enter it below."),!s.dataset.sent){s.dataset.sent="1",s.dataset.sentContact=a;const n=document.getElementById("sbs-otp-msg"),i=document.getElementById("sbs-otp-resend-btn");n&&(n.textContent=o("Sending verification code..."),n.style.color=""),i&&(i.disabled=!0),jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_send_otp",nonce:yatoonData.nonce,channel:l,email:e,phone:t,name:c},function(e){const t=!(!e||!e.success);n&&(n.textContent=t?e.data&&e.data.message?e.data.message:o("Verification code sent."):e&&e.data&&e.data.message?e.data.message:o("Failed to send code.")),i&&(i.style.display=""),i&&(i.disabled=!1),t||(s.dataset.sent="",s.dataset.sentContact="",n&&(n.style.color="#dc2626"))}).fail(function(){s.dataset.sent="",s.dataset.sentContact="",n&&(n.textContent=o("Could not send the verification code. Please try again."),n.style.color="#dc2626"),i&&(i.style.display="",i.disabled=!1)})}const p=document.getElementById("sbs-otp-verify-btn");p&&!p.dataset.bound&&(p.dataset.bound="1",p.addEventListener("click",function(){const e=(document.getElementById("sbs-otp-input")||{}).value||"",t=document.getElementById("sbs-otp-msg"),a=(document.getElementById("sbs-customer-email")||{}).value||"",i=(document.getElementById("sbs-customer-phone")||{}).value||"",r=a.trim()+"|"+i.trim();e.trim()?(p.disabled=!0,p.dataset.pending="1",t&&(t.textContent=o("Verifying..."),t.style.color=""),jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_verify_otp",nonce:yatoonData.nonce,channel:l,email:a,phone:i,code:e,remember:document.getElementById("sbs-otp-remember")&&document.getElementById("sbs-otp-remember").checked?1:0},function(e){e.success?(s.dataset.verified="1",s.dataset.verifiedKey=e.data&&e.data.verified_key?e.data.verified_key:"",n._giftSubmissionQuote=null,n._dynamicQuoteKey="",s.dataset.verifiedContact=r,s.style.display="none",n.submitBooking()):(t&&(t.textContent=e.data&&e.data.message?e.data.message:o("Incorrect code.")),t&&(t.style.color="#dc2626"),p.disabled=!1,p.dataset.pending="")}).fail(function(){t&&(t.textContent=o("Could not verify the code. Please try again."),t.style.color="#dc2626"),p.disabled=!1,p.dataset.pending=""})):t&&(t.textContent=o("Enter the verification code first."),t.style.color="#dc2626")}));const _=document.getElementById("sbs-otp-resend-btn");return void(_&&!_.dataset.bound&&(_.dataset.bound="1",_.addEventListener("click",function(){if(_.disabled)return;s.dataset.sent="",s.dataset.sentContact="",s.dataset.verified="",s.dataset.verifiedKey="",s.dataset.verifiedContact="";const e=document.getElementById("sbs-otp-msg");e&&(e.textContent=""),n.submitBooking()})))}}if(this._isSubmitting=!0,this._clearBookingRecovery(),0===this.bookingCart.length&&this.selectedDateTime&&(this.pendingServices.length>0||this.selectedService)&&this.addToCart(),0===this.bookingCart.length)return this._isSubmitting=!1,void this._showToast(o("Please add at least one service to your booking."),"error");const r=t(".sbs-btn-submit"),c=t("#sbs-cart-next-btn"),l=t("#sbs-sidebar-next-btn"),g=r.text(),p=c.text(),_=l.text(),h=()=>{this._isSubmitting=!1,this._turnstileTokenFetched=!1,r.prop("disabled",!1).text(g),c.prop("disabled",!1).removeClass("sbs-submitting").text(p||o("Confirm Booking")),l.prop("disabled",!1).removeClass("sbs-submitting").text(_||o("Confirm Booking")),this._applyConfirmBtn(),this._updateMobileCartBar()};r.prop("disabled",!0).text(o("Confirming your booking...")),c.prop("disabled",!0).addClass("sbs-submitting").text("CONFIRMING..."),l.prop("disabled",!0).addClass("sbs-submitting").text("CONFIRMING..."),this._updateLegalBoxes();const y={customer_name:t("#sbs-customer-name").val(),customer_email:t("#sbs-customer-email").val(),customer_phone:t("#sbs-customer-phone").val(),client_timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||"",notes:t("#sbs-customer-notes").val(),coupon_code:t("#sbs-coupon-code").length?t("#sbs-coupon-code").val():"",marketing_email_optin:t("#sbs-marketing-email-optin").is(":checked")?1:0,marketing_sms_optin:t("#sbs-marketing-sms-optin").is(":checked")?1:0,consent_accepted:t("#sbs-consent-accepted").length&&t("#sbs-consent-accepted").is(":checked")?1:0,consent_signature:t("#sbs-consent-signature").length?t("#sbs-consent-signature").val():"",policy_acknowledged:t("#sbs-policy-acknowledged").length&&t("#sbs-policy-acknowledged").is(":checked")?1:0,tip_amount:parseFloat(t("#sbs-tip-amount").val())||0,gift_card_code:t("#sbs-gift-card-code-confirmed").val()||"",custom_fields:function(){const e={};return t('[name^="cf["]').each(function(){const o=t(this).attr("name").replace(/^cf\[|\]$/g,"");t(this).is(":checkbox")||t(this).is(":radio")?t(this).is(":checked")&&(e[o]=t(this).val()):e[o]=t(this).val()}),JSON.stringify(e)}()},b=this._collectGuestContacts(),k=f(y.customer_email);if(k)return h(),u("sbs-customer-email",k),void(document.getElementById("sbs-customer-email")&&document.getElementById("sbs-customer-email").scrollIntoView({behavior:"smooth",block:"center"}));"undefined"!=typeof yatoonData&&yatoonData.phoneMode&&yatoonData.phoneMode;if(y.customer_phone){const e=d(y.customer_phone);if(e)return h(),m(e),void(document.getElementById("sbs-customer-phone")&&document.getElementById("sbs-customer-phone").scrollIntoView({behavior:"smooth",block:"center"}))}if(this._needsPolicyAck()&&!y.policy_acknowledged)return h(),this._showToast(o("Please review and acknowledge the cancellation / no-show policy before booking."),"error"),void this._focusBookingValidation(t("#sbs-policy-acknowledged"),t(".sbs-policy-box:visible").first());if(this._needsConsent()&&(!y.consent_accepted||!y.consent_signature.trim())){h(),this._showToast(o("Please read and sign the consent form before booking."),"error");const e=y.consent_accepted?t("#sbs-consent-signature"):t("#sbs-consent-accepted");return void this._focusBookingValidation(e,t(".sbs-consent-box:visible").first())}const v=this.bookingCart.slice(),C=[],w=JSON.stringify(v.map(e=>({start:e.dateTime&&e.dateTime.start_at,guest:e.guestLabel||"Me",services:(e.services||[{service:e.service,options:e.options,staff:e.staff}]).map(t=>({service:t.service&&t.service.id,options:(t.options||[]).map(e=>e.id),staff:t.staff&&t.staff.id||0,guest:t.guestLabel||e.guestLabel||"Me"}))}))),T=this._newBookingReference(w), I="undefined"!=typeof yatoonData&&(yatoonData.ajax_url||yatoonData.ajaxUrl)?yatoonData.ajax_url||yatoonData.ajaxUrl:"";if(!I)return h(),void this._showToast(o("Booking could not start because the WordPress AJAX URL is missing. Please refresh and try again."),"error");if(!v.length)return h(),void this._showToast(o("Please choose a service and time before confirming."),"error");const S=v.some(e=>e&&e.services&&e.services.length>1),P=v.length>1||S?"yatoon-"+T:"";let x=this.designUploadAttachmentId||0,B=this.designUploadToken||"";const D=o=>{const s=v[o],a=s.services||[{service:s.service,options:s.options,staff:s.staff}],i=s.dateTime&&s.dateTime.staff_map?s.dateTime.staff_map:null,r="string"==typeof i?function(){try{return JSON.parse(i)}catch(e){return null}}():i,c={},d={};a.forEach(function(e,t){const o=void 0!==e._originalIndex?e._originalIndex:t;s.dateTime.local_staff_map&&Number(s.dateTime.local_staff_map[o])>0&&(d[t]=Number(s.dateTime.local_staff_map[o])),r&&void 0!==r[o]&&(c[t]=r[o])});const l=Object.keys(c).length?JSON.stringify(c):i?"string"==typeof i?i:JSON.stringify(i):"",u=s.guestLabel||a[0]&&a[0].guestLabel||"Me",m=b[u]||{};let g=y.notes||"";if("Me"!==u){const e=[`Guest: ${u}`];m.name&&e.push(`Name: ${m.name}`),m.phone&&e.push(`Phone: ${m.phone}`),g=`${g}${g?"\n\n":""}${e.join(" - ")}`}const f={},p=new Date(s.dateTime.start_at).getTime(),_=a.map(e=>{const t=e.guestLabel||s.guestLabel||"Me",o=f[t]||0,a=Number.isFinite(p)?new Date(p+6e4*o).toISOString():s.dateTime.start_at;return f[t]=o+n._serviceDuration(e),{service_id:e.service.id,staff_id:e.staff?e.staff.id:0,gender_preference:n._genderPreferenceFor(e),option_ids:e.options.map(e=>e.id),guest_label:t,start_at:a,design_attachment_id:parseInt(e.designAttachmentId||0,10)||0,design_upload_token:String(e.designUploadToken||"")}});return{action:"yatoon_create_booking",nonce:yatoonData.nonce,client_reference:`${T}-${o+1}`,start_at:s.dateTime.start_at,local_staff_map_json:JSON.stringify(d),staff_map_json:l,services_json:JSON.stringify(_),service_id:a[0].service.id,staff_id:a[0].staff?a[0].staff.id:0,gender_preference:n._genderPreferenceFor(a[0]),selected_options:a[0].options.map(e=>e.id),notes:g,guest_label:u,guest_name:m.name||"",guest_phone:m.phone||"",booking_group_id:P,coupon_code:y.coupon_code,tip_amount:0===o?y.tip_amount:0,gift_card_code:n._giftSubmissionQuote?.cart[o]?.gift_card_amount>0?y.gift_card_code||n._giftCode:"",gift_card_amount:n._giftSubmissionQuote?.cart[o]?.gift_card_amount||0,custom_fields:y.custom_fields,customer_name:y.customer_name,customer_email:y.customer_email,customer_phone:y.customer_phone,otp_channel:"undefined"!=typeof yatoonData&&"1"===yatoonData.verifySmsOtp?"sms":"email",otp_verified_key:document.getElementById("sbs-otp-section")&&document.getElementById("sbs-otp-section").dataset.verifiedKey?document.getElementById("sbs-otp-section").dataset.verifiedKey:"",marketing_email_optin:y.marketing_email_optin,marketing_sms_optin:y.marketing_sms_optin,consent_accepted:y.consent_accepted,consent_signature:y.consent_signature,policy_acknowledged:y.policy_acknowledged,client_timezone:y.client_timezone,design_attachment_id:x||"",design_upload_token:B||"",website:t("#sbs-website").val()||"",form_rendered_at:t("#sbs-form-rendered-at").val()||"",cf_turnstile_response:void 0!==e.yatoonTurnstileToken?e.yatoonTurnstileToken:"",yatoon_test_booking:t(".sbs-booking-container").hasClass("yatoon-test-mode")?"1":""}},E=()=>{v.length<2||!n._paymentsConfigured()?F(0):n._loadFeatureChunk("recovery").then(async()=>{for(let e=0;e<v.length;e++)try{await n._prepareCheckout(D(e))}catch(t){throw t.cartIndex=e,t}}).then(()=>F(0)).catch(e=>{const t=e&&"number"==typeof e.cartIndex?e.cartIndex:0;if(e&&e.data&&e.data.preflight)return n._showToast(e.message,"error"),void h();n._showBookingRecovery({reference:`${T}-${t+1}`,failedIndex:t,confirmedCount:0,message:e&&e.message||o("This appointment is no longer available. Please choose another time."),uncertain:!1}),h()})},F=s=>{if(s>=v.length){if(C.every(e=>e&&e.success)){const s=C.find(e=>e&&e.success&&e.data&&e.data.woocommerce_checkout_url);if(s&&s.data.woocommerce_checkout_url)return this.bookingConfirmed=!0,this._clearSession(),void e.location.assign(s.data.woocommerce_checkout_url);this.bookingConfirmed=!0,t(".sbs-form-step").removeClass("active"),t(".sbs-step-success").show(),this._updateStepAccordion(),this._markBookingFlowComplete(),t("#sbs-success-count").text(v.length);const a=1!==v.length;t("#sbs-success-booking-word").text(o(a?"Bookings":"Booking"));const i=this._confirmedBookingItems(v,C);this._renderSuccessBookingSummary(i);const r=C.filter(e=>e&&e.success&&e.data&&e.data.manage_url&&String(e.data.manage_url).length),d=r.length&&r[0].data?r[0].data.manage_url:"",u=C.find(e=>e&&e.success&&e.data&&e.data.calendar_url&&String(e.data.calendar_url).length),m=u&&u.data?u.data.calendar_url:"",g=yatoonData.portalUrl||"",f=yatoonData.portalLabel||o("My Appointments"),p=t("#sbs-success-actions").empty();if(t("<div/>",{class:"sbs-success-action-note",text:yatoonData.successNote||o("Your appointment is booked. Save this page or use the manage link below if you need to change services, reschedule, or cancel.")}).appendTo(p),d&&1===r.length&&t("<a/>",{class:"sbs-success-action-link primary",href:d,target:"_blank",rel:"noopener",text:"undefined"!=typeof yatoonData&&yatoonData.isPro?o("Change services, reschedule, or cancel"):o("Reschedule or cancel")}).appendTo(p),r.length>1){const e=t("<div/>",{class:"sbs-success-manage-list"}).appendTo(p),n=v.some(e=>e.guestLabel&&"Me"!==e.guestLabel);r.forEach((s,a)=>{const i=v[a],r=i&&i.guestLabel&&"Me"!==i.guestLabel?i.guestLabel:null;let c;if(r)c=o("Change or cancel for")+" "+r;else if(n)c=o("Change or cancel my appointment");else{const e=s.data&&s.data.service_name?s.data.service_name:o("Appointment")+" "+(a+1);c=o("Change or cancel:")+" "+e}t("<a/>",{class:"sbs-success-action-link compact",href:s.data.manage_url,target:"_blank",rel:"noopener",text:c}).appendTo(e)})}if(m&&!t("#sbs-success-cal-row").length&&t("<a/>",{class:"sbs-success-action-link",href:m,text:o("Add to calendar")}).appendTo(p),g&&t("<a/>",{class:"sbs-success-action-link",href:g,text:f}).appendTo(p),t("<button/>",{type:"button",class:"sbs-success-action-link sbs-success-book-again"+(d?"":" primary"),text:o("Book again")}).appendTo(p),p.show(),m){t("#sbs-cal-ics").attr("href",m);const e=C.find(e=>e&&e.success&&e.data&&(e.data.start_at||e.data.start_time)),n=i[0]||null,s=n&&n.dateTime?n.dateTime.start_at:"",a=n?this._getItemVisitDuration(n):0,r=s?new Date(s):null,c=r&&!isNaN(r.getTime())&&a?new Date(r.getTime()+6e4*a).toISOString():"",d=e&&e.data&&(e.data.start_at||e.data.start_time)||s,l=e&&e.data&&(e.data.end_at||e.data.end_time)||c;if(d&&l){const e=function(e){const t=new Date(e);return isNaN(t.getTime())?"":t.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"Z")},s=(n?n.services||[{service:n.service}]:[]).map(e=>e.service&&e.service.name).filter(Boolean).join(", "),a=encodeURIComponent((yatoonData.businessName||o("Appointment"))+(s?" - "+s:"")),i=encodeURIComponent(e(d)),r=encodeURIComponent(e(l)),c=encodeURIComponent(yatoonData&&yatoonData.siteTimezone?yatoonData.siteTimezone:Intl.DateTimeFormat().resolvedOptions().timeZone);i&&r?t("#sbs-cal-google").attr("href","https://calendar.google.com/calendar/render?action=TEMPLATE&text="+a+"&dates="+i+"/"+r+"&ctz="+c):t("#sbs-cal-google").attr("href",m)}else t("#sbs-cal-google").attr("href",m);t("#sbs-success-cal-row").show()}yatoonData.rebookingNudgeText&&(t("#sbs-rebooking-nudge .sbs-rebooking-text").text(yatoonData.rebookingNudgeText),t("#sbs-rebooking-nudge .sbs-rebooking-btn").text(yatoonData.rebookingNudgeBtn||o("Book next visit")),setTimeout(function(){t("#sbs-rebooking-nudge").fadeIn(400)},1200));const _=C.find(e=>e&&e.success&&e.data&&e.data.booking_id);if(_&&_.data.manage_token&&t("#sbs-recurring-setup").length){const e=_.data.booking_id,n=_.data.manage_token;let s=2;setTimeout(function(){t("#sbs-recurring-setup").fadeIn(400)},2e3),t(document).on("click",".sbs-freq-btn",function(){t(".sbs-freq-btn").removeClass("active"),t(this).addClass("active"),s=parseInt(t(this).data("weeks"))}),t(document).on("click","#sbs-recurring-confirm",function(){const a=t(this).prop("disabled",!0).text(o("Setting up...")),i=parseInt(t("#sbs-recurring-count").val())||6;t.post(ajaxurl,{action:"yatoon_setup_recurring",nonce:yatoonData.nonce,yatoon_location_id:parseInt(yatoonData.locationId||0,10),booking_id:e,manage_token:n,frequency_weeks:s,total_count:i},function(e){const n=t("#sbs-recurring-result");e.success?(a.text(o("Done")),n.removeClass("error").text(e.data.message).show()):(a.prop("disabled",!1).text(o("Try again")),n.addClass("error").text(e.data&&e.data.message||o("Could not set up recurring.")).show())}).fail(function(){a.prop("disabled",!1).text(o("Try again")),t("#sbs-recurring-result").addClass("error").text(o("Network error. Please try again.")).show()})})}n.bookingCart=[],n.pendingServices=[],n._clearSession(),n._clearBookingRecovery(),n._bookingAttemptReference="",n._bookingAttemptFingerprint="",n._giftCode="",n._giftSubmissionQuote=null,t("#sbs-gift-card-code-confirmed").val(""),n._hideMobileCartBar(),n._closeDrawer(),n._isSubmitting=!1,h(),c.hide(),l.hide()}else{const e=C.filter(e=>!e||!e.success),t=e.map(e=>e&&e.data&&e.data.message?e.data.message:"").filter(Boolean).join(" "),s=t?`\n\nDetails: ${t}`:"",a=C.length-e.length;n._showToast(`${a} booking(s) confirmed, but ${e.length} failed. Please contact us.${s}`,"error");const i=e[0]&&e[0].data?e[0].data:{};n._showBookingRecovery({reference:i.reference||T,failedIndex:a,confirmedCount:a,message:t||o("One or more appointments were not confirmed."),safeToRetry:!0===i.retry_safe}),h()}return}const a=D(s),i=document.getElementById("sbs-design-reference"),r=i&&i.files&&i.files[0]?i.files[0]:null;let d=a,u=!0,m="application/x-www-form-urlencoded; charset=UTF-8";r&&!x&&(d=new FormData,Object.keys(a).forEach(function(e){const t=a[e];Array.isArray(t)?t.forEach(function(t){d.append(e+"[]",t)}):d.append(e,t)}),d.append("design_reference",r),u=!1,m=!1);const g=function(){t.ajax({url:I,type:"POST",timeout:9e4,data:d,processData:u,contentType:m,success:function(e,i,r){try{if("string"==typeof e){const t=e.indexOf("{"),o=e.lastIndexOf("}"),n=t>=0&&o>t?e.slice(t,o+1):e;e=JSON.parse(n)}if(C.push(e),!e||!e.success){const t=e&&e.data&&e.data.message?e.data.message:"",i=t?`\n\nDetails: ${t}`:"",r=C.length-1;n._showToast(`${r} booking(s) confirmed, but appointment ${s+1} failed. Please contact us.${i}`,"error");const c=e&&e.data?e.data:{},l=!!function(){const e=["deposit_intent_id","paypal_order_id","square_payment_id"];for(let t=0;t<e.length;t++){const o=d instanceof FormData?d.get(e[t]):d[e[t]];if(o)return String(o)}return""}();return n._showBookingRecovery({reference:a.client_reference||c.reference||`${T}-${s+1}`,failedIndex:s,confirmedCount:r,message:t||o("The appointment was not confirmed."),safeToRetry:!0===c.retry_safe&&!l,uncertain:!0===c.outcome_uncertain||l}),l&&n._showPaidRecoveryNotice(a.client_reference),void h()}n._forgetPaidCheckout(a.client_reference),e.data&&e.data.design_attachment_id&&(x=parseInt(e.data.design_attachment_id,10)||x,n.designUploadAttachmentId=x),e.data&&e.data.design_upload_token&&(B=String(e.data.design_upload_token||""),n.designUploadToken=B),F(s+1)}catch(a){if(console.error(o("Yatoon booking submit failed after server response:"),a),n.bookingConfirmed||t(".sbs-step-success:visible").length>0)return;const i=r&&r.responseText?String(r.responseText):"string"==typeof e?e:"";if(i&&-1!==i.indexOf('"success":true'))return C.push({success:!0,data:{}}),void F(s+1);n._showToast(o("We could not read the booking confirmation response. Please check the booking list before trying again."),"error"),n._showBookingRecovery({reference:`${T}-${s+1}`,failedIndex:s,confirmedCount:C.filter(e=>e&&e.success).length,message:o("We could not verify the server response."),uncertain:!0}),h()}},error:function(e,t){C.push({success:!1});const a=C.length-1,i="timeout"===t?"the request timed out":"a network error";n._showToast(`${a} booking(s) confirmed, but appointment ${s+1} failed due to ${i}. Please contact us.`,"error"),n._showBookingRecovery({reference:`${T}-${s+1}`,failedIndex:s,confirmedCount:a,message:o("timeout"===t?"The request timed out.":"The network connection was interrupted."),uncertain:!0}),h()}})},f=function(){const e=(e,t)=>{n._rememberCheckoutPayment&&n._rememberCheckoutPayment(a.client_reference,e,t),n._giftSubmissionQuote&&(n._giftSubmissionQuote.payments=n._giftSubmissionQuote.payments||{},n._giftSubmissionQuote.payments[s]={field:e,id:t},n._saveSession())},t=n._checkoutSavedPayment||n._giftSubmissionQuote?.payments?.[s];n._checkoutSavedPayment=null;const i=t?"":n._unresolvedPaidCheckout(a.client_reference);if(i)return n._showBookingRecovery({reference:i,failedIndex:s,confirmedCount:s,message:o("A payment for an earlier attempt was received, but that appointment is not confirmed yet."),uncertain:!0}),n._showPaidRecoveryNotice(i,!0),void h();t?(d instanceof FormData?d.set(t.field,t.id):d[t.field]=t.id,g()):a.gift_card_code&&0===n._giftSubmissionQuote?.cart[s]?.amount_due?g():n._squarePreparedPaymentId&&n._squarePreparedPaymentReference===a.client_reference?(e("square_payment_id",n._squarePreparedPaymentId),d instanceof FormData?d.set("square_payment_id",n._squarePreparedPaymentId):d.square_payment_id=n._squarePreparedPaymentId,n._squarePreparedPaymentId="",n._squarePreparedPaymentReference="",g()):n._paymentProviderEnabled("square")?n._ensurePaymentSdk("square").then(function(){return n._createSquarePaymentForPayload(a)}).then(function(t){e("square_payment_id",t),d instanceof FormData?d.set("square_payment_id",t):d.square_payment_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("Square payment could not be started."),"error"),h()}):n._paymentProviderEnabled("paypal")?n._ensurePaymentSdk("paypal").then(function(){return n._createPayPalPaymentForPayload(a)}).then(function(t){e("paypal_order_id",t),d instanceof FormData?d.set("paypal_order_id",t):d.paypal_order_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("PayPal Checkout could not be started."),"error"),h()}):n._paymentProviderEnabled("stripe")?n._ensurePaymentSdk("stripe").then(function(){return n._createStripePaymentForPayload(a)}).then(function(t){e("deposit_intent_id",t),d instanceof FormData?d.set("deposit_intent_id",t):d.deposit_intent_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("Stripe payment could not be started."),"error"),h()}):g()};n._paymentsConfigured()?n._loadFeatureChunk("recovery").then(()=>n._prepareCheckout(a)).then(e=>{d instanceof FormData?d.set("checkout_token",a.checkout_token):d.checkout_token=a.checkout_token,n._checkoutSavedPayment=e.payment||null,f()}).catch(e=>{const t=!!(e&&e.data&&e.data.preflight);if(t&&0===s)return n._showToast(e.message,"error"),void h();n._showBookingRecovery({reference:a.client_reference,failedIndex:s,confirmedCount:s,message:e.message,uncertain:!t}),h()}):f()};try{if(y.gift_card_code||n._giftCode){(n._giftSubmissionQuote?Promise.resolve(n._giftSubmissionQuote):n._fetchGiftQuote(parseFloat(y.tip_amount)||0)).then(e=>{n._giftSubmissionQuote=e,n._saveSession(),n._renderGiftQuote(e),E()}).catch(e=>{n._showToast(e.message,"error"),n._isSubmitting=!1,h()})}else E()}catch(e){console.error(o("Yatoon booking submit error:"),e),this._showToast(o("Something went wrong before the booking could be sent. Please refresh and try again."),"error"),h()}}}Object.getOwnPropertyNames(_.prototype).filter(e=>"constructor"!==e).forEach(t=>e.YatoonSquareBookingForm.prototype[t]=_.prototype[t])}(window,window.jQuery);1 !function(e,t){"use strict";const o=e.wp?.i18n?.__?t=>e.wp.i18n.__(t,"yatoon-booking-system"):e=>e,{ysSiteNow:n,ysSiteOffsetMin:s,ysFormatMoney:a,ysPriceVaries:i,ysMoneyFrom:r,ysCalcDeposit:c,validateBookingPhone:d,validateUSPhone:l,showFieldError:u,showPhoneError:m,validateCustomerName:g,validateCustomerEmail:f,ysFocusTrap:p}=e.YatoonBookingHelpers;class _{_paidCheckoutKey(e){return"yatoon-checkout:"+location.pathname+":"+e}_forgetPaidCheckout(e){if(e)try{sessionStorage.removeItem(this._paidCheckoutKey(e))}catch(e){}}_unresolvedPaidCheckout(e){const t=this._paidCheckoutKey("");try{for(let o=0;o<sessionStorage.length;o++){const n=sessionStorage.key(o);if(!n||0!==n.indexOf(t))continue;const s=n.slice(t.length);if(!s||s===e)continue;const a=JSON.parse(sessionStorage.getItem(n)||"null");if(a&&a.payment&&a.payment.id&&!a.resolved)return s}}catch(e){}return""}_showPaidRecoveryNotice(e,n){const s=this,a=t("#sbs-booking-recovery");a.length&&(a.addClass("sbs-booking-recovery-paid"),a.find("h3").first().text(o("Payment received, appointment not confirmed yet")),a.find(".sbs-booking-recovery-guidance").text(o('Your payment went through, but this appointment could not be confirmed. Please do not pay again. Use "Check payment and appointment status" to finish it, or contact the salon with the reference below so they can confirm another time or refund you.')),n&&!a.find(".sbs-paid-recovery-resolved").length&&t("<button/>",{type:"button",class:"sbs-paid-recovery-resolved",text:o("The salon has resolved this payment")}).appendTo(a.find(".sbs-booking-recovery-actions")).on("click",function(){try{const t=s._paidCheckoutKey(e),o=JSON.parse(sessionStorage.getItem(t)||"null");o&&(o.resolved=!0,sessionStorage.setItem(t,JSON.stringify(o)))}catch(e){}s._clearBookingRecovery(),s._saveSession()}))}submitBooking(){const n=this;if(this._handleBookingRecoveryAttempt())return;if(this._paymentsConfigured()&&"function"!=typeof this._ensurePaymentSdk){if(this._submissionChunkPromise)return;const e=t(".sbs-btn-submit").prop("disabled",!0).text(o("Loading secure payment..."));return void(this._submissionChunkPromise=this._loadFeatureChunk("payments").then(function(){n._submissionChunkPromise=null,e.prop("disabled",!1),n._applyConfirmBtn(),n.submitBooking()}).catch(function(t){n._submissionChunkPromise=null,e.prop("disabled",!1),n._applyConfirmBtn(),n._showToast(t.message||o("The secure payment component could not be loaded."),"error")}))}if(this._isSubmitting)return;if(this.designUploadInProgress)return void this._showToast(o("Please wait for the reference photo to finish uploading."),"info");if(!this._paymentsConfigured()&&(!this._turnstileTokenFetched||Date.now()>(this._turnstileTokenExpires||0))&&"function"==typeof e.yatoonGetTurnstileToken)return this._turnstileTokenFetched=!0,void e.yatoonGetTurnstileToken().then(function(t){e.yatoonTurnstileToken=t,n._turnstileTokenFetched=!0,n._turnstileTokenExpires=Date.now()+9e4,n.submitBooking()}).catch(function(){n._turnstileTokenFetched=!1,n._turnstileTokenExpires=0,n._showToast(o("Verification could not finish. Please try again."),"error")});const s=document.getElementById("sbs-otp-section"),a="undefined"!=typeof yatoonData&&"1"===yatoonData.verifyEmailOtp,i="undefined"!=typeof yatoonData&&"1"===yatoonData.verifySmsOtp;if(s&&(a||i)){const e=(document.getElementById("sbs-customer-email")||{}).value||"",t=(document.getElementById("sbs-customer-phone")||{}).value||"",a=e.trim()+"|"+t.trim();s.dataset.sentContact&&s.dataset.sentContact!==a&&(s.dataset.sent="",s.dataset.sentContact="");const r="1"===s.dataset.verified&&s.dataset.verifiedContact===a;"1"!==s.dataset.verified||r||(s.dataset.verified="",s.dataset.verifiedKey="");const c=function(e){const t=String(e||"").replace(/\D/g,"");return 11===t.length&&"1"===t.charAt(0)?t.slice(1):t},l=i?""!==c(s.dataset.verifiedPhone)&&c(t)===c(s.dataset.verifiedPhone):!!s.dataset.verifiedEmail&&e.trim().toLowerCase()===s.dataset.verifiedEmail.toLowerCase(),g=s.dataset.deviceVerified===a;if(!r&&!l&&!g){const r=f(e);if(r){u("sbs-customer-email",r);const e=document.getElementById("sbs-customer-email");return void(e&&e.scrollIntoView({behavior:"smooth",block:"center"}))}if(i){const e=d(t);if(e){m(e);const t=document.getElementById("sbs-phone-display")||document.getElementById("sbs-customer-phone");return void(t&&t.scrollIntoView({behavior:"smooth",block:"center"}))}}if(s.dataset.deviceChecked!==a)return void jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_otp_device_check",nonce:yatoonData.nonce,email:e,phone:t},function(e){s.dataset.deviceChecked=a,e&&e.success&&e.data&&e.data.verified&&(s.dataset.deviceVerified=a),n.submitBooking()}).fail(function(){s.dataset.deviceChecked=a,n.submitBooking()});const c=(document.getElementById("sbs-customer-name")||{}).value||"",l=i?"sms":"email";s.style.display="block";const g=document.getElementById("sbs-otp-remember");if(g&&"1"===g.dataset.regionAuto&&!g.dataset.regionChecked){g.dataset.regionChecked="1";let e="";try{e=Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch(t){e=""}const t=/^Europe\/(Moscow|Minsk|Kaliningrad|Samara|Volgograd|Kirov|Astrakhan|Saratov|Ulyanovsk|Simferopol|Istanbul|Kiev|Kyiv|Uzhgorod|Zaporozhye|Chisinau|Tirane|Skopje|Sarajevo|Belgrade|Podgorica)$/;(/^Europe\//.test(e)&&!t.test(e)||/^Atlantic\/(Reykjavik|Madeira|Azores|Canary)$/.test(e))&&(g.checked=!1)}if(document.getElementById("sbs-otp-prompt").textContent="sms"===l?o("We are sending a verification code to your phone. Please enter it below."):o("We are sending a verification code to")+" "+e+". "+o("Please enter it below."),!s.dataset.sent){s.dataset.sent="1",s.dataset.sentContact=a;const n=document.getElementById("sbs-otp-msg"),i=document.getElementById("sbs-otp-resend-btn");n&&(n.textContent=o("Sending verification code..."),n.style.color=""),i&&(i.disabled=!0),jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_send_otp",nonce:yatoonData.nonce,channel:l,email:e,phone:t,name:c},function(e){const t=!(!e||!e.success);n&&(n.textContent=t?e.data&&e.data.message?e.data.message:o("Verification code sent."):e&&e.data&&e.data.message?e.data.message:o("Failed to send code.")),i&&(i.style.display=""),i&&(i.disabled=!1),t||(s.dataset.sent="",s.dataset.sentContact="",n&&(n.style.color="#dc2626"))}).fail(function(){s.dataset.sent="",s.dataset.sentContact="",n&&(n.textContent=o("Could not send the verification code. Please try again."),n.style.color="#dc2626"),i&&(i.style.display="",i.disabled=!1)})}const p=document.getElementById("sbs-otp-verify-btn");p&&!p.dataset.bound&&(p.dataset.bound="1",p.addEventListener("click",function(){const e=(document.getElementById("sbs-otp-input")||{}).value||"",t=document.getElementById("sbs-otp-msg"),a=(document.getElementById("sbs-customer-email")||{}).value||"",i=(document.getElementById("sbs-customer-phone")||{}).value||"",r=a.trim()+"|"+i.trim();e.trim()?(p.disabled=!0,p.dataset.pending="1",t&&(t.textContent=o("Verifying..."),t.style.color=""),jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_verify_otp",nonce:yatoonData.nonce,channel:l,email:a,phone:i,code:e,remember:document.getElementById("sbs-otp-remember")&&document.getElementById("sbs-otp-remember").checked?1:0},function(e){e.success?(s.dataset.verified="1",s.dataset.verifiedKey=e.data&&e.data.verified_key?e.data.verified_key:"",n._giftSubmissionQuote=null,n._dynamicQuoteKey="",s.dataset.verifiedContact=r,s.style.display="none",n.submitBooking()):(t&&(t.textContent=e.data&&e.data.message?e.data.message:o("Incorrect code.")),t&&(t.style.color="#dc2626"),p.disabled=!1,p.dataset.pending="")}).fail(function(){t&&(t.textContent=o("Could not verify the code. Please try again."),t.style.color="#dc2626"),p.disabled=!1,p.dataset.pending=""})):t&&(t.textContent=o("Enter the verification code first."),t.style.color="#dc2626")}));const _=document.getElementById("sbs-otp-resend-btn");return void(_&&!_.dataset.bound&&(_.dataset.bound="1",_.addEventListener("click",function(){if(_.disabled)return;s.dataset.sent="",s.dataset.sentContact="",s.dataset.verified="",s.dataset.verifiedKey="",s.dataset.verifiedContact="";const e=document.getElementById("sbs-otp-msg");e&&(e.textContent=""),n.submitBooking()})))}}if(this._isSubmitting=!0,this._clearBookingRecovery(),0===this.bookingCart.length&&this.selectedDateTime&&(this.pendingServices.length>0||this.selectedService)&&this.addToCart(),0===this.bookingCart.length)return this._isSubmitting=!1,void this._showToast(o("Please add at least one service to your booking."),"error");const r=t(".sbs-btn-submit"),c=t("#sbs-cart-next-btn"),l=t("#sbs-sidebar-next-btn"),g=r.text(),p=c.text(),_=l.text(),h=()=>{this._isSubmitting=!1,this._turnstileTokenFetched=!1,r.prop("disabled",!1).text(g),c.prop("disabled",!1).removeClass("sbs-submitting").text(p||o("Confirm Booking")),l.prop("disabled",!1).removeClass("sbs-submitting").text(_||o("Confirm Booking")),this._applyConfirmBtn(),this._updateMobileCartBar()};r.prop("disabled",!0).text(o("Confirming your booking...")),c.prop("disabled",!0).addClass("sbs-submitting").text("CONFIRMING..."),l.prop("disabled",!0).addClass("sbs-submitting").text("CONFIRMING..."),this._updateLegalBoxes();const y={customer_name:t("#sbs-customer-name").val(),customer_email:t("#sbs-customer-email").val(),customer_phone:t("#sbs-customer-phone").val(),client_timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||"",notes:t("#sbs-customer-notes").val(),coupon_code:t("#sbs-coupon-code").length?t("#sbs-coupon-code").val():"",marketing_email_optin:t("#sbs-marketing-email-optin").is(":checked")?1:0,marketing_sms_optin:t("#sbs-marketing-sms-optin").is(":checked")?1:0,consent_accepted:t("#sbs-consent-accepted").length&&t("#sbs-consent-accepted").is(":checked")?1:0,consent_signature:t("#sbs-consent-signature").length?t("#sbs-consent-signature").val():"",policy_acknowledged:t("#sbs-policy-acknowledged").length&&t("#sbs-policy-acknowledged").is(":checked")?1:0,tip_amount:parseFloat(t("#sbs-tip-amount").val())||0,gift_card_code:t("#sbs-gift-card-code-confirmed").val()||"",custom_fields:function(){const e={};return t('[name^="cf["]').each(function(){const o=t(this).attr("name").replace(/^cf\[|\]$/g,"");t(this).is(":checkbox")||t(this).is(":radio")?t(this).is(":checked")&&(e[o]=t(this).val()):e[o]=t(this).val()}),JSON.stringify(e)}()},b=this._collectGuestContacts(),k=f(y.customer_email);if(k)return h(),u("sbs-customer-email",k),void(document.getElementById("sbs-customer-email")&&document.getElementById("sbs-customer-email").scrollIntoView({behavior:"smooth",block:"center"}));"undefined"!=typeof yatoonData&&yatoonData.phoneMode&&yatoonData.phoneMode;if(y.customer_phone){const e=d(y.customer_phone);if(e)return h(),m(e),void(document.getElementById("sbs-customer-phone")&&document.getElementById("sbs-customer-phone").scrollIntoView({behavior:"smooth",block:"center"}))}if(this._needsPolicyAck()&&!y.policy_acknowledged)return h(),this._showToast(o("Please review and acknowledge the cancellation / no-show policy before booking."),"error"),void this._focusBookingValidation(t("#sbs-policy-acknowledged"),t(".sbs-policy-box:visible").first());if(this._needsConsent()&&(!y.consent_accepted||!y.consent_signature.trim())){h(),this._showToast(o("Please read and sign the consent form before booking."),"error");const e=y.consent_accepted?t("#sbs-consent-signature"):t("#sbs-consent-accepted");return void this._focusBookingValidation(e,t(".sbs-consent-box:visible").first())}const v=this.bookingCart.slice(),C=[],w=JSON.stringify(v.map(e=>({start:e.dateTime&&e.dateTime.start_at,guest:e.guestLabel||"Me",services:(e.services||[{service:e.service,options:e.options,staff:e.staff}]).map(t=>({service:t.service&&t.service.id,options:(t.options||[]).map(e=>e.id),staff:t.staff&&t.staff.id||0,guest:t.guestLabel||e.guestLabel||"Me"}))}))),T=this._newBookingReference(w),S="undefined"!=typeof yatoonData&&(yatoonData.ajax_url||yatoonData.ajaxUrl)?yatoonData.ajax_url||yatoonData.ajaxUrl:"";if(!S)return h(),void this._showToast(o("Booking could not start because the WordPress AJAX URL is missing. Please refresh and try again."),"error");if(!v.length)return h(),void this._showToast(o("Please choose a service and time before confirming."),"error");const I=v.some(e=>e&&e.services&&e.services.length>1),P=v.length>1||I?"yatoon-"+T:"";let x=this.designUploadAttachmentId||0,B=this.designUploadToken||"";const D=o=>{const s=v[o],a=s.services||[{service:s.service,options:s.options,staff:s.staff}],i=s.dateTime&&s.dateTime.staff_map?s.dateTime.staff_map:null,r="string"==typeof i?function(){try{return JSON.parse(i)}catch(e){return null}}():i,c={},d={};a.forEach(function(e,t){const o=void 0!==e._originalIndex?e._originalIndex:t;s.dateTime.local_staff_map&&Number(s.dateTime.local_staff_map[o])>0&&(d[t]=Number(s.dateTime.local_staff_map[o])),r&&void 0!==r[o]&&(c[t]=r[o])});const l=Object.keys(c).length?JSON.stringify(c):i?"string"==typeof i?i:JSON.stringify(i):"",u=s.guestLabel||a[0]&&a[0].guestLabel||"Me",m=b[u]||{};let g=y.notes||"";if("Me"!==u){const e=[`Guest: ${u}`];m.name&&e.push(`Name: ${m.name}`),m.phone&&e.push(`Phone: ${m.phone}`),g=`${g}${g?"\n\n":""}${e.join(" - ")}`}const f={},p=new Date(s.dateTime.start_at).getTime(),_=a.map(e=>{const t=e.guestLabel||s.guestLabel||"Me",o=f[t]||0,a=Number.isFinite(p)?new Date(p+6e4*o).toISOString():s.dateTime.start_at;return f[t]=o+n._serviceDuration(e),{service_id:e.service.id,staff_id:e.staff?e.staff.id:0,gender_preference:n._genderPreferenceFor(e),option_ids:e.options.map(e=>e.id),guest_label:t,start_at:a,design_attachment_id:parseInt(e.designAttachmentId||0,10)||0,design_upload_token:String(e.designUploadToken||"")}});return{action:"yatoon_create_booking",nonce:yatoonData.nonce,client_reference:`${T}-${o+1}`,start_at:s.dateTime.start_at,local_staff_map_json:JSON.stringify(d),staff_map_json:l,services_json:JSON.stringify(_),service_id:a[0].service.id,staff_id:a[0].staff?a[0].staff.id:0,gender_preference:n._genderPreferenceFor(a[0]),selected_options:a[0].options.map(e=>e.id),notes:g,guest_label:u,guest_name:m.name||"",guest_phone:m.phone||"",booking_group_id:P,coupon_code:y.coupon_code,tip_amount:0===o?y.tip_amount:0,gift_card_code:n._giftSubmissionQuote?.cart[o]?.gift_card_amount>0?y.gift_card_code||n._giftCode:"",gift_card_amount:n._giftSubmissionQuote?.cart[o]?.gift_card_amount||0,custom_fields:y.custom_fields,customer_name:y.customer_name,customer_email:y.customer_email,customer_phone:y.customer_phone,otp_channel:"undefined"!=typeof yatoonData&&"1"===yatoonData.verifySmsOtp?"sms":"email",otp_verified_key:document.getElementById("sbs-otp-section")&&document.getElementById("sbs-otp-section").dataset.verifiedKey?document.getElementById("sbs-otp-section").dataset.verifiedKey:"",marketing_email_optin:y.marketing_email_optin,marketing_sms_optin:y.marketing_sms_optin,consent_accepted:y.consent_accepted,consent_signature:y.consent_signature,policy_acknowledged:y.policy_acknowledged,client_timezone:y.client_timezone,design_attachment_id:x||"",design_upload_token:B||"",website:t("#sbs-website").val()||"",form_rendered_at:t("#sbs-form-rendered-at").val()||"",cf_turnstile_response:void 0!==e.yatoonTurnstileToken?e.yatoonTurnstileToken:"",yatoon_test_booking:t(".sbs-booking-container").hasClass("yatoon-test-mode")?"1":""}},E=()=>{v.length<2||!n._paymentsConfigured()?F(0):n._loadFeatureChunk("recovery").then(async()=>{for(let e=0;e<v.length;e++)try{await n._prepareCheckout(D(e))}catch(t){throw t.cartIndex=e,t}}).then(()=>F(0)).catch(e=>{const t=e&&"number"==typeof e.cartIndex?e.cartIndex:0;if(e&&e.data&&e.data.preflight)return n._showToast(e.message,"error"),void h();n._showBookingRecovery({reference:`${T}-${t+1}`,failedIndex:t,confirmedCount:0,message:e&&e.message||o("This appointment is no longer available. Please choose another time."),uncertain:!1}),h()})},F=s=>{if(s>=v.length){if(C.every(e=>e&&e.success)){const s=C.find(e=>e&&e.success&&e.data&&e.data.woocommerce_checkout_url);if(s&&s.data.woocommerce_checkout_url)return this.bookingConfirmed=!0,this._clearSession(),void e.location.assign(s.data.woocommerce_checkout_url);this.bookingConfirmed=!0,t(".sbs-form-step").removeClass("active"),t(".sbs-step-success").show(),this._updateStepAccordion(),this._markBookingFlowComplete(),t("#sbs-success-count").text(v.length);const a=1!==v.length;t("#sbs-success-booking-word").text(o(a?"Bookings":"Booking"));const i=this._confirmedBookingItems(v,C);this._renderSuccessBookingSummary(i);const r=C.filter(e=>e&&e.success&&e.data&&e.data.manage_url&&String(e.data.manage_url).length),d=r.length&&r[0].data?r[0].data.manage_url:"",u=C.find(e=>e&&e.success&&e.data&&e.data.calendar_url&&String(e.data.calendar_url).length),m=u&&u.data?u.data.calendar_url:"",g=yatoonData.portalUrl||"",f=yatoonData.portalLabel||o("My Appointments"),p=t("#sbs-success-actions").empty();if(t("<div/>",{class:"sbs-success-action-note",text:yatoonData.successNote||o("Your appointment is booked. Save this page or use the manage link below if you need to change services, reschedule, or cancel.")}).appendTo(p),d&&1===r.length&&t("<a/>",{class:"sbs-success-action-link primary",href:d,target:"_blank",rel:"noopener",text:"undefined"!=typeof yatoonData&&yatoonData.isPro?o("Change services, reschedule, or cancel"):o("Reschedule or cancel")}).appendTo(p),r.length>1){const e=t("<div/>",{class:"sbs-success-manage-list"}).appendTo(p),n=v.some(e=>e.guestLabel&&"Me"!==e.guestLabel);r.forEach((s,a)=>{const i=v[a],r=i&&i.guestLabel&&"Me"!==i.guestLabel?i.guestLabel:null;let c;if(r)c=o("Change or cancel for")+" "+r;else if(n)c=o("Change or cancel my appointment");else{const e=s.data&&s.data.service_name?s.data.service_name:o("Appointment")+" "+(a+1);c=o("Change or cancel:")+" "+e}t("<a/>",{class:"sbs-success-action-link compact",href:s.data.manage_url,target:"_blank",rel:"noopener",text:c}).appendTo(e)})}if(m&&!t("#sbs-success-cal-row").length&&t("<a/>",{class:"sbs-success-action-link",href:m,text:o("Add to calendar")}).appendTo(p),g&&t("<a/>",{class:"sbs-success-action-link",href:g,text:f}).appendTo(p),t("<button/>",{type:"button",class:"sbs-success-action-link sbs-success-book-again"+(d?"":" primary"),text:o("Book again")}).appendTo(p),p.show(),m){t("#sbs-cal-ics").attr("href",m);const e=C.find(e=>e&&e.success&&e.data&&(e.data.start_at||e.data.start_time)),n=i[0]||null,s=n&&n.dateTime?n.dateTime.start_at:"",a=n?this._getItemVisitDuration(n):0,r=s?new Date(s):null,c=r&&!isNaN(r.getTime())&&a?new Date(r.getTime()+6e4*a).toISOString():"",d=e&&e.data&&(e.data.start_at||e.data.start_time)||s,l=e&&e.data&&(e.data.end_at||e.data.end_time)||c;if(d&&l){const e=function(e){const t=new Date(e);return isNaN(t.getTime())?"":t.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"Z")},s=(n?n.services||[{service:n.service}]:[]).map(e=>e.service&&e.service.name).filter(Boolean).join(", "),a=encodeURIComponent((yatoonData.businessName||o("Appointment"))+(s?" - "+s:"")),i=encodeURIComponent(e(d)),r=encodeURIComponent(e(l)),c=encodeURIComponent(yatoonData&&yatoonData.siteTimezone?yatoonData.siteTimezone:Intl.DateTimeFormat().resolvedOptions().timeZone);i&&r?t("#sbs-cal-google").attr("href","https://calendar.google.com/calendar/render?action=TEMPLATE&text="+a+"&dates="+i+"/"+r+"&ctz="+c):t("#sbs-cal-google").attr("href",m)}else t("#sbs-cal-google").attr("href",m);t("#sbs-success-cal-row").show()}yatoonData.rebookingNudgeText&&(t("#sbs-rebooking-nudge .sbs-rebooking-text").text(yatoonData.rebookingNudgeText),t("#sbs-rebooking-nudge .sbs-rebooking-btn").text(yatoonData.rebookingNudgeBtn||o("Book next visit")),setTimeout(function(){t("#sbs-rebooking-nudge").fadeIn(400)},1200));const _=C.find(e=>e&&e.success&&e.data&&e.data.booking_id);if(_&&_.data.manage_token&&t("#sbs-recurring-setup").length){const e=_.data.booking_id,n=_.data.manage_token;let s=2;setTimeout(function(){t("#sbs-recurring-setup").fadeIn(400)},2e3),t(document).on("click",".sbs-freq-btn",function(){t(".sbs-freq-btn").removeClass("active"),t(this).addClass("active"),s=parseInt(t(this).data("weeks"))}),t(document).on("click","#sbs-recurring-confirm",function(){const a=t(this).prop("disabled",!0).text(o("Setting up...")),i=parseInt(t("#sbs-recurring-count").val())||6;t.post(ajaxurl,{action:"yatoon_setup_recurring",nonce:yatoonData.nonce,yatoon_location_id:parseInt(yatoonData.locationId||0,10),booking_id:e,manage_token:n,frequency_weeks:s,total_count:i},function(e){const n=t("#sbs-recurring-result");e.success?(a.text(o("Done")),n.removeClass("error").text(e.data.message).show()):(a.prop("disabled",!1).text(o("Try again")),n.addClass("error").text(e.data&&e.data.message||o("Could not set up recurring.")).show())}).fail(function(){a.prop("disabled",!1).text(o("Try again")),t("#sbs-recurring-result").addClass("error").text(o("Network error. Please try again.")).show()})})}n.bookingCart=[],n.pendingServices=[],n._clearSession(),n._clearBookingRecovery(),n._bookingAttemptReference="",n._bookingAttemptFingerprint="",n._giftCode="",n._giftSubmissionQuote=null,t("#sbs-gift-card-code-confirmed").val(""),n._hideMobileCartBar(),n._closeDrawer(),n._isSubmitting=!1,h(),c.hide(),l.hide()}else{const e=C.filter(e=>!e||!e.success),t=e.map(e=>e&&e.data&&e.data.message?e.data.message:"").filter(Boolean).join(" "),s=t?`\n\nDetails: ${t}`:"",a=C.length-e.length;n._showToast(`${a} booking(s) confirmed, but ${e.length} failed. Please contact us.${s}`,"error");const i=e[0]&&e[0].data?e[0].data:{};n._showBookingRecovery({reference:i.reference||T,failedIndex:a,confirmedCount:a,message:t||o("One or more appointments were not confirmed."),safeToRetry:!0===i.retry_safe}),h()}return}const a=D(s),i=document.getElementById("sbs-design-reference"),r=i&&i.files&&i.files[0]?i.files[0]:null;let d=a,u=!0,m="application/x-www-form-urlencoded; charset=UTF-8";r&&!x&&(d=new FormData,Object.keys(a).forEach(function(e){const t=a[e];Array.isArray(t)?t.forEach(function(t){d.append(e+"[]",t)}):d.append(e,t)}),d.append("design_reference",r),u=!1,m=!1);const g=function(){t.ajax({url:S,type:"POST",timeout:9e4,data:d,processData:u,contentType:m,success:function(e,i,r){try{if("string"==typeof e){const t=e.indexOf("{"),o=e.lastIndexOf("}"),n=t>=0&&o>t?e.slice(t,o+1):e;e=JSON.parse(n)}if(C.push(e),!e||!e.success){const t=e&&e.data&&e.data.message?e.data.message:"",i=t?`\n\nDetails: ${t}`:"",r=C.length-1;n._showToast(`${r} booking(s) confirmed, but appointment ${s+1} failed. Please contact us.${i}`,"error");const c=e&&e.data?e.data:{},l=!!function(){const e=["deposit_intent_id","paypal_order_id","square_payment_id"];for(let t=0;t<e.length;t++){const o=d instanceof FormData?d.get(e[t]):d[e[t]];if(o)return String(o)}return""}();return n._showBookingRecovery({reference:a.client_reference||c.reference||`${T}-${s+1}`,failedIndex:s,confirmedCount:r,message:t||o("The appointment was not confirmed."),safeToRetry:!0===c.retry_safe&&!l,uncertain:!0===c.outcome_uncertain||l}),l&&n._showPaidRecoveryNotice(a.client_reference),void h()}n._forgetPaidCheckout(a.client_reference),e.data&&e.data.design_attachment_id&&(x=parseInt(e.data.design_attachment_id,10)||x,n.designUploadAttachmentId=x),e.data&&e.data.design_upload_token&&(B=String(e.data.design_upload_token||""),n.designUploadToken=B),F(s+1)}catch(a){if(console.error(o("Yatoon booking submit failed after server response:"),a),n.bookingConfirmed||t(".sbs-step-success:visible").length>0)return;const i=r&&r.responseText?String(r.responseText):"string"==typeof e?e:"";if(i&&-1!==i.indexOf('"success":true'))return C.push({success:!0,data:{}}),void F(s+1);n._showToast(o("We could not read the booking confirmation response. Please check the booking list before trying again."),"error"),n._showBookingRecovery({reference:`${T}-${s+1}`,failedIndex:s,confirmedCount:C.filter(e=>e&&e.success).length,message:o("We could not verify the server response."),uncertain:!0}),h()}},error:function(e,t){C.push({success:!1});const a=C.length-1,i="timeout"===t?"the request timed out":"a network error";n._showToast(`${a} booking(s) confirmed, but appointment ${s+1} failed due to ${i}. Please contact us.`,"error"),n._showBookingRecovery({reference:`${T}-${s+1}`,failedIndex:s,confirmedCount:a,message:o("timeout"===t?"The request timed out.":"The network connection was interrupted."),uncertain:!0}),h()}})},f=function(){const e=(e,t)=>{n._rememberCheckoutPayment&&n._rememberCheckoutPayment(a.client_reference,e,t),n._giftSubmissionQuote&&(n._giftSubmissionQuote.payments=n._giftSubmissionQuote.payments||{},n._giftSubmissionQuote.payments[s]={field:e,id:t},n._saveSession())},t=n._checkoutSavedPayment||n._giftSubmissionQuote?.payments?.[s];n._checkoutSavedPayment=null;const i=t?"":n._unresolvedPaidCheckout(a.client_reference);if(i)return n._showBookingRecovery({reference:i,failedIndex:s,confirmedCount:s,message:o("A payment for an earlier attempt was received, but that appointment is not confirmed yet."),uncertain:!0}),n._showPaidRecoveryNotice(i,!0),void h();t?(d instanceof FormData?d.set(t.field,t.id):d[t.field]=t.id,g()):a.gift_card_code&&0===n._giftSubmissionQuote?.cart[s]?.amount_due?g():n._squarePreparedPaymentId&&n._squarePreparedPaymentReference===a.client_reference?(e("square_payment_id",n._squarePreparedPaymentId),d instanceof FormData?d.set("square_payment_id",n._squarePreparedPaymentId):d.square_payment_id=n._squarePreparedPaymentId,n._squarePreparedPaymentId="",n._squarePreparedPaymentReference="",g()):n._paymentProviderEnabled("square")?n._ensurePaymentSdk("square").then(function(){return n._createSquarePaymentForPayload(a)}).then(function(t){e("square_payment_id",t),d instanceof FormData?d.set("square_payment_id",t):d.square_payment_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("Square payment could not be started."),"error"),h()}):n._paymentProviderEnabled("paypal")?n._ensurePaymentSdk("paypal").then(function(){return n._createPayPalPaymentForPayload(a)}).then(function(t){e("paypal_order_id",t),d instanceof FormData?d.set("paypal_order_id",t):d.paypal_order_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("PayPal Checkout could not be started."),"error"),h()}):n._paymentProviderEnabled("stripe")?n._ensurePaymentSdk("stripe").then(function(){return n._createStripePaymentForPayload(a)}).then(function(t){e("deposit_intent_id",t),d instanceof FormData?d.set("deposit_intent_id",t):d.deposit_intent_id=t,g()}).catch(function(e){if(0===s&&e&&e.data&&e.data.preflight)return n._showToast(e.message||o("Stripe payment could not be started."),"error"),void h();n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("Stripe payment could not be started."),"error"),h()}):g()};n._paymentsConfigured()?n._loadFeatureChunk("recovery").then(()=>n._prepareCheckout(a)).then(e=>{d instanceof FormData?d.set("checkout_token",a.checkout_token):d.checkout_token=a.checkout_token,n._checkoutSavedPayment=e.payment||null,f()}).catch(e=>{const t=!!(e&&e.data&&e.data.preflight);if(t&&0===s)return n._showToast(e.message,"error"),void h();n._showBookingRecovery({reference:a.client_reference,failedIndex:s,confirmedCount:s,message:e.message,uncertain:!t}),h()}):f()};try{if(y.gift_card_code||n._giftCode){(n._giftSubmissionQuote?Promise.resolve(n._giftSubmissionQuote):n._fetchGiftQuote(parseFloat(y.tip_amount)||0)).then(e=>{n._giftSubmissionQuote=e,n._saveSession(),n._renderGiftQuote(e),E()}).catch(e=>{n._showToast(e.message,"error"),n._isSubmitting=!1,h()})}else E()}catch(e){console.error(o("Yatoon booking submit error:"),e),this._showToast(o("Something went wrong before the booking could be sent. Please refresh and try again."),"error"),h()}}}Object.getOwnPropertyNames(_.prototype).filter(e=>"constructor"!==e).forEach(t=>e.YatoonSquareBookingForm.prototype[t]=_.prototype[t])}(window,window.jQuery); -
yatoon-booking-system/tags/4.10.2/assets/js/frontend-payments.js
r3780403 r3780965 87 87 return new Promise(function(resolve, reject) { 88 88 if (!self._stripePaymentsReady()) { 89 reject(new Error(__('Stripe payment form is not ready. Please refresh and try again.'))); 89 const notReady = new Error(__('Stripe payment form is not ready. Please refresh and try again.')); 90 notReady.data = { preflight: true }; 91 reject(notReady); 90 92 return; 91 93 } … … 126 128 paymentElement.mount('#sbs-stripe-payment-element'); 127 129 const $status = $('#sbs-stripe-payment-status'); 130 const payLabel = yatoonData.nativePaymentMode === 'full' ? __('Pay total') : __('Pay deposit'); 131 // 4.10.2: the box is reused for the next appointment in a cart. 132 // Start each payment with a fresh, clickable button and no old status. 133 $status.text(''); 134 $('#sbs-stripe-pay-button').prop('disabled', false).text(payLabel); 128 135 $('#sbs-stripe-pay-button').off('.yatoonStripe').on('click.yatoonStripe', function() { 129 136 const $button = $(this).prop('disabled', true).text(__('Processing...')); 130 137 $status.text(__('Confirming your payment securely...')); 138 // 4.10.2: a Stripe error (no payment method chosen, card declined, 139 // failed verification) means nothing was charged. Keep the customer 140 // in this payment box so they can fix it and pay again, instead of 141 // ending the checkout and sending them to the booking-status panel. 142 const retryHere = function(message) { 143 $button.prop('disabled', false).text(payLabel); 144 $status.text(message); 145 self._showToast(message, 'error'); 146 }; 131 147 stripe.confirmPayment({ 132 148 elements: elements, 133 149 redirect: 'if_required' 134 150 }).then(function(result) { 135 if (result.error) throw new Error(result.error.message || __('Stripe could not complete the payment.')); 151 let intent = result.paymentIntent || null; 152 // A repeat click after a lost response: Stripe reports the intent 153 // is already paid. Treat that as success, not as an error. 154 if (result.error && result.error.payment_intent) { 155 const already = result.error.payment_intent.status; 156 if (already === 'succeeded' || already === 'processing') intent = result.error.payment_intent; 157 } 158 if (result.error && !intent) { 159 retryHere(result.error.message || __('Stripe could not complete the payment.')); 160 return; 161 } 136 162 // 4.10.2: bank debits stay "processing" for a few days. The 137 163 // appointment is booked now and marked paid when the bank clears. 138 const intentStatus = result.paymentIntent ? result.paymentIntent.status : '';164 const intentStatus = intent ? intent.status : ''; 139 165 if (intentStatus !== 'succeeded' && intentStatus !== 'processing') { 140 throw new Error(__('Stripe payment is not complete.')); 166 retryHere(__('Stripe payment is not complete. Please check your payment details and try again.')); 167 return; 141 168 } 142 169 $status.text(intentStatus === 'processing' … … 144 171 : __('Payment approved. Confirming your appointment...')); 145 172 $box.hide(); 146 resolve( result.paymentIntent.id);173 resolve(intent.id); 147 174 }).catch(function(error) { 148 $button.prop('disabled', false).text(yatoonData.nativePaymentMode === 'full' ? __('Pay total') : __('Pay deposit'));149 $status.text(error.message || __('Stripe payment failed.'));150 self._showToast(error.message || __('Stripe payment failed.'), 'error');151 re ject(error);175 // Stripe.js itself failed (network). The charge state is unknown, 176 // so let the customer press Pay again: Stripe answers a repeat 177 // confirm of a paid intent with its paid status (handled above). 178 retryHere((error && error.message) || __('We could not reach Stripe. Please check your connection and press Pay again.')); 152 179 }); 153 180 }); 154 181 $box.show(); 155 182 if ($box[0] && $box[0].scrollIntoView) $box[0].scrollIntoView({ behavior: 'smooth', block: 'center' }); 156 }).catch(reject); 183 }).catch(function(error) { 184 // The payment form could not be opened, so nothing was charged. 185 if (error && typeof error === 'object') error.data = Object.assign({}, error.data, { preflight: true }); 186 reject(error); 187 }); 157 188 }); 158 189 } -
yatoon-booking-system/tags/4.10.2/assets/js/frontend-payments.min.js
r3780403 r3780965 1 !function(e,t){"use strict";const a=e.wp&&e.wp.i18n&&"function"==typeof e.wp.i18n.__?function(t){return e.wp.i18n.__(t,"yatoon-booking-system")}:function(e){return e},n=e.YatoonSquareBookingForm;if(n&&t){class o{_squarePaymentsReady(){return!!("undefined"!=typeof yatoonData&&yatoonData.squarePaymentsEnabled&&yatoonData.squareApplicationId&&yatoonData.squareLocationId&&e.Square&&"function"==typeof e.Square.payments)}_paymentProviderEnabled(e){return"undefined"!=typeof yatoonData&&("square"===e?!!yatoonData.squarePaymentsEnabled:"paypal"===e?!!yatoonData.paypalPaymentsEnabled:"stripe"===e&&!!yatoonData.depositEnabled)}_ensurePaymentSdk(e){const t={square:()=>this._squarePaymentsReady(),paypal:()=>this._paypalPaymentsReady(),stripe:()=>this._stripePaymentsReady()}[e],n={square:yatoonData.squareSdkUrl,paypal:yatoonData.paypalSdkUrl,stripe:yatoonData.stripeSdkUrl}[e];return t&&t()?Promise.resolve():n?(this._paymentSdkPromises=this._paymentSdkPromises||{},this._paymentSdkPromises[e]||(this._paymentSdkPromises[e]=new Promise(function(o,r){const s=document.createElement("script");s.src=n,s.async=!0,s.dataset.yatoonPaymentSdk=e,s.onload=function(){t&&t()?o():r(new Error(a("The secure payment service did not initialize.")))},s.onerror=function(){r(new Error(a("The secure payment service could not be loaded. Check your connection and try again.")))},document.head.appendChild(s)}).catch(t=>{throw delete this._paymentSdkPromises[e],t})),this._paymentSdkPromises[e]):Promise.reject(new Error(a("The secure payment service is not configured.")))}_paypalPaymentsReady(){return!("undefined"==typeof yatoonData||!yatoonData.paypalPaymentsEnabled||!e.paypal||"function"!=typeof e.paypal.Buttons)}_stripePaymentsReady(){return!("undefined"==typeof yatoonData||!yatoonData.depositEnabled||!yatoonData.stripePublishableKey||"function"!=typeof e.Stripe)}_createStripePaymentForPayload(n){const o=this;return new Promise(function(r,s){if(!o._stripePaymentsReady()) return void s(new Error(a("Stripe payment form is not ready. Please refresh and try again.")));const i=new FormData;Object.keys(n).forEach(function(e){const t=n[e];Array.isArray(t)?t.forEach(function(t){i.append(e+"[]",t)}):i.append(e,null==t?"":t)}),i.set("action","yatoon_stripe_create_intent"),i.set("nonce",yatoonData.nonce),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:i,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(n){if(n?.success&&n.data?.already_paid&&n.data.intent_id)return void r(n.data.intent_id);if(!(n&&n.success&&n.data&&n.data.client_secret))throw new Error(n&&n.data&&n.data.message?n.data.message:a("Could not start the Stripe payment."));let i=t("#sbs-stripe-payment-box");if(!i.length){i=t(`\n <div id="sbs-stripe-payment-box" style="margin:16px 0;padding:16px;border:1px solid #ddd6fe;border-radius:14px;background:#f5f3ff;">\n <div style="font-size:14px;font-weight:800;color:#2e1065;margin-bottom:6px;">Secure Stripe Payment</div>\n <div id="sbs-stripe-payment-amount" style="font-size:13px;color:#475569;margin-bottom:12px;"></div>\n <div id="sbs-stripe-payment-element"></div>\n <button type="button" id="sbs-stripe-pay-button" style="width:100%;min-height:46px;margin-top:14px;border:0;border-radius:9px;background:#635bff;color:#fff;font-weight:800;cursor:pointer;">${"full"===yatoonData.nativePaymentMode?a("Pay total"):a("Pay deposit")}</button>\n <div id="sbs-stripe-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>`);const e=t("#sbs-booking-form");e.length?e.prepend(i):t(".sbs-step-5").prepend(i)}t("#sbs-stripe-payment-element").empty(),t("#sbs-stripe-payment-amount").text(("full"===yatoonData.nativePaymentMode?a("Full payment due now:"):a("Deposit due now:"))+" "+(n.data.deposit_display||""));const p=e.Stripe(yatoonData.stripePublishableKey),d=p.elements({clientSecret:n.data.client_secret});d.create("payment").mount("#sbs-stripe-payment-element");const u=t("#sbs-stripe-payment-status");t("#sbs-stripe-pay-button").off(".yatoonStripe").on("click.yatoonStripe",function(){const e=t(this).prop("disabled",!0).text(a("Processing..."));u.text(a("Confirming your payment securely...")),p.confirmPayment({elements:d,redirect:"if_required"}).then(function(e){if(e.error)throw new Error(e.error.message||a("Stripe could not complete the payment."));const t=e.paymentIntent?e.paymentIntent.status:"";if("succeeded"!==t&&"processing"!==t)throw new Error(a("Stripe payment is not complete."));u.text(a("processing"===t?"Bank payment submitted. Confirming your appointment...":"Payment approved. Confirming your appointment...")),i.hide(),r(e.paymentIntent.id)}).catch(function(t){e.prop("disabled",!1).text("full"===yatoonData.nativePaymentMode?a("Pay total"):a("Pay deposit")),u.text(t.message||a("Stripe payment failed.")),o._showToast(t.message||a("Stripe payment failed."),"error"),s(t)})}),i.show(),i[0]&&i[0].scrollIntoView&&i[0].scrollIntoView({behavior:"smooth",block:"center"})}).catch(s)})}_createPayPalPaymentForPayload(n){const o=this;return new Promise(function(r,s){if(!o._paypalPaymentsReady())return void s(new Error(a("PayPal Checkout is not ready. Please refresh and try again.")));let i=t("#sbs-paypal-payment-box");if(!i.length){i=t(`\n <div id="sbs-paypal-payment-box" style="margin:16px 0;padding:16px;border:1px solid #bfdbfe;border-radius:14px;background:#eff6ff;">\n <div style="font-size:14px;font-weight:800;color:#172554;margin-bottom:6px;">Secure PayPal Payment</div>\n <div style="font-size:13px;color:#475569;margin-bottom:12px;">${"full"===yatoonData.nativePaymentMode?a("Pay the full appointment total with PayPal to confirm your booking."):a("Choose PayPal below to pay the deposit and confirm your appointment.")}</div>\n <div id="sbs-paypal-button-container"></div>\n <div id="sbs-paypal-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>`);const e=t("#sbs-booking-form");e.length?e.prepend(i):t(".sbs-step-5").prepend(i)}const p=t("#sbs-paypal-payment-status"),d=yatoonData.ajax_url||yatoonData.ajaxUrl;function u(e,t){const o=new FormData;return Object.keys(n).forEach(function(e){const t=n[e];Array.isArray(t)?t.forEach(function(t){o.append(e+"[]",t)}):o.append(e,null==t?"":t)}),o.set("action",e),o.set("nonce",yatoonData.nonce),Object.keys(t||{}).forEach(function(e){o.set(e,t[e])}),fetch(d,{method:"POST",body:o,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!e||!e.success||!e.data)throw new Error(e&&e.data&&e.data.message?e.data.message:a("PayPal payment failed."));return e.data})}t("#sbs-paypal-button-container").empty(),e.paypal.Buttons({style:{layout:"vertical",shape:"rect",label:"paypal"},createOrder:function(){return p.text(a("Preparing secure PayPal Checkout...")),u("yatoon_paypal_create_order").then(function(e){return e.amount_display&&p.text(("full"===yatoonData.nativePaymentMode?a("Full payment due now:"):a("Deposit due now:"))+" "+e.amount_display),e.order_id})},onApprove:function(e){return p.text(a("Confirming your PayPal payment...")),u("yatoon_paypal_capture_order",{order_id:e.orderID}).then(function(t){p.text(a("Payment approved. Confirming your appointment...")),i.hide(),r(t.order_id||e.orderID)}).catch(function(e){p.text(e.message||a("PayPal could not capture the payment.")),o._showToast(e.message||a("PayPal could not capture the payment."),"error"),s(e)})},onCancel:function(){const e=new Error(a("PayPal Checkout was cancelled."));p.text(e.message),s(e)},onError:function(e){p.text(a("PayPal Checkout could not be opened. Please try again.")),o._showToast(e&&e.message?e.message:a("PayPal Checkout failed."),"error"),s(e instanceof Error?e:new Error(a("PayPal Checkout failed.")))}}).render("#sbs-paypal-button-container").then(function(){i.show(),i[0]&&i[0].scrollIntoView&&i[0].scrollIntoView({behavior:"smooth",block:"center"})}).catch(s)})}_squareMethods(){const e=yatoonData&&Array.isArray(yatoonData.squarePaymentMethods)?yatoonData.squarePaymentMethods:["card"];return e.length?e:["card"]}_previewSquarePayment(e){const t=new FormData;return Object.keys(e).forEach(function(a){const n=e[a];Array.isArray(n)?n.forEach(function(e){t.append(a+"[]",e)}):t.append(a,null==n?"":n)}),t.set("action","yatoon_square_preview_payment"),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:t,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!e||!e.success||!e.data){const t=e&&e.data&&e.data.message?e.data.message:a("Could not calculate the Square payment amount.");throw new Error(t)}return e.data})}_buildSquarePaymentRequest(e,t){return e.paymentRequest({countryCode:(yatoonData.squareCountryCode||"US").toUpperCase(),currencyCode:(t.currency||yatoonData.currency||"USD").toUpperCase(),total:{amount:t.amount||"0.00",label:"full"===yatoonData.squarePaymentMode?a("Appointment total"):a("Booking deposit")}})}_ensureSquarePaymentCard(n){const o=this,r=JSON.stringify({services_json:n.services_json||"",service_id:n.service_id||"",selected_options:n.selected_options||[],coupon_code:n.coupon_code||"",customer_email:n.customer_email||"",customer_phone:n.customer_phone||"",client_reference:n.client_reference||"",checkout_token:n.checkout_token||"",start_at:n.start_at||"",location:n.yatoon_location_id||0,tip_amount:n.tip_amount||0,gift_card_code:n.gift_card_code||""});return this._squareCardPromise&&this._squarePaymentPayloadKey===r||(this._squarePaymentPayloadKey=r,this._squareCardPromise=new Promise(function(r,s){if(!o._squarePaymentsReady())return void s(new Error(a("Square payment form is not ready. Please refresh and try again.")));let i=t("#sbs-square-payment-box");if(!i.length){const e="full"===yatoonData.squarePaymentMode?a("Pay securely now to confirm your appointment."):a("Pay your deposit securely now to confirm your appointment.");i=t(`\n <div id="sbs-square-payment-box" class="sbs-square-payment-box" style="margin:16px 0;padding:16px;border:1px solid #dbeafe;border-radius:14px;background:#eff6ff;">\n <div style="font-size:14px;font-weight:800;color:#1e3a8a;margin-bottom:6px;">Secure Square Payment</div>\n <div style="font-size:13px;color:#475569;margin-bottom:12px;">${e}</div>\n <div id="sbs-square-payment-amount" style="font-size:13px;font-weight:800;color:#0f172a;margin-bottom:12px;"></div>\n <div id="sbs-square-method-tabs" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;"></div>\n <button id="sbs-square-apple-pay-button" type="button" class="sbs-square-method-panel" data-method-panel="apple_pay" style="display:none;width:100%;min-height:44px;border-radius:8px;border:0;background:#000;color:#fff;font-weight:800;">Apple Pay</button>\n <div id="sbs-square-google-pay" class="sbs-square-method-panel" data-method-panel="google_pay" style="display:none;"></div>\n <div id="sbs-square-cash-app-pay" class="sbs-square-method-panel" data-method-panel="cash_app_pay" style="display:none;"></div>\n <div id="sbs-square-gift-card-container" class="sbs-square-method-panel" data-method-panel="gift_card" style="display:none;"></div>\n <div id="sbs-square-card-container"></div>\n <div id="sbs-square-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>\n `);const n=t("#sbs-booking-form");n.length?n.prepend(i):t(".sbs-step-5").prepend(i)}t("#sbs-square-payment-status").text(a("Loading secure Square card form...")),o._previewSquarePayment(n).then(function(s){return t("#sbs-square-payment-amount").text(("full"===s.payment_mode?a("Pay now:"):a("Deposit due now:"))+" "+s.amount_display),Promise.resolve(e.Square.payments(yatoonData.squareApplicationId,yatoonData.squareLocationId)).then(function(i){const p=o._squareMethods(),d={payments:i,preview:s,methods:{},selected:p[0]||"card"},u=o._buildSquarePaymentRequest(i,s),c={card:"Card",apple_pay:a("Apple Pay"),google_pay:a("Google Pay"),cash_app_pay:a("Cash App"),gift_card:a("Gift Card")},y=t("#sbs-square-method-tabs").empty();function l(e){d.selected=e,t(".sbs-square-method-tab").each(function(){const a=t(this).data("method")===e;t(this).css({background:a?"#1d4ed8":"#fff",color:a?"#fff":"#1e3a8a"})}),t(".sbs-square-method-panel").hide(),t("#sbs-square-card-container").toggle("card"===e),t('[data-method-panel="'+e+'"]').show(),t("#sbs-square-payment-status").text(a("apple_pay"===e||"cash_app_pay"===e?"Tap the wallet button above to authorize payment, then booking will continue automatically.":"Payment details are encrypted by Square."))}p.forEach(function(e){t("<button/>",{type:"button",class:"sbs-square-method-tab","data-method":e,text:c[e]||e}).css({border:"1px solid #bfdbfe",background:e===d.selected?"#1d4ed8":"#fff",color:e===d.selected?"#fff":"#1e3a8a",borderRadius:"999px",padding:"8px 12px",fontWeight:"800",cursor:"pointer"}).appendTo(y)}),t(document).off("click.squareMethod").on("click.squareMethod",".sbs-square-method-tab",function(){l(t(this).data("method"))});const m=[];return p.includes("card")&&m.push(i.card().then(function(e){return d.methods.card=e,e.attach("#sbs-square-card-container")})),p.includes("gift_card")&&"function"==typeof i.giftCard&&m.push(i.giftCard().then(function(e){return d.methods.gift_card=e,e.attach("#sbs-square-gift-card-container")}).catch(function(){})),p.includes("apple_pay")&&"function"==typeof i.applePay&&m.push(i.applePay(u).then(function(e){d.methods.apple_pay=e,t("#sbs-square-apple-pay-button").off("click.squareApple").on("click.squareApple",function(t){t.preventDefault(),o._handleSquareWalletButton(n,e,"apple_pay")})}).catch(function(){t('[data-method="apple_pay"], [data-method-panel="apple_pay"]').hide()})),p.includes("google_pay")&&"function"==typeof i.googlePay&&m.push(i.googlePay(u).then(function(e){return d.methods.google_pay=e,e.attach("#sbs-square-google-pay")}).catch(function(){t('[data-method="google_pay"], [data-method-panel="google_pay"]').hide()})),p.includes("cash_app_pay")&&"function"==typeof i.cashAppPay&&m.push(i.cashAppPay(u,{redirectURL:e.location.href,referenceId:"yatoon-"+Date.now()}).then(function(e){return d.methods.cash_app_pay=e,e.addEventListener("ontokenization",function(e){const t=e.detail||{};t.error?o._showToast(a("Cash App Pay could not be authorized."),"error"):t.tokenResult&&"OK"===t.tokenResult.status&&o._finishSquareTokenPayment(n,t.tokenResult.token,"cash_app_pay")}),e.attach("#sbs-square-cash-app-pay")}).catch(function(){t('[data-method="cash_app_pay"], [data-method-panel="cash_app_pay"]').hide()})),Promise.all(m).then(function(){o._squarePaymentState=d,l(d.methods[d.selected]?d.selected:d.methods.card?"card":Object.keys(d.methods)[0]),r(d)})})}).catch(function(e){o._squareCardPromise=null,s(e)})})),this._squareCardPromise}_finishSquareTokenPayment(e,n,o){const r=this;return t("#sbs-square-payment-status").text(a("Completing")+" "+(o||a("Square"))+" "+a("payment...")),this._sendSquareTokenPayment(e,n).then(function(n){return r._squarePreparedPaymentId=n,r._squarePreparedPaymentReference=e.client_reference,r._rememberCheckoutPayment&&r._rememberCheckoutPayment(e.client_reference,"square_payment_id",n),t("#sbs-square-payment-status").text(a("Payment approved by Square. Confirming your booking...")),r._isSubmitting=!1,r.submitBooking(),n}).catch(function(e){throw r._showToast(e&&e.message?e.message:a("Square payment failed. Please try again."),"error"),e})}_handleSquareWalletButton(e,n,o){const r=this;return t("#sbs-square-payment-status").text(a("Opening")+" "+a("apple_pay"===o?"Apple Pay":"Square wallet")+"..."),n.tokenize().then(function(t){if(!t||"OK"!==t.status||!t.token){const e=t&&t.errors&&t.errors.length?t.errors.map(function(e){return e.message}).join(" "):a("The wallet payment was not authorized.");throw new Error(e)}return r._finishSquareTokenPayment(e,t.token,o)}).catch(function(e){t("#sbs-square-payment-status").text(e&&e.message?e.message:a("Wallet payment failed.")),r._showToast(e&&e.message?e.message:a("Wallet payment failed. Please try again."),"error")})}_sendSquareTokenPayment(e,t){const n=new FormData;return Object.keys(e).forEach(function(t){const a=e[t];Array.isArray(a)?a.forEach(function(e){n.append(t+"[]",e)}):n.append(t,null==a?"":a)}),n.set("action","yatoon_square_create_payment"),n.set("source_id",t),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:n,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!(e&&e.success&&e.data&&e.data.payment_id)){const t=e&&e.data&&e.data.message?e.data.message:a("Square payment failed. Please try again.");throw new Error(t)}return e.data.payment_id})}_createSquarePaymentForPayload(e){const n=this;return this._squarePaymentsReady()?this._ensureSquarePaymentCard(e).then(function(e){t("#sbs-square-payment-box").show();const n=document.getElementById("sbs-square-payment-box");n&&n.scrollIntoView({behavior:"smooth",block:"center"});const o=e.selected||"card",r=e.methods[o];if(!r)throw new Error(a("This Square payment method is not available on this device. Please choose another method."));return"cash_app_pay"===o?(t("#sbs-square-payment-status").text(a("Tap the Cash App Pay button above to authorize payment.")),new Promise(function(){})):(t("#sbs-square-payment-status").text(a("Securing your payment with Square...")),r.tokenize())}).then(function(t){if(!t||"OK"!==t.status||!t.token){const e=t&&t.errors&&t.errors.length?t.errors.map(function(e){return e.message}).join(" "):a("Please check your card details and try again.");throw new Error(e)}return n._sendSquareTokenPayment(e,t.token)}).then(function(e){return t("#sbs-square-payment-status").text(a("Payment approved by Square.")),e}).catch(function(e){throw t("#sbs-square-payment-status").text(e&&e.message?e.message:a("Square payment failed.")),n._showToast(e&&e.message?e.message:a("Square payment failed. Please try again."),"error"),e}):Promise.reject(new Error(a("Square payment is enabled but the secure payment form is unavailable.")))}}Object.getOwnPropertyNames(o.prototype).forEach(function(e){"constructor"!==e&&Object.defineProperty(n.prototype,e,Object.getOwnPropertyDescriptor(o.prototype,e))})}}(window,window.jQuery);1 !function(e,t){"use strict";const a=e.wp&&e.wp.i18n&&"function"==typeof e.wp.i18n.__?function(t){return e.wp.i18n.__(t,"yatoon-booking-system")}:function(e){return e},n=e.YatoonSquareBookingForm;if(n&&t){class o{_squarePaymentsReady(){return!!("undefined"!=typeof yatoonData&&yatoonData.squarePaymentsEnabled&&yatoonData.squareApplicationId&&yatoonData.squareLocationId&&e.Square&&"function"==typeof e.Square.payments)}_paymentProviderEnabled(e){return"undefined"!=typeof yatoonData&&("square"===e?!!yatoonData.squarePaymentsEnabled:"paypal"===e?!!yatoonData.paypalPaymentsEnabled:"stripe"===e&&!!yatoonData.depositEnabled)}_ensurePaymentSdk(e){const t={square:()=>this._squarePaymentsReady(),paypal:()=>this._paypalPaymentsReady(),stripe:()=>this._stripePaymentsReady()}[e],n={square:yatoonData.squareSdkUrl,paypal:yatoonData.paypalSdkUrl,stripe:yatoonData.stripeSdkUrl}[e];return t&&t()?Promise.resolve():n?(this._paymentSdkPromises=this._paymentSdkPromises||{},this._paymentSdkPromises[e]||(this._paymentSdkPromises[e]=new Promise(function(o,r){const s=document.createElement("script");s.src=n,s.async=!0,s.dataset.yatoonPaymentSdk=e,s.onload=function(){t&&t()?o():r(new Error(a("The secure payment service did not initialize.")))},s.onerror=function(){r(new Error(a("The secure payment service could not be loaded. Check your connection and try again.")))},document.head.appendChild(s)}).catch(t=>{throw delete this._paymentSdkPromises[e],t})),this._paymentSdkPromises[e]):Promise.reject(new Error(a("The secure payment service is not configured.")))}_paypalPaymentsReady(){return!("undefined"==typeof yatoonData||!yatoonData.paypalPaymentsEnabled||!e.paypal||"function"!=typeof e.paypal.Buttons)}_stripePaymentsReady(){return!("undefined"==typeof yatoonData||!yatoonData.depositEnabled||!yatoonData.stripePublishableKey||"function"!=typeof e.Stripe)}_createStripePaymentForPayload(n){const o=this;return new Promise(function(r,s){if(!o._stripePaymentsReady()){const e=new Error(a("Stripe payment form is not ready. Please refresh and try again."));return e.data={preflight:!0},void s(e)}const i=new FormData;Object.keys(n).forEach(function(e){const t=n[e];Array.isArray(t)?t.forEach(function(t){i.append(e+"[]",t)}):i.append(e,null==t?"":t)}),i.set("action","yatoon_stripe_create_intent"),i.set("nonce",yatoonData.nonce),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:i,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(n){if(n?.success&&n.data?.already_paid&&n.data.intent_id)return void r(n.data.intent_id);if(!(n&&n.success&&n.data&&n.data.client_secret))throw new Error(n&&n.data&&n.data.message?n.data.message:a("Could not start the Stripe payment."));let s=t("#sbs-stripe-payment-box");if(!s.length){s=t(`\n <div id="sbs-stripe-payment-box" style="margin:16px 0;padding:16px;border:1px solid #ddd6fe;border-radius:14px;background:#f5f3ff;">\n <div style="font-size:14px;font-weight:800;color:#2e1065;margin-bottom:6px;">Secure Stripe Payment</div>\n <div id="sbs-stripe-payment-amount" style="font-size:13px;color:#475569;margin-bottom:12px;"></div>\n <div id="sbs-stripe-payment-element"></div>\n <button type="button" id="sbs-stripe-pay-button" style="width:100%;min-height:46px;margin-top:14px;border:0;border-radius:9px;background:#635bff;color:#fff;font-weight:800;cursor:pointer;">${"full"===yatoonData.nativePaymentMode?a("Pay total"):a("Pay deposit")}</button>\n <div id="sbs-stripe-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>`);const e=t("#sbs-booking-form");e.length?e.prepend(s):t(".sbs-step-5").prepend(s)}t("#sbs-stripe-payment-element").empty(),t("#sbs-stripe-payment-amount").text(("full"===yatoonData.nativePaymentMode?a("Full payment due now:"):a("Deposit due now:"))+" "+(n.data.deposit_display||""));const i=e.Stripe(yatoonData.stripePublishableKey),p=i.elements({clientSecret:n.data.client_secret});p.create("payment").mount("#sbs-stripe-payment-element");const d=t("#sbs-stripe-payment-status"),c="full"===yatoonData.nativePaymentMode?a("Pay total"):a("Pay deposit");d.text(""),t("#sbs-stripe-pay-button").prop("disabled",!1).text(c),t("#sbs-stripe-pay-button").off(".yatoonStripe").on("click.yatoonStripe",function(){const e=t(this).prop("disabled",!0).text(a("Processing..."));d.text(a("Confirming your payment securely..."));const n=function(t){e.prop("disabled",!1).text(c),d.text(t),o._showToast(t,"error")};i.confirmPayment({elements:p,redirect:"if_required"}).then(function(e){let t=e.paymentIntent||null;if(e.error&&e.error.payment_intent){const a=e.error.payment_intent.status;"succeeded"!==a&&"processing"!==a||(t=e.error.payment_intent)}if(e.error&&!t)return void n(e.error.message||a("Stripe could not complete the payment."));const o=t?t.status:"";"succeeded"===o||"processing"===o?(d.text(a("processing"===o?"Bank payment submitted. Confirming your appointment...":"Payment approved. Confirming your appointment...")),s.hide(),r(t.id)):n(a("Stripe payment is not complete. Please check your payment details and try again."))}).catch(function(e){n(e&&e.message||a("We could not reach Stripe. Please check your connection and press Pay again."))})}),s.show(),s[0]&&s[0].scrollIntoView&&s[0].scrollIntoView({behavior:"smooth",block:"center"})}).catch(function(e){e&&"object"==typeof e&&(e.data=Object.assign({},e.data,{preflight:!0})),s(e)})})}_createPayPalPaymentForPayload(n){const o=this;return new Promise(function(r,s){if(!o._paypalPaymentsReady())return void s(new Error(a("PayPal Checkout is not ready. Please refresh and try again.")));let i=t("#sbs-paypal-payment-box");if(!i.length){i=t(`\n <div id="sbs-paypal-payment-box" style="margin:16px 0;padding:16px;border:1px solid #bfdbfe;border-radius:14px;background:#eff6ff;">\n <div style="font-size:14px;font-weight:800;color:#172554;margin-bottom:6px;">Secure PayPal Payment</div>\n <div style="font-size:13px;color:#475569;margin-bottom:12px;">${"full"===yatoonData.nativePaymentMode?a("Pay the full appointment total with PayPal to confirm your booking."):a("Choose PayPal below to pay the deposit and confirm your appointment.")}</div>\n <div id="sbs-paypal-button-container"></div>\n <div id="sbs-paypal-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>`);const e=t("#sbs-booking-form");e.length?e.prepend(i):t(".sbs-step-5").prepend(i)}const p=t("#sbs-paypal-payment-status"),d=yatoonData.ajax_url||yatoonData.ajaxUrl;function c(e,t){const o=new FormData;return Object.keys(n).forEach(function(e){const t=n[e];Array.isArray(t)?t.forEach(function(t){o.append(e+"[]",t)}):o.append(e,null==t?"":t)}),o.set("action",e),o.set("nonce",yatoonData.nonce),Object.keys(t||{}).forEach(function(e){o.set(e,t[e])}),fetch(d,{method:"POST",body:o,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!e||!e.success||!e.data)throw new Error(e&&e.data&&e.data.message?e.data.message:a("PayPal payment failed."));return e.data})}t("#sbs-paypal-button-container").empty(),e.paypal.Buttons({style:{layout:"vertical",shape:"rect",label:"paypal"},createOrder:function(){return p.text(a("Preparing secure PayPal Checkout...")),c("yatoon_paypal_create_order").then(function(e){return e.amount_display&&p.text(("full"===yatoonData.nativePaymentMode?a("Full payment due now:"):a("Deposit due now:"))+" "+e.amount_display),e.order_id})},onApprove:function(e){return p.text(a("Confirming your PayPal payment...")),c("yatoon_paypal_capture_order",{order_id:e.orderID}).then(function(t){p.text(a("Payment approved. Confirming your appointment...")),i.hide(),r(t.order_id||e.orderID)}).catch(function(e){p.text(e.message||a("PayPal could not capture the payment.")),o._showToast(e.message||a("PayPal could not capture the payment."),"error"),s(e)})},onCancel:function(){const e=new Error(a("PayPal Checkout was cancelled."));p.text(e.message),s(e)},onError:function(e){p.text(a("PayPal Checkout could not be opened. Please try again.")),o._showToast(e&&e.message?e.message:a("PayPal Checkout failed."),"error"),s(e instanceof Error?e:new Error(a("PayPal Checkout failed.")))}}).render("#sbs-paypal-button-container").then(function(){i.show(),i[0]&&i[0].scrollIntoView&&i[0].scrollIntoView({behavior:"smooth",block:"center"})}).catch(s)})}_squareMethods(){const e=yatoonData&&Array.isArray(yatoonData.squarePaymentMethods)?yatoonData.squarePaymentMethods:["card"];return e.length?e:["card"]}_previewSquarePayment(e){const t=new FormData;return Object.keys(e).forEach(function(a){const n=e[a];Array.isArray(n)?n.forEach(function(e){t.append(a+"[]",e)}):t.append(a,null==n?"":n)}),t.set("action","yatoon_square_preview_payment"),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:t,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!e||!e.success||!e.data){const t=e&&e.data&&e.data.message?e.data.message:a("Could not calculate the Square payment amount.");throw new Error(t)}return e.data})}_buildSquarePaymentRequest(e,t){return e.paymentRequest({countryCode:(yatoonData.squareCountryCode||"US").toUpperCase(),currencyCode:(t.currency||yatoonData.currency||"USD").toUpperCase(),total:{amount:t.amount||"0.00",label:"full"===yatoonData.squarePaymentMode?a("Appointment total"):a("Booking deposit")}})}_ensureSquarePaymentCard(n){const o=this,r=JSON.stringify({services_json:n.services_json||"",service_id:n.service_id||"",selected_options:n.selected_options||[],coupon_code:n.coupon_code||"",customer_email:n.customer_email||"",customer_phone:n.customer_phone||"",client_reference:n.client_reference||"",checkout_token:n.checkout_token||"",start_at:n.start_at||"",location:n.yatoon_location_id||0,tip_amount:n.tip_amount||0,gift_card_code:n.gift_card_code||""});return this._squareCardPromise&&this._squarePaymentPayloadKey===r||(this._squarePaymentPayloadKey=r,this._squareCardPromise=new Promise(function(r,s){if(!o._squarePaymentsReady())return void s(new Error(a("Square payment form is not ready. Please refresh and try again.")));let i=t("#sbs-square-payment-box");if(!i.length){const e="full"===yatoonData.squarePaymentMode?a("Pay securely now to confirm your appointment."):a("Pay your deposit securely now to confirm your appointment.");i=t(`\n <div id="sbs-square-payment-box" class="sbs-square-payment-box" style="margin:16px 0;padding:16px;border:1px solid #dbeafe;border-radius:14px;background:#eff6ff;">\n <div style="font-size:14px;font-weight:800;color:#1e3a8a;margin-bottom:6px;">Secure Square Payment</div>\n <div style="font-size:13px;color:#475569;margin-bottom:12px;">${e}</div>\n <div id="sbs-square-payment-amount" style="font-size:13px;font-weight:800;color:#0f172a;margin-bottom:12px;"></div>\n <div id="sbs-square-method-tabs" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;"></div>\n <button id="sbs-square-apple-pay-button" type="button" class="sbs-square-method-panel" data-method-panel="apple_pay" style="display:none;width:100%;min-height:44px;border-radius:8px;border:0;background:#000;color:#fff;font-weight:800;">Apple Pay</button>\n <div id="sbs-square-google-pay" class="sbs-square-method-panel" data-method-panel="google_pay" style="display:none;"></div>\n <div id="sbs-square-cash-app-pay" class="sbs-square-method-panel" data-method-panel="cash_app_pay" style="display:none;"></div>\n <div id="sbs-square-gift-card-container" class="sbs-square-method-panel" data-method-panel="gift_card" style="display:none;"></div>\n <div id="sbs-square-card-container"></div>\n <div id="sbs-square-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>\n `);const n=t("#sbs-booking-form");n.length?n.prepend(i):t(".sbs-step-5").prepend(i)}t("#sbs-square-payment-status").text(a("Loading secure Square card form...")),o._previewSquarePayment(n).then(function(s){return t("#sbs-square-payment-amount").text(("full"===s.payment_mode?a("Pay now:"):a("Deposit due now:"))+" "+s.amount_display),Promise.resolve(e.Square.payments(yatoonData.squareApplicationId,yatoonData.squareLocationId)).then(function(i){const p=o._squareMethods(),d={payments:i,preview:s,methods:{},selected:p[0]||"card"},c=o._buildSquarePaymentRequest(i,s),u={card:"Card",apple_pay:a("Apple Pay"),google_pay:a("Google Pay"),cash_app_pay:a("Cash App"),gift_card:a("Gift Card")},y=t("#sbs-square-method-tabs").empty();function l(e){d.selected=e,t(".sbs-square-method-tab").each(function(){const a=t(this).data("method")===e;t(this).css({background:a?"#1d4ed8":"#fff",color:a?"#fff":"#1e3a8a"})}),t(".sbs-square-method-panel").hide(),t("#sbs-square-card-container").toggle("card"===e),t('[data-method-panel="'+e+'"]').show(),t("#sbs-square-payment-status").text(a("apple_pay"===e||"cash_app_pay"===e?"Tap the wallet button above to authorize payment, then booking will continue automatically.":"Payment details are encrypted by Square."))}p.forEach(function(e){t("<button/>",{type:"button",class:"sbs-square-method-tab","data-method":e,text:u[e]||e}).css({border:"1px solid #bfdbfe",background:e===d.selected?"#1d4ed8":"#fff",color:e===d.selected?"#fff":"#1e3a8a",borderRadius:"999px",padding:"8px 12px",fontWeight:"800",cursor:"pointer"}).appendTo(y)}),t(document).off("click.squareMethod").on("click.squareMethod",".sbs-square-method-tab",function(){l(t(this).data("method"))});const m=[];return p.includes("card")&&m.push(i.card().then(function(e){return d.methods.card=e,e.attach("#sbs-square-card-container")})),p.includes("gift_card")&&"function"==typeof i.giftCard&&m.push(i.giftCard().then(function(e){return d.methods.gift_card=e,e.attach("#sbs-square-gift-card-container")}).catch(function(){})),p.includes("apple_pay")&&"function"==typeof i.applePay&&m.push(i.applePay(c).then(function(e){d.methods.apple_pay=e,t("#sbs-square-apple-pay-button").off("click.squareApple").on("click.squareApple",function(t){t.preventDefault(),o._handleSquareWalletButton(n,e,"apple_pay")})}).catch(function(){t('[data-method="apple_pay"], [data-method-panel="apple_pay"]').hide()})),p.includes("google_pay")&&"function"==typeof i.googlePay&&m.push(i.googlePay(c).then(function(e){return d.methods.google_pay=e,e.attach("#sbs-square-google-pay")}).catch(function(){t('[data-method="google_pay"], [data-method-panel="google_pay"]').hide()})),p.includes("cash_app_pay")&&"function"==typeof i.cashAppPay&&m.push(i.cashAppPay(c,{redirectURL:e.location.href,referenceId:"yatoon-"+Date.now()}).then(function(e){return d.methods.cash_app_pay=e,e.addEventListener("ontokenization",function(e){const t=e.detail||{};t.error?o._showToast(a("Cash App Pay could not be authorized."),"error"):t.tokenResult&&"OK"===t.tokenResult.status&&o._finishSquareTokenPayment(n,t.tokenResult.token,"cash_app_pay")}),e.attach("#sbs-square-cash-app-pay")}).catch(function(){t('[data-method="cash_app_pay"], [data-method-panel="cash_app_pay"]').hide()})),Promise.all(m).then(function(){o._squarePaymentState=d,l(d.methods[d.selected]?d.selected:d.methods.card?"card":Object.keys(d.methods)[0]),r(d)})})}).catch(function(e){o._squareCardPromise=null,s(e)})})),this._squareCardPromise}_finishSquareTokenPayment(e,n,o){const r=this;return t("#sbs-square-payment-status").text(a("Completing")+" "+(o||a("Square"))+" "+a("payment...")),this._sendSquareTokenPayment(e,n).then(function(n){return r._squarePreparedPaymentId=n,r._squarePreparedPaymentReference=e.client_reference,r._rememberCheckoutPayment&&r._rememberCheckoutPayment(e.client_reference,"square_payment_id",n),t("#sbs-square-payment-status").text(a("Payment approved by Square. Confirming your booking...")),r._isSubmitting=!1,r.submitBooking(),n}).catch(function(e){throw r._showToast(e&&e.message?e.message:a("Square payment failed. Please try again."),"error"),e})}_handleSquareWalletButton(e,n,o){const r=this;return t("#sbs-square-payment-status").text(a("Opening")+" "+a("apple_pay"===o?"Apple Pay":"Square wallet")+"..."),n.tokenize().then(function(t){if(!t||"OK"!==t.status||!t.token){const e=t&&t.errors&&t.errors.length?t.errors.map(function(e){return e.message}).join(" "):a("The wallet payment was not authorized.");throw new Error(e)}return r._finishSquareTokenPayment(e,t.token,o)}).catch(function(e){t("#sbs-square-payment-status").text(e&&e.message?e.message:a("Wallet payment failed.")),r._showToast(e&&e.message?e.message:a("Wallet payment failed. Please try again."),"error")})}_sendSquareTokenPayment(e,t){const n=new FormData;return Object.keys(e).forEach(function(t){const a=e[t];Array.isArray(a)?a.forEach(function(e){n.append(t+"[]",e)}):n.append(t,null==a?"":a)}),n.set("action","yatoon_square_create_payment"),n.set("source_id",t),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:n,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!(e&&e.success&&e.data&&e.data.payment_id)){const t=e&&e.data&&e.data.message?e.data.message:a("Square payment failed. Please try again.");throw new Error(t)}return e.data.payment_id})}_createSquarePaymentForPayload(e){const n=this;return this._squarePaymentsReady()?this._ensureSquarePaymentCard(e).then(function(e){t("#sbs-square-payment-box").show();const n=document.getElementById("sbs-square-payment-box");n&&n.scrollIntoView({behavior:"smooth",block:"center"});const o=e.selected||"card",r=e.methods[o];if(!r)throw new Error(a("This Square payment method is not available on this device. Please choose another method."));return"cash_app_pay"===o?(t("#sbs-square-payment-status").text(a("Tap the Cash App Pay button above to authorize payment.")),new Promise(function(){})):(t("#sbs-square-payment-status").text(a("Securing your payment with Square...")),r.tokenize())}).then(function(t){if(!t||"OK"!==t.status||!t.token){const e=t&&t.errors&&t.errors.length?t.errors.map(function(e){return e.message}).join(" "):a("Please check your card details and try again.");throw new Error(e)}return n._sendSquareTokenPayment(e,t.token)}).then(function(e){return t("#sbs-square-payment-status").text(a("Payment approved by Square.")),e}).catch(function(e){throw t("#sbs-square-payment-status").text(e&&e.message?e.message:a("Square payment failed.")),n._showToast(e&&e.message?e.message:a("Square payment failed. Please try again."),"error"),e}):Promise.reject(new Error(a("Square payment is enabled but the secure payment form is unavailable.")))}}Object.getOwnPropertyNames(o.prototype).forEach(function(e){"constructor"!==e&&Object.defineProperty(n.prototype,e,Object.getOwnPropertyDescriptor(o.prototype,e))})}}(window,window.jQuery); -
yatoon-booking-system/tags/4.10.2/assets/js/yatoon-asset-manifest.json
r3780403 r3780965 1 { 2 "version": "4.10.0", 3 "builder": "terser-5.50.0 + postcss-8.5.6/cssnano-7.1.2/rtlcss-4.3.0", 4 "inputs": { 5 "yatoon-category-bar-423-path16.js": { 6 "sha256": "d9d21e398c540a08d8e07c291b54a5f670616e5c5da35fbff9f3b579b7424cc7", 7 "bytes": 11121 8 }, 9 "frontend.js": { 10 "sha256": "338ebe2b74415737c7616e1e36b62a28028dae5aa2037f6a4b1a5b2bc68a7ded", 11 "bytes": 182985 12 }, 13 "manage-booking.js": { 14 "sha256": "aadbdf0f0c0b4e26eaa5dd4625d79387d7e0f9906cb9a6403cf3626d7d4907c7", 15 "bytes": 36499 16 }, 17 "customer-portal.js": { 18 "sha256": "c139f4be47fa849e90565371e16c10919c697736b0d22dd33ef6d85d3f005707", 19 "bytes": 83590 20 }, 21 "admin-services.js": { 22 "sha256": "7f8c293589fc1f2a4d9be24b19c78668e9b73106ec1eb8cd111f31b5ff88f376", 23 "bytes": 79799 24 }, 25 "admin.js": { 26 "sha256": "4b0851842309bc4e794d67c903f8ae777f93f455a6b69e1729d2f813a88e4b9a", 27 "bytes": 23364 28 }, 29 "admin-settings.js": { 30 "sha256": "0f6928ef9a7c2967f5759ff846bc2492af4faf8490352b9d01f7af4491dc2a64", 31 "bytes": 58129 32 }, 33 "admin-option-groups.js": { 34 "sha256": "dab46594bdf73d1eea2a85e79f976570c34185d9434633483bb086facc2c3f9c", 35 "bytes": 15069 36 }, 37 "frontend-payments.js": { 38 "sha256": "17b903150a7629e803d3c8664642a7a4c3b693f7473bff24216e35375a70cf5c", 39 "bytes": 35380 40 }, 41 "yatoon-concierge-4766.js": { 42 "sha256": "079493bf51ced34a809eb3fbc06079f507070627e247d1955019297acbcb59a1", 43 "bytes": 131985 44 }, 45 "admin-calendar.js": { 46 "sha256": "46ecdfa78ad656102c720dd6deb0e0ef97ca94e758c1b56f5ba9c33b38ce7c9a", 47 "bytes": 36565 48 }, 49 "admin-clients.js": { 50 "sha256": "a42717f6b0c4f1f6515040a218cfa681be7e7d44d82261f6a7e1402c1cb3b2ce", 51 "bytes": 29292 52 }, 53 "admin-bookings.js": { 54 "sha256": "c1f8b151b6d7e097443634572aad2714aeb36cda507f525f7fe5842a6f1d467f", 55 "bytes": 41934 56 }, 57 "admin-staff.js": { 58 "sha256": "b6b6e56b538ed9f2b6768104c7b7cc2bda2d94ffa48ff00932e964b1fe454b89", 59 "bytes": 54358 60 }, 61 "staff-portal.js": { 62 "sha256": "2e36384d5c6d37a7f50d02b21505bdff0cc4c4bb39e247fe9f1edf4f62ceef68", 63 "bytes": 220988 64 }, 65 "frontend-availability.js": { 66 "sha256": "4a271e0ecb0db8a4385331c67ba27776c3c7212aafe4e29e9f9ae49eace017c8", 67 "bytes": 70358 68 }, 69 "frontend-checkout.js": { 70 "sha256": "44d9771ecd3505f72066e6eae910998ff38a2cb5dd4ff8363276f71549e062d2", 71 "bytes": 68665 72 }, 73 "frontend-recovery.js": { 74 "sha256": "f96d9a84be0724732eb6baf4292fa0f5a81a6523f53456de5e880c7cca1ccef8", 75 "bytes": 4566 76 }, 77 "frontend-glass.js": { 78 "sha256": "595c0c6c539d1495470f9597465a863e913fe81f726c7c7824c4f92d5051d66d", 79 "bytes": 1416 80 }, 81 "client-merge-ui.js": { 82 "sha256": "a4f80bea59a75459b0625f295ba486753fd266c8e410d847a640b7f2d9fb31fe", 83 "bytes": 7635 84 }, 85 "staff-hours-editor.js": { 86 "sha256": "9c8f00b26da3dd8c26b9160f5e8e3dd55507743aebaaf84895faa584fce27a96", 87 "bytes": 8209 88 }, 89 "admin-tools.js": { 90 "sha256": "d084fac962bd24d074f636ae04a3e084bf6e22ff4458ba79f57854647cd9c206", 91 "bytes": 6818 92 }, 93 "yatoon-app-shell.js": { 94 "sha256": "801018f7cf5f30cfade4ed8ae3905624df97d3a714a6cf3ec335db094edfc877", 95 "bytes": 9793 96 }, 97 "yatoon-category-bar-4721.js": { 98 "sha256": "3596279a0fb230ed54ae6fc8ba7f7f0dc207c81891ea345b758bc9397085ff68", 99 "bytes": 14196 100 }, 101 "frontend-flow.js": { 102 "sha256": "1529602f4b91c5be53f8c84f3fcd63b10e8f7e295d46697ad1edada2afc62392", 103 "bytes": 233386 104 }, 105 "frontend-cart.js": { 106 "sha256": "24fd1e3756f95e3e9715f5945ee201e1095df68c12fd24d57dbc14a3184296d4", 107 "bytes": 120622 108 }, 109 "frontend-boot.js": { 110 "sha256": "c0d60031a8f1da307ea5e896a747f96616a76de18fa6021e5ddcb8d74fe8ae37", 111 "bytes": 30947 112 }, 113 "yatoon-booking-header.js": { 114 "sha256": "2bb689d5bf4e08a80d27582ee5a4474c029c45b67a7c12da1401bb8e3bdc8aaf", 115 "bytes": 11913 116 }, 117 "yatoon-language-order.js": { 118 "sha256": "599194bba4daf0a4258843f43df0082d3aae7f78c0e0432efc1f281d6527e9d4", 119 "bytes": 2125 120 } 121 }, 122 "outputs": { 123 "frontend.min.js": { 124 "sha256": "2358e461fd346486cc1d89f8702c1bca3e762ffd68863288166a93c03dd38773", 125 "bytes": 78688 126 }, 127 "manage-booking.min.js": { 128 "sha256": "aadbdf0f0c0b4e26eaa5dd4625d79387d7e0f9906cb9a6403cf3626d7d4907c7", 129 "bytes": 36499 130 }, 131 "customer-portal.min.js": { 132 "sha256": "c139f4be47fa849e90565371e16c10919c697736b0d22dd33ef6d85d3f005707", 133 "bytes": 83590 134 }, 135 "admin-services.min.js": { 136 "sha256": "18c487c0411571490cf721d0b30b49f2eff8e60d3d6c662e36d3920b7120c32f", 137 "bytes": 46201 138 }, 139 "admin.min.js": { 140 "sha256": "ff2b431a9d6dc0f5e8c391ca762c27172461acfcf4ff85773bc865e5e9f75c37", 141 "bytes": 10612 142 }, 143 "admin-settings.min.js": { 144 "sha256": "38db0164f533a4edfe41d999727e1f67705d498a8f50f50af0532e10e656ccb0", 145 "bytes": 31390 146 }, 147 "admin-option-groups.min.js": { 148 "sha256": "7bc60b7c3208f3dc3d6380207ed551ed1619d00924c5a62cafa071958fbcef3e", 149 "bytes": 11420 150 }, 151 "frontend-payments.min.js": { 152 "sha256": "e2c70a3d8bde13b32d4016a02835d6a2b2dc63e0171f74ef06ce829609f40925", 153 "bytes": 18861 154 }, 155 "frontend-availability.min.js": { 156 "sha256": "aaa225d5ee3a114a82e1af57be8180d866d140f0ddbab2f81c3059f7c4fdeefb", 157 "bytes": 29644 158 }, 159 "yatoon-category-bar-423-path16.min.js": { 160 "sha256": "a5608fd4415c1dbf4e851a4f207e60c8dd48e96f8ff9e7da3b396f6c71673b7d", 161 "bytes": 6115 162 }, 163 "yatoon-concierge-4766.min.js": { 164 "sha256": "091e689701686070f21841c298121cd67163b6a0214b39a002d4bf96aa5e7652", 165 "bytes": 51279 166 }, 167 "admin-calendar.min.js": { 168 "sha256": "ff82d1459da6b1f422dfd4437df106919891ed8fcc05e756c708513c87cb54d7", 169 "bytes": 18956 170 }, 171 "admin-clients.min.js": { 172 "sha256": "9dea7f478d7b3d9310a1f9c0375bf18ccde5857ce0402a712407d48227dd7dda", 173 "bytes": 17378 174 }, 175 "admin-bookings.min.js": { 176 "sha256": "f6046d4ee5b556126f2ea5d91511dc69d1fef81827bcf9177d14e99344dbe5e1", 177 "bytes": 28731 178 }, 179 "admin-staff.min.js": { 180 "sha256": "3316771f28e0e574ad1ee09f68e993db71dc5943060c7b7a97ed39312a90a7a2", 181 "bytes": 33428 182 }, 183 "staff-portal.min.js": { 184 "sha256": "2e36384d5c6d37a7f50d02b21505bdff0cc4c4bb39e247fe9f1edf4f62ceef68", 185 "bytes": 220988 186 }, 187 "frontend-checkout.min.js": { 188 "sha256": "d45284aad5790bd63b1880dcc05fcb84c600fb771c04ce29dd2e68259b63c51f", 189 "bytes": 27884 190 }, 191 "frontend-recovery.min.js": { 192 "sha256": "fcc85f9e563b837cab4f76d417b20efb3004378b16f34d81e6cc4af405588ff7", 193 "bytes": 3081 194 }, 195 "yatoon-app-shell.min.js": { 196 "sha256": "801018f7cf5f30cfade4ed8ae3905624df97d3a714a6cf3ec335db094edfc877", 197 "bytes": 9793 198 }, 199 "yatoon-category-bar-4721.min.js": { 200 "sha256": "cc9730273303f106ad4ca0a8d11a9723f00d2f4d0ab2d3fd7bccb6f80c2a70aa", 201 "bytes": 7178 202 }, 203 "frontend-flow.min.js": { 204 "sha256": "1529602f4b91c5be53f8c84f3fcd63b10e8f7e295d46697ad1edada2afc62392", 205 "bytes": 233386 206 }, 207 "frontend-cart.min.js": { 208 "sha256": "24fd1e3756f95e3e9715f5945ee201e1095df68c12fd24d57dbc14a3184296d4", 209 "bytes": 120622 210 }, 211 "frontend-boot.min.js": { 212 "sha256": "b83003f71f6a02c18efa96508552fffd4087da007b02ac7a34eb86552b35b234", 213 "bytes": 15656 214 }, 215 "frontend-steps.min.js": { 216 "sha256": "5244218e1cc8c6eda02c5ca557c104a66594ab53b95c1ec740972f2d9b103180", 217 "bytes": 81847 218 }, 219 "frontend.bundle.min.js": { 220 "sha256": "c3a8002ca40541d6d7fc5534d2a8b24aed5a6816e134dcb28b094a7a9ce109ce", 221 "bytes": 448361 222 } 223 }, 224 "css_inputs": { 225 "frontend.css": { 226 "sha256": "41a3b2b765cf4a4a6646664009bbc55e6b848c351061169449290751c94caf5c", 227 "bytes": 274924 228 }, 229 "yatoon-booking-bundle.css": { 230 "sha256": "2b9f874ee912d2a42e2fedb93d045eb82c813e8713301f0a757b0f18cf144473", 231 "bytes": 416 232 }, 233 "yatoon-booking-final.css": { 234 "sha256": "810d51757acea75ec0dbabac87dca581bf4c866dbee37c5d8937bfdbc5991d2b", 235 "bytes": 71386 236 }, 237 "apple-polish.css": { 238 "sha256": "66aefa6e5e9daa980fac6f33ffe95b878f26a2cb50c791222fc368007c6afdb5", 239 "bytes": 10131 240 }, 241 "yatoon-ui-polish.css": { 242 "sha256": "7bfb8a792cadb7412456e45d5e74f30b34749426ce3a8551573c4dedc5e976fb", 243 "bytes": 111082 244 }, 245 "yatoon-design-system.css": { 246 "sha256": "981bbb291a331dff7529dfddec6a3ab176f79f599bb8b983dc76c987109da310", 247 "bytes": 42448 248 }, 249 "yatoon-motion-polish.css": { 250 "sha256": "c7a758608be1b9272933ef4e9cbf0f5d23a4348e5e09731bbc5e51732e14ede7", 251 "bytes": 2103 252 }, 253 "yatoon-category-bar-423-path16.css": { 254 "sha256": "e8b85960ff07b991b0f1b6714358a913a7097537c2a883020e153cb7d9a16c2c", 255 "bytes": 4871 256 }, 257 "yatoon-concierge-4757.css": { 258 "sha256": "8e08fee86c08d37e4dc90787f28a375c0c32bc83ed8dee328336f4e368ab2373", 259 "bytes": 26524 260 }, 261 "admin-calendar.css": { 262 "sha256": "39c78d8120ae664b4c4205c4306c377dc344f948624336dba63a74272823b8d0", 263 "bytes": 21529 264 }, 265 "admin-calendar-rtl.css": { 266 "sha256": "9b3b47f492056ae3186f7ad278955cb154218dfb5f8557c644d29e0ad17e13d2", 267 "bytes": 21529 268 }, 269 "admin-clients.css": { 270 "sha256": "9f38abe8dcb60ad4ee74af66839fffe730e84a1eb9474ca06f1db4374f1e0149", 271 "bytes": 11234 272 }, 273 "admin-clients-rtl.css": { 274 "sha256": "00fe481c7c305a9cd07daf1af8609e276ab05ae32c3bb15f37f32888b28bfeca", 275 "bytes": 11237 276 }, 277 "admin-dashboard.css": { 278 "sha256": "e9e2c37b664f26d1791977676453c6e125bc86330db03566a42348c8354a3fd9", 279 "bytes": 12570 280 }, 281 "yatoon-color-schemes.css": { 282 "sha256": "784d7e6dd912894c3fef4a278e90eb75350f2a3dd0bb12319d5d4e98cbfca872", 283 "bytes": 71724 284 }, 285 "yatoon-theme-preview.css": { 286 "sha256": "707ece181bfb8eb30eb2c54384d02cae9b8638ece567e8150c548dc5ecc01e56", 287 "bytes": 22155 288 }, 289 "yatoon-app-shell.css": { 290 "sha256": "79fe24a1d2852409a46796fa5b6a42a2ca9dfb8be4ed06fbbef4b639eaaff474", 291 "bytes": 32896 292 }, 293 "manage-booking.css": { 294 "sha256": "ccde50e15dc10671de366575dcfa1bc93319aed409a1771d05dd4ec6ed7c76e9", 295 "bytes": 19507 296 }, 297 "staff-portal.css": { 298 "sha256": "b60f1cd59069ad536b5088293f883aa41afa35d0bbcd2c3127783d4e04cb49a9", 299 "bytes": 123789 300 }, 301 "yatoon-seasonal-viewport-4781.css": { 302 "sha256": "347ddefa10bba3327b1918be78913125e55164c643128caac5ceac81a5ca2723", 303 "bytes": 8190 304 }, 305 "frontend-glass.css": { 306 "sha256": "060681cdf1a6b9805f40a6d788b12b39c00e2a6e0007ea57c69e17e9142374a3", 307 "bytes": 664 308 }, 309 "customer-portal.css": { 310 "sha256": "f881d319ad2873eaa0de81cbb060c429744d334a8cfdcfd4e3444623a923d8ab", 311 "bytes": 35043 312 }, 313 "client-merge-ui.css": { 314 "sha256": "d328401272323ca1026ef0928573c09aa3151f16e4d95388362a3dd3f9b0b5ac", 315 "bytes": 2336 316 }, 317 "staff-hours-editor.css": { 318 "sha256": "70a2fac16897f3d9f523a1581f23de04d392f4110841229f064844432be39cd9", 319 "bytes": 2226 320 }, 321 "admin-tools.css": { 322 "sha256": "f3f79f99b46c3e2613175254f54ce06454c952bebbdde278fa05c68ac923e464", 323 "bytes": 14457 324 }, 325 "admin-setup-wizard.css": { 326 "sha256": "11b02bc28c20df7a5189165173103ebab2dba28318ead2520a261f7068953b66", 327 "bytes": 7499 328 }, 329 "yatoon-booking-discovery.css": { 330 "sha256": "8c33bc55568bfd39b9acf0fe0ee1e380e69d475e992477a6909fccac0525b9a0", 331 "bytes": 1231 332 }, 333 "yatoon-booking-header.css": { 334 "sha256": "597726d71d1e251243a7d56ddb6c81a2e51f0af33a345404b87f1b75443a3268", 335 "bytes": 48073 336 } 337 }, 338 "css_outputs": { 339 "frontend-rtl.css": { 340 "sha256": "4fcc61fab31b13e36746b260f9a8658f784ebe5838527d00df96eabd372cf596", 341 "bytes": 274828 342 }, 343 "frontend.min.css": { 344 "sha256": "d755cf890841367223dd97f290d8b933c80681f60cf85f6bcf8100a2373b7662", 345 "bytes": 190078 346 }, 347 "frontend.min-rtl.css": { 348 "sha256": "576231fe623f4559e2cd918368e2d786276f1764680146544cfbf7bf14ae6c2e", 349 "bytes": 189980 350 }, 351 "yatoon-booking-final-rtl.css": { 352 "sha256": "b1846d748cbe4fbc2d95be026aac1e111abe0481e4ec5b1bb11c5d8482bf0506", 353 "bytes": 71396 354 }, 355 "yatoon-booking-final.min.css": { 356 "sha256": "fe13d8069725b96b098a0d233c871c89003553b72b2a677ca8203a8879f3179a", 357 "bytes": 51544 358 }, 359 "yatoon-booking-final.min-rtl.css": { 360 "sha256": "78e4f83c38324104f7c09c6cc3305135741e03feba84077f008402bf04966aec", 361 "bytes": 51554 362 }, 363 "yatoon-booking-core.min.css": { 364 "sha256": "2fe2d03c4426ca02ffefd11ffdbe1477b5f198913b4a8692c62a711884c6dd51", 365 "bytes": 198836 366 }, 367 "yatoon-booking-core.min-rtl.css": { 368 "sha256": "2bbcea4c58e4b31386906c38ef89b5dc3e49bd7d219d24cc669c715e4d2808b6", 369 "bytes": 198905 370 }, 371 "yatoon-booking-flow.min.css": { 372 "sha256": "6e6c980791ec4f5bcc4e09562700835fd86e23c532b5bc6a0654cbef12e1a5f5", 373 "bytes": 90325 374 }, 375 "yatoon-booking-flow.min-rtl.css": { 376 "sha256": "3386631ef8de2623df26cd4f56c077859da5a5b753fef5bfedca98d625fde3b0", 377 "bytes": 90334 378 }, 379 "yatoon-design-system.min.css": { 380 "sha256": "c2cbc79b447e9696a1c82dce32ca5c2acfe40c215f538ff1041856761c036c65", 381 "bytes": 36073 382 }, 383 "yatoon-design-system.min-rtl.css": { 384 "sha256": "570028fe4afa537e34609ec8b6138f0287e2d9364bc057132f23287d249f3bd3", 385 "bytes": 36079 386 }, 387 "yatoon-design-system-rtl.css": { 388 "sha256": "bb8a615fa8d19330e40b55622a4118764e83c5ea5b3ef5db8ae12f2dc2e3d5e8", 389 "bytes": 42454 390 }, 391 "yatoon-concierge-4757.min.css": { 392 "sha256": "c03e6af34c28a629f11f891b00ae6323d81c12ea884fe91a4658855c485a6136", 393 "bytes": 18402 394 }, 395 "admin-calendar.min.css": { 396 "sha256": "33404dd42bf72e0288d745e47835c77a8f943c65cbc975f542581ae1a2cc4116", 397 "bytes": 20844 398 }, 399 "admin-calendar.min-rtl.css": { 400 "sha256": "893162b877b8db9281a895e3de1507b4ce80073e43e1ec969189d8ce6d20ea14", 401 "bytes": 20846 402 }, 403 "admin-clients.min.css": { 404 "sha256": "ce423fecaf41cb6ce16a1caa9c90e7c167169a92ac14d0d8fa67ddf02a618eaa", 405 "bytes": 10182 406 }, 407 "admin-clients.min-rtl.css": { 408 "sha256": "f68db34ec24385cdb44a8e53f21a0d576fa9ae12ac6d8f92ccabff3de3a8278d", 409 "bytes": 10185 410 }, 411 "admin-dashboard.min.css": { 412 "sha256": "0037bfdb2dfaa0bda06d72c6bfb7861dc29a2c85d326857009f1efa7cd361c98", 413 "bytes": 11515 414 }, 415 "admin-dashboard.min-rtl.css": { 416 "sha256": "c8cbf59d96754f7f5d18085462e3ddaf4d6795bfd4980d80ecaf39d13984c80f", 417 "bytes": 11516 418 }, 419 "yatoon-color-schemes.min.css": { 420 "sha256": "2947b3269dad3bfecffd53e411987326c0cf72248955edfe1c6ecb26a88d339e", 421 "bytes": 64203 422 }, 423 "yatoon-color-schemes.min-rtl.css": { 424 "sha256": "2947b3269dad3bfecffd53e411987326c0cf72248955edfe1c6ecb26a88d339e", 425 "bytes": 64203 426 }, 427 "yatoon-theme-preview.min.css": { 428 "sha256": "d7eac486f0adced3d552784675de7c21cef46844c385f80b395c7f8f06441c11", 429 "bytes": 19897 430 }, 431 "yatoon-theme-preview.min-rtl.css": { 432 "sha256": "b0580176744c9922574ce8629527c0a43fa533b095ddcc9769b4d25f64206a2a", 433 "bytes": 19908 434 }, 435 "yatoon-color-schemes-rtl.css": { 436 "sha256": "784d7e6dd912894c3fef4a278e90eb75350f2a3dd0bb12319d5d4e98cbfca872", 437 "bytes": 71724 438 }, 439 "yatoon-theme-preview-rtl.css": { 440 "sha256": "5042c873ed908a826c434c6c83c4ebd053b02942a8e46c70bd9957cb51aabf57", 441 "bytes": 22166 442 }, 443 "yatoon-app-shell-rtl.css": { 444 "sha256": "5bfff9f1a2487fb1f78279a7ac5cd80c67d692012808bc3f8f50cad3bf5c78d0", 445 "bytes": 32908 446 }, 447 "yatoon-app-shell.min.css": { 448 "sha256": "cd9ccb19cbef6a0d42feb7c0c2ae70a23eb04b8693df459778cdc3624d4e439c", 449 "bytes": 23417 450 }, 451 "yatoon-app-shell.min-rtl.css": { 452 "sha256": "c5c52c43dedfa22859427bed065649e2e57df6ea9d6e0ead55ece2b2be1e292f", 453 "bytes": 23425 454 }, 455 "manage-booking-rtl.css": { 456 "sha256": "3ebdcf5de5c267e52ad3cbd47fd7a743501b298cb97532bbfa9dde6001f5777f", 457 "bytes": 19510 458 }, 459 "manage-booking.min.css": { 460 "sha256": "f5d7287ca0ac4cf55a6b63e1fc8b04b63e6e70f043f1f23d32c5bdd52ea8b9ca", 461 "bytes": 13560 462 }, 463 "manage-booking.min-rtl.css": { 464 "sha256": "92c6d808efd9c37c87a618ee97430688d4a8478d28648953b41dff28670a7570", 465 "bytes": 13563 466 }, 467 "staff-portal-rtl.css": { 468 "sha256": "8af62f4563b1ab40a95eb2be04c547ae7e16d9ffa94e7b15d2c8aa8baf3088ac", 469 "bytes": 123823 470 }, 471 "staff-portal.min.css": { 472 "sha256": "b33d5f555a6d1eda7aff23aa4c4ba926143fcad79a5fe68bd6384c44d8a5951e", 473 "bytes": 92450 474 }, 475 "staff-portal.min-rtl.css": { 476 "sha256": "a9d3af72734dd81db4d5ddff67a0b044bb8d2ce041a4d69a66405cfb05f7a788", 477 "bytes": 92481 478 }, 479 "customer-portal-rtl.css": { 480 "sha256": "3a3533ba65af2f364016e4e4ca30ecdc03f47b84a325835ce6b3fc84cc818581", 481 "bytes": 34643 482 }, 483 "customer-portal.min.css": { 484 "sha256": "e886e0d65396c4dd202c93703547e3ec1f111f3be6910f135a951e392615733e", 485 "bytes": 26556 486 }, 487 "customer-portal.min-rtl.css": { 488 "sha256": "dba031b25b63dbcde7ecd9004a71ef4174ba202aceb4e69e9f8590a879cedbf5", 489 "bytes": 26343 490 }, 491 "admin-setup-wizard-rtl.css": { 492 "sha256": "8c2381f5b07e05067b316c10ce4a9333f1ab62714d197bcb85c7ce67e967d676", 493 "bytes": 7502 494 }, 495 "admin-setup-wizard.min.css": { 496 "sha256": "4a9ef36fa5a16fd188b6db80e86a3d825bc786d844a3f1905bcc2facc504d0ba", 497 "bytes": 7046 498 }, 499 "admin-setup-wizard.min-rtl.css": { 500 "sha256": "9cf36af333dae3b82ca7bc98f99ae297e5e59c34ac1766fafb4fa5364bd6e818", 501 "bytes": 7048 502 } 503 }, 504 "frontend_builder": "terser-5.50.0", 505 "staff_portal_builder": "Source-equivalent production JS/CSS; inherited assets retain their original build.", 506 "internal_build": "490-free-20261025-theme-header-lang-picker-compact-languages-ordered-language-picker-mobile-single-brand-row", 507 "css_note": "4.8.2: yatoon-booking-core/flow/final min bundles and frontend/ui-polish/final sources had declarations removed that a later same-selector rule in the same stylesheet always overrides; outputs were edited in place (not rebuilt with cssnano), so hashes are of the shipped files. 4.8.5: core/flow/final min files also had declarations removed that never take effect in the captured cascade and rules for class names the plugin never outputs; outputs edited in place.", 508 "css_bundles": { 509 "yatoon-booking-core.bundle.min.css": { 510 "sha256": "bd16143171cd19aa9b2ef73ee546de2846fe78a8b4b3566d26ec9af34bd85de6", 511 "bytes": 208911, 512 "parts": [ 513 "yatoon-theme-isolation.css", 514 "yatoon-booking-core.min.css" 515 ] 516 }, 517 "yatoon-booking-core.bundle.min-rtl.css": { 518 "sha256": "95a8512c82e3839ce88cae5aaf50236a52e9c57b9abad0bc1a04e62bdbd6d399", 519 "bytes": 208984, 520 "parts": [ 521 "yatoon-theme-isolation.css", 522 "yatoon-booking-core.min-rtl.css" 523 ] 524 }, 525 "yatoon-booking-layers.bundle.min.css": { 526 "sha256": "319ec68f7b14bc6ccb1997f747d36bbab8f985cc73b0c21be51460ba60f96595", 527 "bytes": 79694, 528 "parts": [ 529 "yatoon-color-schemes.min.css", 530 "yatoon-service-image-frame.css", 531 "yatoon-theme-armor-4723.min.css", 532 "yatoon-booking-responsive.min.css" 533 ] 534 }, 535 "yatoon-booking-layers.bundle.min-rtl.css": { 536 "sha256": "0361d779e153376c92d30f991c2ffe1b20f9c39bd6ccd8130ac97f968765d74f", 537 "bytes": 79698, 538 "parts": [ 539 "yatoon-color-schemes.min.css", 540 "yatoon-service-image-frame.css", 541 "yatoon-theme-armor-4723.min.css", 542 "yatoon-booking-responsive.min-rtl.css" 543 ] 544 }, 545 "yatoon-booking-extras.bundle.min.css": { 546 "sha256": "8eb2ad13592a630dc19ff24101d4c69aead136eee39fef404ef6322a46d7d508", 547 "bytes": 9565, 548 "parts": [ 549 "yatoon-seasonal-viewport-4781.css", 550 "yatoon-booking-discovery.css" 551 ] 552 } 553 }, 554 "js_note": "4.8.5: the booking form is split into frontend.js, frontend-flow.js, frontend-cart.js and frontend-boot.js (sources). build_frontend.js generates the lazy chunks frontend-availability.js and frontend-steps.js, every .min.js, and frontend.bundle.min.js.", 555 "css_sources": "4.9.0: assets/css/src/yatoon-booking-core.css and yatoon-booking-flow.css are readable sources with exactly the rules of the shipped .min files; rebuild with csso --no-restructure (keeps rule order), then rtlcss.", 556 "header_note": "Compact local SVG country flags with native details navigation and a circular account control. Header remains visible on step one only.", 557 "cart_note": "Single section dividers and aligned total/duration rows in the mobile drawer; booking calculations are unchanged." 558 } 1 {"version":"4.10.0","builder":"terser-5.50.0 + postcss-8.5.6/cssnano-7.1.2/rtlcss-4.3.0","inputs":{"yatoon-category-bar-423-path16.js":{"sha256":"d9d21e398c540a08d8e07c291b54a5f670616e5c5da35fbff9f3b579b7424cc7","bytes":11121},"frontend.js":{"sha256":"338ebe2b74415737c7616e1e36b62a28028dae5aa2037f6a4b1a5b2bc68a7ded","bytes":182985},"manage-booking.js":{"sha256":"aadbdf0f0c0b4e26eaa5dd4625d79387d7e0f9906cb9a6403cf3626d7d4907c7","bytes":36499},"customer-portal.js":{"sha256":"c139f4be47fa849e90565371e16c10919c697736b0d22dd33ef6d85d3f005707","bytes":83590},"admin-services.js":{"sha256":"7f8c293589fc1f2a4d9be24b19c78668e9b73106ec1eb8cd111f31b5ff88f376","bytes":79799},"admin.js":{"sha256":"4b0851842309bc4e794d67c903f8ae777f93f455a6b69e1729d2f813a88e4b9a","bytes":23364},"admin-settings.js":{"sha256":"0f6928ef9a7c2967f5759ff846bc2492af4faf8490352b9d01f7af4491dc2a64","bytes":58129},"admin-option-groups.js":{"sha256":"dab46594bdf73d1eea2a85e79f976570c34185d9434633483bb086facc2c3f9c","bytes":15069},"frontend-payments.js":{"sha256":"01bcee85136bc3826c39688d57df9082676556080e97185c884c3a63d5497d42","bytes":37720},"yatoon-concierge-4766.js":{"sha256":"079493bf51ced34a809eb3fbc06079f507070627e247d1955019297acbcb59a1","bytes":131985},"admin-calendar.js":{"sha256":"46ecdfa78ad656102c720dd6deb0e0ef97ca94e758c1b56f5ba9c33b38ce7c9a","bytes":36565},"admin-clients.js":{"sha256":"a42717f6b0c4f1f6515040a218cfa681be7e7d44d82261f6a7e1402c1cb3b2ce","bytes":29292},"admin-bookings.js":{"sha256":"c1f8b151b6d7e097443634572aad2714aeb36cda507f525f7fe5842a6f1d467f","bytes":41934},"admin-staff.js":{"sha256":"b6b6e56b538ed9f2b6768104c7b7cc2bda2d94ffa48ff00932e964b1fe454b89","bytes":54358},"staff-portal.js":{"sha256":"2e36384d5c6d37a7f50d02b21505bdff0cc4c4bb39e247fe9f1edf4f62ceef68","bytes":220988},"frontend-availability.js":{"sha256":"4a271e0ecb0db8a4385331c67ba27776c3c7212aafe4e29e9f9ae49eace017c8","bytes":70358},"frontend-checkout.js":{"sha256":"710c9ca74997dd979c4556910328d04a1db66a90a8974282d456701178c7c027","bytes":69189},"frontend-recovery.js":{"sha256":"f96d9a84be0724732eb6baf4292fa0f5a81a6523f53456de5e880c7cca1ccef8","bytes":4566},"frontend-glass.js":{"sha256":"595c0c6c539d1495470f9597465a863e913fe81f726c7c7824c4f92d5051d66d","bytes":1416},"client-merge-ui.js":{"sha256":"a4f80bea59a75459b0625f295ba486753fd266c8e410d847a640b7f2d9fb31fe","bytes":7635},"staff-hours-editor.js":{"sha256":"9c8f00b26da3dd8c26b9160f5e8e3dd55507743aebaaf84895faa584fce27a96","bytes":8209},"admin-tools.js":{"sha256":"d084fac962bd24d074f636ae04a3e084bf6e22ff4458ba79f57854647cd9c206","bytes":6818},"yatoon-app-shell.js":{"sha256":"801018f7cf5f30cfade4ed8ae3905624df97d3a714a6cf3ec335db094edfc877","bytes":9793},"yatoon-category-bar-4721.js":{"sha256":"3596279a0fb230ed54ae6fc8ba7f7f0dc207c81891ea345b758bc9397085ff68","bytes":14196},"frontend-flow.js":{"sha256":"1529602f4b91c5be53f8c84f3fcd63b10e8f7e295d46697ad1edada2afc62392","bytes":233386},"frontend-cart.js":{"sha256":"24fd1e3756f95e3e9715f5945ee201e1095df68c12fd24d57dbc14a3184296d4","bytes":120622},"frontend-boot.js":{"sha256":"c0d60031a8f1da307ea5e896a747f96616a76de18fa6021e5ddcb8d74fe8ae37","bytes":30947},"yatoon-booking-header.js":{"sha256":"2bb689d5bf4e08a80d27582ee5a4474c029c45b67a7c12da1401bb8e3bdc8aaf","bytes":11913},"yatoon-language-order.js":{"sha256":"599194bba4daf0a4258843f43df0082d3aae7f78c0e0432efc1f281d6527e9d4","bytes":2125}},"outputs":{"frontend.min.js":{"sha256":"2358e461fd346486cc1d89f8702c1bca3e762ffd68863288166a93c03dd38773","bytes":78688},"manage-booking.min.js":{"sha256":"aadbdf0f0c0b4e26eaa5dd4625d79387d7e0f9906cb9a6403cf3626d7d4907c7","bytes":36499},"customer-portal.min.js":{"sha256":"c139f4be47fa849e90565371e16c10919c697736b0d22dd33ef6d85d3f005707","bytes":83590},"admin-services.min.js":{"sha256":"18c487c0411571490cf721d0b30b49f2eff8e60d3d6c662e36d3920b7120c32f","bytes":46201},"admin.min.js":{"sha256":"ff2b431a9d6dc0f5e8c391ca762c27172461acfcf4ff85773bc865e5e9f75c37","bytes":10612},"admin-settings.min.js":{"sha256":"38db0164f533a4edfe41d999727e1f67705d498a8f50f50af0532e10e656ccb0","bytes":31390},"admin-option-groups.min.js":{"sha256":"7bc60b7c3208f3dc3d6380207ed551ed1619d00924c5a62cafa071958fbcef3e","bytes":11420},"frontend-payments.min.js":{"sha256":"52b59f072af0b0df01b6d3505820515db57c968c2835c402e8af7fb05365b9d3","bytes":19251},"frontend-availability.min.js":{"sha256":"aaa225d5ee3a114a82e1af57be8180d866d140f0ddbab2f81c3059f7c4fdeefb","bytes":29644},"yatoon-category-bar-423-path16.min.js":{"sha256":"a5608fd4415c1dbf4e851a4f207e60c8dd48e96f8ff9e7da3b396f6c71673b7d","bytes":6115},"yatoon-concierge-4766.min.js":{"sha256":"091e689701686070f21841c298121cd67163b6a0214b39a002d4bf96aa5e7652","bytes":51279},"admin-calendar.min.js":{"sha256":"ff82d1459da6b1f422dfd4437df106919891ed8fcc05e756c708513c87cb54d7","bytes":18956},"admin-clients.min.js":{"sha256":"9dea7f478d7b3d9310a1f9c0375bf18ccde5857ce0402a712407d48227dd7dda","bytes":17378},"admin-bookings.min.js":{"sha256":"f6046d4ee5b556126f2ea5d91511dc69d1fef81827bcf9177d14e99344dbe5e1","bytes":28731},"admin-staff.min.js":{"sha256":"3316771f28e0e574ad1ee09f68e993db71dc5943060c7b7a97ed39312a90a7a2","bytes":33428},"staff-portal.min.js":{"sha256":"2e36384d5c6d37a7f50d02b21505bdff0cc4c4bb39e247fe9f1edf4f62ceef68","bytes":220988},"frontend-checkout.min.js":{"sha256":"bcfbd71409007b50fd60aa869c6bcd1cbad18b86c21b98a9c70696032e1217db","bytes":28012},"frontend-recovery.min.js":{"sha256":"fcc85f9e563b837cab4f76d417b20efb3004378b16f34d81e6cc4af405588ff7","bytes":3081},"yatoon-app-shell.min.js":{"sha256":"801018f7cf5f30cfade4ed8ae3905624df97d3a714a6cf3ec335db094edfc877","bytes":9793},"yatoon-category-bar-4721.min.js":{"sha256":"cc9730273303f106ad4ca0a8d11a9723f00d2f4d0ab2d3fd7bccb6f80c2a70aa","bytes":7178},"frontend-flow.min.js":{"sha256":"1529602f4b91c5be53f8c84f3fcd63b10e8f7e295d46697ad1edada2afc62392","bytes":233386},"frontend-cart.min.js":{"sha256":"24fd1e3756f95e3e9715f5945ee201e1095df68c12fd24d57dbc14a3184296d4","bytes":120622},"frontend-boot.min.js":{"sha256":"b83003f71f6a02c18efa96508552fffd4087da007b02ac7a34eb86552b35b234","bytes":15656},"frontend-steps.min.js":{"sha256":"5244218e1cc8c6eda02c5ca557c104a66594ab53b95c1ec740972f2d9b103180","bytes":81847},"frontend.bundle.min.js":{"sha256":"c3a8002ca40541d6d7fc5534d2a8b24aed5a6816e134dcb28b094a7a9ce109ce","bytes":448361}},"css_inputs":{"frontend.css":{"sha256":"41a3b2b765cf4a4a6646664009bbc55e6b848c351061169449290751c94caf5c","bytes":274924},"yatoon-booking-bundle.css":{"sha256":"2b9f874ee912d2a42e2fedb93d045eb82c813e8713301f0a757b0f18cf144473","bytes":416},"yatoon-booking-final.css":{"sha256":"810d51757acea75ec0dbabac87dca581bf4c866dbee37c5d8937bfdbc5991d2b","bytes":71386},"apple-polish.css":{"sha256":"66aefa6e5e9daa980fac6f33ffe95b878f26a2cb50c791222fc368007c6afdb5","bytes":10131},"yatoon-ui-polish.css":{"sha256":"7bfb8a792cadb7412456e45d5e74f30b34749426ce3a8551573c4dedc5e976fb","bytes":111082},"yatoon-design-system.css":{"sha256":"981bbb291a331dff7529dfddec6a3ab176f79f599bb8b983dc76c987109da310","bytes":42448},"yatoon-motion-polish.css":{"sha256":"c7a758608be1b9272933ef4e9cbf0f5d23a4348e5e09731bbc5e51732e14ede7","bytes":2103},"yatoon-category-bar-423-path16.css":{"sha256":"e8b85960ff07b991b0f1b6714358a913a7097537c2a883020e153cb7d9a16c2c","bytes":4871},"yatoon-concierge-4757.css":{"sha256":"8e08fee86c08d37e4dc90787f28a375c0c32bc83ed8dee328336f4e368ab2373","bytes":26524},"admin-calendar.css":{"sha256":"39c78d8120ae664b4c4205c4306c377dc344f948624336dba63a74272823b8d0","bytes":21529},"admin-calendar-rtl.css":{"sha256":"9b3b47f492056ae3186f7ad278955cb154218dfb5f8557c644d29e0ad17e13d2","bytes":21529},"admin-clients.css":{"sha256":"9f38abe8dcb60ad4ee74af66839fffe730e84a1eb9474ca06f1db4374f1e0149","bytes":11234},"admin-clients-rtl.css":{"sha256":"00fe481c7c305a9cd07daf1af8609e276ab05ae32c3bb15f37f32888b28bfeca","bytes":11237},"admin-dashboard.css":{"sha256":"e9e2c37b664f26d1791977676453c6e125bc86330db03566a42348c8354a3fd9","bytes":12570},"yatoon-color-schemes.css":{"sha256":"784d7e6dd912894c3fef4a278e90eb75350f2a3dd0bb12319d5d4e98cbfca872","bytes":71724},"yatoon-theme-preview.css":{"sha256":"707ece181bfb8eb30eb2c54384d02cae9b8638ece567e8150c548dc5ecc01e56","bytes":22155},"yatoon-app-shell.css":{"sha256":"79fe24a1d2852409a46796fa5b6a42a2ca9dfb8be4ed06fbbef4b639eaaff474","bytes":32896},"manage-booking.css":{"sha256":"ccfdd6c0adbaad8fa3ed2dc8902f0911a65cea4dcecce99bc481ba4306cabc35","bytes":21975},"staff-portal.css":{"sha256":"b60f1cd59069ad536b5088293f883aa41afa35d0bbcd2c3127783d4e04cb49a9","bytes":123789},"yatoon-seasonal-viewport-4781.css":{"sha256":"347ddefa10bba3327b1918be78913125e55164c643128caac5ceac81a5ca2723","bytes":8190},"frontend-glass.css":{"sha256":"060681cdf1a6b9805f40a6d788b12b39c00e2a6e0007ea57c69e17e9142374a3","bytes":664},"customer-portal.css":{"sha256":"f881d319ad2873eaa0de81cbb060c429744d334a8cfdcfd4e3444623a923d8ab","bytes":35043},"client-merge-ui.css":{"sha256":"d328401272323ca1026ef0928573c09aa3151f16e4d95388362a3dd3f9b0b5ac","bytes":2336},"staff-hours-editor.css":{"sha256":"70a2fac16897f3d9f523a1581f23de04d392f4110841229f064844432be39cd9","bytes":2226},"admin-tools.css":{"sha256":"f3f79f99b46c3e2613175254f54ce06454c952bebbdde278fa05c68ac923e464","bytes":14457},"admin-setup-wizard.css":{"sha256":"11b02bc28c20df7a5189165173103ebab2dba28318ead2520a261f7068953b66","bytes":7499},"yatoon-booking-discovery.css":{"sha256":"8c33bc55568bfd39b9acf0fe0ee1e380e69d475e992477a6909fccac0525b9a0","bytes":1231},"yatoon-booking-header.css":{"sha256":"597726d71d1e251243a7d56ddb6c81a2e51f0af33a345404b87f1b75443a3268","bytes":48073}},"css_outputs":{"frontend-rtl.css":{"sha256":"4fcc61fab31b13e36746b260f9a8658f784ebe5838527d00df96eabd372cf596","bytes":274828},"frontend.min.css":{"sha256":"d755cf890841367223dd97f290d8b933c80681f60cf85f6bcf8100a2373b7662","bytes":190078},"frontend.min-rtl.css":{"sha256":"576231fe623f4559e2cd918368e2d786276f1764680146544cfbf7bf14ae6c2e","bytes":189980},"yatoon-booking-final-rtl.css":{"sha256":"b1846d748cbe4fbc2d95be026aac1e111abe0481e4ec5b1bb11c5d8482bf0506","bytes":71396},"yatoon-booking-final.min.css":{"sha256":"fe13d8069725b96b098a0d233c871c89003553b72b2a677ca8203a8879f3179a","bytes":51544},"yatoon-booking-final.min-rtl.css":{"sha256":"78e4f83c38324104f7c09c6cc3305135741e03feba84077f008402bf04966aec","bytes":51554},"yatoon-booking-core.min.css":{"sha256":"2fe2d03c4426ca02ffefd11ffdbe1477b5f198913b4a8692c62a711884c6dd51","bytes":198836},"yatoon-booking-core.min-rtl.css":{"sha256":"2bbcea4c58e4b31386906c38ef89b5dc3e49bd7d219d24cc669c715e4d2808b6","bytes":198905},"yatoon-booking-flow.min.css":{"sha256":"6e6c980791ec4f5bcc4e09562700835fd86e23c532b5bc6a0654cbef12e1a5f5","bytes":90325},"yatoon-booking-flow.min-rtl.css":{"sha256":"3386631ef8de2623df26cd4f56c077859da5a5b753fef5bfedca98d625fde3b0","bytes":90334},"yatoon-design-system.min.css":{"sha256":"c2cbc79b447e9696a1c82dce32ca5c2acfe40c215f538ff1041856761c036c65","bytes":36073},"yatoon-design-system.min-rtl.css":{"sha256":"570028fe4afa537e34609ec8b6138f0287e2d9364bc057132f23287d249f3bd3","bytes":36079},"yatoon-design-system-rtl.css":{"sha256":"bb8a615fa8d19330e40b55622a4118764e83c5ea5b3ef5db8ae12f2dc2e3d5e8","bytes":42454},"yatoon-concierge-4757.min.css":{"sha256":"c03e6af34c28a629f11f891b00ae6323d81c12ea884fe91a4658855c485a6136","bytes":18402},"admin-calendar.min.css":{"sha256":"33404dd42bf72e0288d745e47835c77a8f943c65cbc975f542581ae1a2cc4116","bytes":20844},"admin-calendar.min-rtl.css":{"sha256":"893162b877b8db9281a895e3de1507b4ce80073e43e1ec969189d8ce6d20ea14","bytes":20846},"admin-clients.min.css":{"sha256":"ce423fecaf41cb6ce16a1caa9c90e7c167169a92ac14d0d8fa67ddf02a618eaa","bytes":10182},"admin-clients.min-rtl.css":{"sha256":"f68db34ec24385cdb44a8e53f21a0d576fa9ae12ac6d8f92ccabff3de3a8278d","bytes":10185},"admin-dashboard.min.css":{"sha256":"0037bfdb2dfaa0bda06d72c6bfb7861dc29a2c85d326857009f1efa7cd361c98","bytes":11515},"admin-dashboard.min-rtl.css":{"sha256":"c8cbf59d96754f7f5d18085462e3ddaf4d6795bfd4980d80ecaf39d13984c80f","bytes":11516},"yatoon-color-schemes.min.css":{"sha256":"2947b3269dad3bfecffd53e411987326c0cf72248955edfe1c6ecb26a88d339e","bytes":64203},"yatoon-color-schemes.min-rtl.css":{"sha256":"2947b3269dad3bfecffd53e411987326c0cf72248955edfe1c6ecb26a88d339e","bytes":64203},"yatoon-theme-preview.min.css":{"sha256":"d7eac486f0adced3d552784675de7c21cef46844c385f80b395c7f8f06441c11","bytes":19897},"yatoon-theme-preview.min-rtl.css":{"sha256":"b0580176744c9922574ce8629527c0a43fa533b095ddcc9769b4d25f64206a2a","bytes":19908},"yatoon-color-schemes-rtl.css":{"sha256":"784d7e6dd912894c3fef4a278e90eb75350f2a3dd0bb12319d5d4e98cbfca872","bytes":71724},"yatoon-theme-preview-rtl.css":{"sha256":"5042c873ed908a826c434c6c83c4ebd053b02942a8e46c70bd9957cb51aabf57","bytes":22166},"yatoon-app-shell-rtl.css":{"sha256":"5bfff9f1a2487fb1f78279a7ac5cd80c67d692012808bc3f8f50cad3bf5c78d0","bytes":32908},"yatoon-app-shell.min.css":{"sha256":"cd9ccb19cbef6a0d42feb7c0c2ae70a23eb04b8693df459778cdc3624d4e439c","bytes":23417},"yatoon-app-shell.min-rtl.css":{"sha256":"c5c52c43dedfa22859427bed065649e2e57df6ea9d6e0ead55ece2b2be1e292f","bytes":23425},"manage-booking-rtl.css":{"sha256":"3ebdcf5de5c267e52ad3cbd47fd7a743501b298cb97532bbfa9dde6001f5777f","bytes":19510},"manage-booking.min.css":{"sha256":"431d40da00dd526cb762ebddf10377431e1982b465a3a0943124a28b17c8f444","bytes":16028},"manage-booking.min-rtl.css":{"sha256":"92c6d808efd9c37c87a618ee97430688d4a8478d28648953b41dff28670a7570","bytes":13563},"staff-portal-rtl.css":{"sha256":"8af62f4563b1ab40a95eb2be04c547ae7e16d9ffa94e7b15d2c8aa8baf3088ac","bytes":123823},"staff-portal.min.css":{"sha256":"b33d5f555a6d1eda7aff23aa4c4ba926143fcad79a5fe68bd6384c44d8a5951e","bytes":92450},"staff-portal.min-rtl.css":{"sha256":"a9d3af72734dd81db4d5ddff67a0b044bb8d2ce041a4d69a66405cfb05f7a788","bytes":92481},"customer-portal-rtl.css":{"sha256":"3a3533ba65af2f364016e4e4ca30ecdc03f47b84a325835ce6b3fc84cc818581","bytes":34643},"customer-portal.min.css":{"sha256":"e886e0d65396c4dd202c93703547e3ec1f111f3be6910f135a951e392615733e","bytes":26556},"customer-portal.min-rtl.css":{"sha256":"dba031b25b63dbcde7ecd9004a71ef4174ba202aceb4e69e9f8590a879cedbf5","bytes":26343},"admin-setup-wizard-rtl.css":{"sha256":"8c2381f5b07e05067b316c10ce4a9333f1ab62714d197bcb85c7ce67e967d676","bytes":7502},"admin-setup-wizard.min.css":{"sha256":"4a9ef36fa5a16fd188b6db80e86a3d825bc786d844a3f1905bcc2facc504d0ba","bytes":7046},"admin-setup-wizard.min-rtl.css":{"sha256":"9cf36af333dae3b82ca7bc98f99ae297e5e59c34ac1766fafb4fa5364bd6e818","bytes":7048}},"frontend_builder":"terser-5.50.0","staff_portal_builder":"Source-equivalent production JS/CSS; inherited assets retain their original build.","internal_build":"490-free-20261025-theme-header-lang-picker-compact-languages-ordered-language-picker-mobile-single-brand-row","css_note":"4.8.2: yatoon-booking-core/flow/final min bundles and frontend/ui-polish/final sources had declarations removed that a later same-selector rule in the same stylesheet always overrides; outputs were edited in place (not rebuilt with cssnano), so hashes are of the shipped files. 4.8.5: core/flow/final min files also had declarations removed that never take effect in the captured cascade and rules for class names the plugin never outputs; outputs edited in place.","css_bundles":{"yatoon-booking-core.bundle.min.css":{"sha256":"bd16143171cd19aa9b2ef73ee546de2846fe78a8b4b3566d26ec9af34bd85de6","bytes":208911,"parts":["yatoon-theme-isolation.css","yatoon-booking-core.min.css"]},"yatoon-booking-core.bundle.min-rtl.css":{"sha256":"95a8512c82e3839ce88cae5aaf50236a52e9c57b9abad0bc1a04e62bdbd6d399","bytes":208984,"parts":["yatoon-theme-isolation.css","yatoon-booking-core.min-rtl.css"]},"yatoon-booking-layers.bundle.min.css":{"sha256":"319ec68f7b14bc6ccb1997f747d36bbab8f985cc73b0c21be51460ba60f96595","bytes":79694,"parts":["yatoon-color-schemes.min.css","yatoon-service-image-frame.css","yatoon-theme-armor-4723.min.css","yatoon-booking-responsive.min.css"]},"yatoon-booking-layers.bundle.min-rtl.css":{"sha256":"0361d779e153376c92d30f991c2ffe1b20f9c39bd6ccd8130ac97f968765d74f","bytes":79698,"parts":["yatoon-color-schemes.min.css","yatoon-service-image-frame.css","yatoon-theme-armor-4723.min.css","yatoon-booking-responsive.min-rtl.css"]},"yatoon-booking-extras.bundle.min.css":{"sha256":"8eb2ad13592a630dc19ff24101d4c69aead136eee39fef404ef6322a46d7d508","bytes":9565,"parts":["yatoon-seasonal-viewport-4781.css","yatoon-booking-discovery.css"]}},"js_note":"4.8.5: the booking form is split into frontend.js, frontend-flow.js, frontend-cart.js and frontend-boot.js (sources). build_frontend.js generates the lazy chunks frontend-availability.js and frontend-steps.js, every .min.js, and frontend.bundle.min.js.","css_sources":"4.9.0: assets/css/src/yatoon-booking-core.css and yatoon-booking-flow.css are readable sources with exactly the rules of the shipped .min files; rebuild with csso --no-restructure (keeps rule order), then rtlcss.","header_note":"Compact local SVG country flags with native details navigation and a circular account control. Header remains visible on step one only.","cart_note":"Single section dividers and aligned total/duration rows in the mobile drawer; booking calculations are unchanged."} -
yatoon-booking-system/tags/4.10.2/changelog.txt
r3780403 r3780965 6 6 * Security check: with Strict mode off, a Turnstile check that cannot load (for example behind an ad blocker) no longer blocks a real customer; Strict mode on still blocks. 7 7 * Checkout: a refusal before any payment (security check, booking limit) now shows a message and keeps the form editable instead of switching to the booking-status panel. 8 * Stripe checkout: a payment Stripe refuses (no payment method chosen, card declined, failed verification) now shows the reason and keeps the payment form open so the customer can pay again; it no longer ends the checkout in the booking-status panel. 9 * Orders: a cancelled appointment no longer counts toward the balance due. When every appointment on an order is cancelled the order shows as Cancelled with nothing owed; any deposit kept or refunded stays in the payment history. 10 * Stripe checkout: in a cart with two paid appointments, the second payment form now starts with a working Pay button. Before, it kept the first payment's "Processing..." state and the customer could not pay for the second appointment. 11 * Bookings list: a cart with appointments on different days shows the date range, and each expanded row shows its own day, instead of one long block on the first day. 8 12 * Manage booking: date and time follow the appointments that are still booked after a partial cancel; carts on different days show each day. 9 13 -
yatoon-booking-system/tags/4.10.2/includes/class-yatoon-commerce.php
r3780403 r3780965 81 81 add_action( 'yatoon_booking_created', array( __CLASS__, 'create_for_booking' ), 70, 1 ); 82 82 add_action( 'yatoon_payment_status_changed', array( __CLASS__, 'sync_payment_status' ), 20, 4 ); 83 // 4.10.2: after the cancellation refund (priority 20) so the order shows what is really owed. 84 add_action( 'yatoon_booking_status_changed', array( __CLASS__, 'booking_status_changed' ), 30, 3 ); 83 85 add_action( 'admin_menu', array( __CLASS__, 'add_menu' ), 23 ); 84 86 add_action( 'admin_post_yatoon_record_order_payment', array( __CLASS__, 'record_payment' ) ); … … 602 604 ) ) ); 603 605 $net_paid = max( 0, $paid - $refunds ); 604 $balance = max( 0, (float) $order->total - $net_paid ); 605 $status = $refunds >= $paid && $paid > 0 ? 'refunded' : ( $balance <= 0 ? 'paid' : ( $net_paid > 0 ? 'partial' : 'open' ) ); 606 // 4.10.2: a cancelled appointment is no longer owed. Its line stays on the 607 // order for the record, but it does not count toward the balance due. When 608 // every appointment is cancelled nothing is owed (a tip line included) and 609 // the order is marked cancelled; money kept or refunded stays in the ledger. 610 $lines = yatoon_db_get_row( $wpdb->prepare( 611 "SELECT COUNT(i.booking_id) AS booked, 612 COALESCE(SUM(CASE WHEN LOWER(b.status) IN ('cancelled','canceled','cancelled_by_customer','cancelled_by_seller','declined') THEN 1 ELSE 0 END),0) AS voided, 613 COALESCE(SUM(CASE WHEN LOWER(b.status) IN ('cancelled','canceled','cancelled_by_customer','cancelled_by_seller','declined') THEN i.line_total ELSE 0 END),0) AS voided_total 614 FROM {$wpdb->prefix}yatoon_order_items i 615 LEFT JOIN {$wpdb->prefix}yatoon_bookings b ON b.id=i.booking_id 616 WHERE i.order_id=%d", 617 $order_id 618 ) ); 619 $all_cancelled = $lines && (int) $lines->booked > 0 && (int) $lines->voided >= (int) $lines->booked; 620 $owed = $all_cancelled ? 0.0 : max( 0, (float) $order->total - ( $lines ? (float) $lines->voided_total : 0 ) ); 621 $balance = max( 0, round( $owed - $net_paid, 2 ) ); 622 $status = $refunds >= $paid && $paid > 0 ? 'refunded' : ( $all_cancelled ? 'cancelled' : ( $balance <= 0 ? 'paid' : ( $net_paid > 0 ? 'partial' : 'open' ) ) ); 606 623 $saved_order = yatoon_db_update( 607 624 $wpdb->prefix . 'yatoon_orders', … … 615 632 ); 616 633 return false !== $saved_order && false !== $saved_invoice; 634 } 635 636 /** 4.10.2: refresh the order balance when one of its appointments is cancelled or restored. */ 637 public static function booking_status_changed( $booking_id, $new_status = '', $old_status = '' ) { 638 global $wpdb; 639 $booking_id = absint( $booking_id ); 640 if ( ! $booking_id || (string) $new_status === (string) $old_status ) { 641 return; 642 } 643 $order_ids = array_map( 'absint', (array) yatoon_db_get_col( $wpdb->prepare( 644 "SELECT DISTINCT order_id FROM {$wpdb->prefix}yatoon_order_items WHERE booking_id=%d", 645 $booking_id 646 ) ) ); 647 foreach ( array_filter( $order_ids ) as $order_id ) { 648 self::recalculate( $order_id ); 649 } 617 650 } 618 651 -
yatoon-booking-system/tags/4.10.2/readme.txt
r3780403 r3780965 212 212 * Security check: with Strict mode off, a Turnstile check that cannot load (for example behind an ad blocker) no longer blocks a real customer; Strict mode on still blocks. 213 213 * Checkout: a refusal before any payment (security check, booking limit) now shows a message and keeps the form editable instead of switching to the booking-status panel. 214 * Stripe checkout: a payment Stripe refuses (no payment method chosen, card declined, failed verification) now shows the reason and keeps the payment form open so the customer can pay again; it no longer ends the checkout in the booking-status panel. 215 * Orders: a cancelled appointment no longer counts toward the balance due. When every appointment on an order is cancelled the order shows as Cancelled with nothing owed; any deposit kept or refunded stays in the payment history. 216 * Stripe checkout: in a cart with two paid appointments, the second payment form now starts with a working Pay button. Before, it kept the first payment's "Processing..." state and the customer could not pay for the second appointment. 217 * Bookings list: a cart with appointments on different days shows the date range, and each expanded row shows its own day, instead of one long block on the first day. 214 218 * Manage booking: date and time follow the appointments that are still booked after a partial cancel; carts on different days show each day. 215 219 -
yatoon-booking-system/trunk/admin/views/bookings.php
r3780403 r3780965 367 367 if ( $summary_end && ( ! $get || $summary_end > $get ) ) { $get = $summary_end; } 368 368 } 369 // 4.10.2: label each expanded row with its day when the group covers more than one day (cancelled rows included). 370 $yatoon_group_days = array(); 371 foreach ( $gbks as $yatoon_day_row ) { 372 $yatoon_day_start = yatoon_booking_display_dt( $yatoon_day_row, 'start_time', $_sbs_local_tz, $_sbs_utc_tz ); 373 if ( $yatoon_day_start ) { $yatoon_group_days[ $yatoon_day_start->format( 'Y-m-d' ) ] = true; } 374 } 375 $yatoon_group_multi_day = count( $yatoon_group_days ) > 1; 369 376 $total_price = array_sum(array_column($summary_bookings, 'total_price')); 370 377 $group_statuses = array_unique( array_map( static fn( $b ) => (string) $b->status, $summary_bookings ) ); … … 432 439 <td><span style="font-size:12px;"><?php echo esc_html( $staff_names ); ?></span></td> 433 440 <td> 441 <?php // 4.10.2: a cart can hold appointments on different days; show the date range, not one long block. ?> 442 <?php if ( $gst->format( 'Y-m-d' ) === $get->format( 'Y-m-d' ) ) : ?> 434 443 <strong><?php echo esc_html( $gst->format('M j, Y') ); ?></strong><br> 435 444 <small><?php echo esc_html( $gst->format('g:i A') ); ?> - <?php echo esc_html( $get->format('g:i A') ); ?></small> 445 <?php else : ?> 446 <strong><?php echo esc_html( $gst->format( 'Y' ) === $get->format( 'Y' ) ? $gst->format( 'M j' ) . ' – ' . $get->format( 'M j, Y' ) : $gst->format( 'M j, Y' ) . ' – ' . $get->format( 'M j, Y' ) ); ?></strong><br> 447 <small><?php esc_html_e( 'Several days. Expand for each time.', 'yatoon-booking-system' ); ?></small> 448 <?php endif; ?> 436 449 </td> 437 450 <td><?php echo esc_html( $yatoon_admin_money( $total_price ) ); if ( $cancelled_count ) { echo '<br><small>' . esc_html( $active_bookings ? __( 'Excludes cancelled items', 'yatoon-booking-system' ) : __( 'Cancelled service total', 'yatoon-booking-system' ) ) . '</small>'; } echo wp_kses_post(YATOON_Gift_Cards::summary_html($summary_bookings)); ?></td> … … 493 506 <td><?php echo esc_html($yatoon_booking_row->staff_name ?: 'N/A'); ?></td> 494 507 <td> 495 <small style="color:#0369a1;font-weight:600;"><?php echo esc_html( $yatoon_booking_start_time->format('g:i A') ); ?></small>508 <small style="color:#0369a1;font-weight:600;"><?php echo esc_html( ( $yatoon_group_multi_day ? $yatoon_booking_start_time->format( 'M j' ) . ' · ' : '' ) . $yatoon_booking_start_time->format('g:i A') ); ?></small> 496 509 <small> - <?php echo esc_html( $yatoon_booking_end_time->format('g:i A') ); ?></small> 497 510 </td> -
yatoon-booking-system/trunk/assets/css/manage-booking.css
r3729808 r3780965 737 737 .yatoon-manage-wrap .yatoon-rebook-btn { width:100%; } 738 738 } 739 /* Customer appointment management language menu. */ 740 .yatoon-manage-wrap .sbs-header-language{margin:0;position:relative;font-family:inherit} 741 .yatoon-manage-wrap .sbs-language-picker{position:relative;margin:0;padding:0;border:0} 742 .yatoon-manage-wrap .sbs-language-trigger{display:flex;align-items:center;gap:6px;min-height:40px;padding:7px 9px;border:0;border-radius:999px;background:transparent;color:#111827;font-family:inherit;font-size:13px;font-weight:600;line-height:1.4;cursor:pointer;list-style:none} 743 .yatoon-manage-wrap .sbs-language-trigger::-webkit-details-marker{display:none}.yatoon-manage-wrap .sbs-language-trigger::marker{content:''}.yatoon-manage-wrap .sbs-language-trigger::before,.yatoon-manage-wrap .sbs-language-trigger::after{content:none!important} 744 .yatoon-manage-wrap .sbs-language-flag{display:inline-flex!important;flex:0 0 21px;width:21px!important;height:21px!important;overflow:hidden;border-radius:50%;border:1px solid rgba(128,128,128,.22);box-sizing:border-box} 745 .yatoon-manage-wrap .sbs-language-flag svg{display:block;width:100%!important;height:100%!important;max-width:none!important} 746 .yatoon-manage-wrap .sbs-language-chevron{width:12px;height:12px;flex:0 0 12px}.yatoon-manage-wrap .sbs-language-picker[open] .sbs-language-chevron{transform:rotate(180deg)} 747 .yatoon-manage-wrap .sbs-language-panel{position:absolute;z-index:10004;right:0;top:calc(100% + 5px);box-sizing:border-box;width:min(220px,calc(100vw - 40px));max-height:65vh;overflow:auto;padding:5px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;box-shadow:0 8px 28px rgba(0,0,0,.16)} 748 .yatoon-manage-wrap .sbs-language-picker:not([open]) .sbs-language-panel{display:none!important} 749 .yatoon-manage-wrap .sbs-language-choice{display:flex!important;align-items:center;gap:9px;width:100%;min-height:42px;margin:0;padding:9px;border:0!important;border-radius:8px;background:transparent!important;color:#111827!important;box-shadow:none!important;font-family:inherit;font-size:13px;font-weight:500;line-height:1.4;text-align:left;text-transform:none;cursor:pointer} 750 .yatoon-manage-wrap .sbs-language-choice:hover,.yatoon-manage-wrap .sbs-language-choice[aria-current=true],.yatoon-manage-wrap .sbs-language-trigger:hover{background:#f3f4f6!important}.yatoon-manage-wrap .sbs-language-check{margin-left:auto}.yatoon-manage-wrap .sbs-language-trigger:focus-visible,.yatoon-manage-wrap .sbs-language-choice:focus-visible{outline:2px solid #2563eb;outline-offset:2px} -
yatoon-booking-system/trunk/assets/css/manage-booking.min.css
r3767282 r3780965 1 1 /*! Yatoon Booking System 4.9.0 */.yatoon-manage-wrap{--yatoon-primary-light:#fdf2f8;--yatoon-text:#1f2937;--yatoon-radius:12px;color:var(--yatoon-text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;margin:0 auto;max-width:520px;padding:20px 16px 40px}.yatoon-manage-card{background:#fff;border:1px solid var(--yatoon-border);box-shadow:0 4px 24px rgba(0,0,0,.07)}.yatoon-manage-header{background:var(--yatoon-primary);color:#fff;padding:24px 28px 20px}.yatoon-manage-header h2{font-size:20px;font-weight:700}.yatoon-manage-subtitle{opacity:.85}.yatoon-manage-details{border-bottom:1px solid var(--yatoon-border);padding:20px 28px}.yatoon-manage-row{align-items:baseline;border-bottom:1px solid #f3f4f6;padding:7px 0}.ymr-label{flex:0 0 90px;letter-spacing:.04em;text-transform:uppercase}.yatoon-manage-actions{gap:12px;padding:24px 28px 4px}.yatoon-btn{border:2px solid transparent;border-radius:8px;font-size:14px;font-weight:600;padding:10px 20px;transition:all .15s}.yatoon-btn:disabled{opacity:.6}.yatoon-btn-primary:hover:not(:disabled){filter:brightness(1.1)}.yatoon-btn-outline{background:transparent;border-color:var(--yatoon-primary)}.yatoon-btn-ghost{background:transparent;border-color:var(--yatoon-border)}.yatoon-btn-ghost:hover:not(:disabled){background:#f9fafb}.yatoon-btn-sm{padding:7px 14px}.yatoon-reschedule-panel{background:#fafafa;border-top:1px solid var(--yatoon-border);padding:20px 28px}.yatoon-reschedule-panel h3{font-size:15px}.yatoon-reschedule-date-row{align-items:center;display:flex;flex-wrap:wrap;gap:10px;margin-bottom:16px}.yatoon-reschedule-date-row label{color:var(--yatoon-muted);font-size:13px;font-weight:600}.yatoon-reschedule-date-row input[type=date]{border:1.5px solid var(--yatoon-border);border-radius:7px;outline:none;padding:8px 10px}.yatoon-slots-list{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px}.yatoon-slot-chip{background:#fff;border:1.5px solid var(--yatoon-border);border-radius:20px;cursor:pointer;font-weight:600;padding:8px 14px;transition:all .15s}.yatoon-reschedule-confirm-row{display:flex;gap:10px;margin-top:4px}.yatoon-change-services-help{color:var(--yatoon-muted);font-size:13px;line-height:1.45;margin:-4px 0 14px}.yatoon-change-services-status{border-radius:10px;font-size:14px;line-height:1.5;margin:12px 0;padding:12px 14px}.yatoon-change-services-panel .yatoon-reschedule-confirm-row{flex-wrap:wrap}.yatoon-change-services-panel .yatoon-reschedule-confirm-row .yatoon-btn{flex:1 1 150px}.yatoon-service-change-row{align-items:center;display:grid;gap:10px;grid-template-columns:92px minmax(0,1fr);margin-bottom:12px}.yatoon-service-change-row label{color:var(--yatoon-muted);font-size:13px;font-weight:700}.yatoon-service-change-select,.yatoon-service-change-staff{background:#fff;border:1px solid var(--yatoon-border);border-radius:10px;color:var(--yatoon-text);font-size:14px;min-height:42px;padding:8px 10px;width:100%}.yatoon-service-change-staff-note{color:var(--yatoon-muted);font-size:12px;grid-column:2;margin-top:-4px}.yatoon-service-remove-row{background:#fff;border:1px solid var(--yatoon-border);border-radius:999px;color:#dc2626;cursor:pointer;font-weight:700;grid-column:2;min-height:38px;padding:7px 12px}.yatoon-manage-notice{border-radius:8px;margin:16px 28px;padding:12px 16px}.yatoon-notice-success{background:#d1fae5;color:#065f46}.yatoon-notice-warning{background:#fef3c7;color:#92400e}.yatoon-notice-info{color:#1e40af}.yatoon-manage-error{background:#fee2e2;border-radius:8px;color:#991b1b;padding:14px 18px}.yatoon-manage-footer{border-top:1px solid var(--yatoon-border);padding:16px 28px;text-align:center}.yatoon-after-cancel-actions{display:flex;flex-wrap:wrap;gap:10px;padding:0 28px 18px}.yatoon-after-cancel-actions .yatoon-btn{flex:1 1 180px;justify-content:center}@media (max-width:480px){.yatoon-manage-wrap{padding:12px 8px 32px}.yatoon-manage-actions,.yatoon-manage-details,.yatoon-manage-header,.yatoon-manage-notice,.yatoon-reschedule-panel{padding-left:18px;padding-right:18px}.yatoon-manage-actions{flex-direction:column}.yatoon-after-cancel-actions{flex-direction:column;padding-left:18px;padding-right:18px}.yatoon-btn{justify-content:center}.yatoon-service-change-row{grid-template-columns:1fr}.yatoon-service-change-staff-note,.yatoon-service-remove-row{grid-column:1}}.yatoon-manage-footer .yatoon-manage-return{color:var(--yatoon-text);display:inline-flex;text-decoration:none}.yatoon-manage-footer .yatoon-manage-return:hover{text-decoration:none}.yatoon-manage-wrap{--yatoon-border:#e5e7eb;--yatoon-radius:16px}.yatoon-manage-card{box-shadow:0 14px 36px rgba(15,23,42,.08)}.yatoon-manage-header h2{letter-spacing:0}.ymr-value{color:#111827}.yatoon-btn{border-width:1px;min-height:42px}.yatoon-btn-primary{box-shadow:0 10px 22px rgba(236,72,153,.16)}.yatoon-btn-ghost,.yatoon-btn-outline{background:#fff}.yatoon-reschedule-panel{background:#f8fafc}.yatoon-reschedule-date-row input[type=date]{border-width:1px;min-height:40px}.yatoon-reschedule-date-row input[type=date]:focus{box-shadow:0 0 0 3px rgba(236,72,153,.12)}.yatoon-slot-chip{border-width:1px}.yatoon-manage-wrap{--yatoon-primary:#ec4899;--yatoon-primary-light:rgba(236,72,153,.1);--yatoon-text:#111827;--yatoon-muted:#6b7280;--yatoon-border:rgba(0,0,0,.08);--yatoon-surface:#fff;--yatoon-surface2:#f8fafc;--yatoon-radius:20px;--yatoon-ease:cubic-bezier(.4,0,.2,1);-webkit-font-smoothing:antialiased;font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,Helvetica Neue,Arial,sans-serif}.yatoon-manage-card{background:var(--yatoon-surface);border:1px solid rgba(0,0,0,.08);border-radius:var(--yatoon-radius);box-shadow:0 16px 48px rgba(15,23,42,.11),inset 0 1px 0 hsla(0,0%,100%,.9);overflow:hidden}.yatoon-manage-header{background:#111827;padding:28px 30px 22px}.yatoon-manage-header h2{border:none;color:#fff;font-size:22px;font-weight:900;letter-spacing:-.03em;margin:0 0 4px}.yatoon-manage-subtitle{color:hsla(0,0%,100%,.65);font-size:13px;margin:0}.yatoon-manage-details{border-bottom:1px solid rgba(0,0,0,.06);padding:22px 30px}.yatoon-manage-row{align-items:flex-start;border-bottom:1px solid rgba(0,0,0,.05);display:flex;font-size:14px;gap:16px;justify-content:space-between;padding:8px 0;transition:background .15s}.yatoon-manage-row:last-child{border-bottom:none}.ymr-label{color:var(--yatoon-muted);flex:0 0 100px;font-size:12px;font-weight:700;letter-spacing:0;text-transform:none}.ymr-value{color:var(--yatoon-text);font-weight:600;text-align:right}.yatoon-manage-actions{display:flex;flex-wrap:wrap;gap:10px;padding:22px 30px 8px}.yatoon-btn{align-items:center;border:1px solid transparent;border-radius:999px;cursor:pointer;display:inline-flex;font-size:15px;font-weight:700;gap:6px;letter-spacing:-.01em;min-height:44px;padding:10px 22px;text-decoration:none;transition:all .18s var(--yatoon-ease)}.yatoon-btn:hover{transform:translateY(-1px)}.yatoon-btn:active{transform:scale(.97)}.yatoon-btn:disabled{cursor:not-allowed;opacity:.5;transform:none}.yatoon-btn-primary{background:var(--yatoon-primary);border-color:var(--yatoon-primary);box-shadow:0 6px 18px rgba(236,72,153,.25);color:#fff}.yatoon-btn-primary:hover:not(:disabled){box-shadow:0 10px 26px rgba(236,72,153,.32);filter:brightness(1.06)}.yatoon-btn-outline{background:var(--yatoon-surface);border-color:rgba(236,72,153,.3);color:var(--yatoon-primary)}.yatoon-btn-outline:hover:not(:disabled){background:var(--yatoon-primary-light);border-color:var(--yatoon-primary)}.yatoon-btn-ghost{background:var(--yatoon-surface);border-color:rgba(0,0,0,.12);box-shadow:0 1px 3px rgba(0,0,0,.06);color:var(--yatoon-muted)}.yatoon-btn-ghost:hover:not(:disabled){background:var(--yatoon-surface2);color:var(--yatoon-text)}.yatoon-btn-sm{font-size:13px;min-height:36px;padding:7px 16px}.yatoon-reschedule-panel{background:var(--yatoon-surface2);border-top:1px solid rgba(0,0,0,.07);padding:22px 30px}.yatoon-reschedule-panel h3{color:var(--yatoon-text);font-size:16px;font-weight:800;letter-spacing:-.015em;margin:0 0 16px}.yatoon-reschedule-date-row input[type=date]{background:var(--yatoon-surface);border:1px solid rgba(0,0,0,.14);border-radius:10px;font-size:14px;min-height:42px;transition:border-color .18s,box-shadow .18s}.yatoon-reschedule-date-row input[type=date]:focus{border-color:var(--yatoon-primary);box-shadow:0 0 0 4px rgba(236,72,153,.12);outline:none}.yatoon-slot-chip{background:var(--yatoon-surface);border:1px solid rgba(0,0,0,.1);border-radius:999px;box-shadow:0 1px 3px rgba(0,0,0,.06);color:var(--yatoon-text);font-size:13px;font-weight:700;padding:9px 16px;transition:all .15s var(--yatoon-ease)}.yatoon-slot-chip:hover{border-color:var(--yatoon-primary);box-shadow:0 3px 10px rgba(236,72,153,.15);color:var(--yatoon-primary);transform:translateY(-1px)}.yatoon-slot-chip.selected{background:var(--yatoon-primary);border-color:var(--yatoon-primary);box-shadow:0 4px 14px rgba(236,72,153,.28);color:#fff}.yatoon-manage-notice{border-radius:12px;font-size:14px;font-weight:500;line-height:1.5;margin:14px 30px;padding:13px 16px}.yatoon-notice-success{background:#dcfce7;border-left:3px solid #22c55e;color:#15803d}.yatoon-notice-error{background:#fee2e2;border-left:3px solid #ef4444;color:#991b1b}.yatoon-notice-warning{background:#fef9c3;border-left:3px solid #f59e0b;color:#a16207}.yatoon-notice-info{background:#eff6ff;border-left:3px solid #3b82f6;color:#1d4ed8}.yatoon-manage-footer{background:var(--yatoon-surface2);border-top:1px solid rgba(0,0,0,.06);color:var(--yatoon-muted);font-size:13px;padding:16px 30px}.yatoon-manage-footer a{color:var(--yatoon-primary);font-weight:600;text-decoration:none}.yatoon-manage-footer a:hover{text-decoration:underline}.yatoon-status-pending{color:#d97706;font-weight:700}.yatoon-status-confirmed{color:#059669;font-weight:700}.yatoon-status-completed{color:#6b7280;font-weight:700}.yatoon-status-cancelled,.yatoon-status-cancelled_by_customer{color:#dc2626;font-weight:700}.yatoon-cancel-choice{align-items:flex-start;cursor:pointer;display:inline-flex;gap:10px;justify-content:flex-end}.yatoon-cancel-choice input{flex:0 0 auto;margin-top:3px}.yatoon-cancel-choice span{display:block}@media (max-width:480px){.yatoon-manage-wrap{padding:10px 6px 28px}.yatoon-manage-actions,.yatoon-manage-details,.yatoon-manage-footer,.yatoon-manage-header,.yatoon-manage-notice,.yatoon-reschedule-panel{padding-left:18px;padding-right:18px}.yatoon-manage-actions{flex-direction:column}.yatoon-btn{justify-content:center}}#yatoon-after-cancel-actions.yatoon-after-cancel-actions{align-items:center;display:flex;flex-wrap:wrap;gap:10px;padding:0 30px 18px}#yatoon-after-cancel-actions.yatoon-after-cancel-actions .yatoon-btn{border-radius:14px;box-shadow:none;flex:1 1 180px;font-size:14px;height:auto;line-height:1.2;max-height:48px;min-height:44px;padding:10px 16px}#yatoon-manage-overlay :where(button,a,input,select,textarea,[tabindex]):focus-visible,.yatoon-manage-wrap :where(button,a,input,select,textarea):focus-visible{outline:3px solid #2563eb;outline-offset:3px}@media (prefers-reduced-motion:reduce){#yatoon-manage-overlay *,.yatoon-manage-wrap *{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important}}@media (max-width:480px){#yatoon-after-cancel-actions.yatoon-after-cancel-actions{flex-direction:column;padding-left:18px;padding-right:18px}#yatoon-after-cancel-actions.yatoon-after-cancel-actions .yatoon-btn{flex:0 0 auto;width:100%}}.yatoon-manage-wrap{box-sizing:border-box;min-width:0}.yatoon-manage-wrap .ymr-value{min-width:0;overflow-wrap:anywhere}.yatoon-manage-wrap .yatoon-manage-row{gap:14px}#yatoon-manage-overlay button,.yatoon-manage-wrap :is(.yatoon-btn,input:not([type=checkbox]),select,textarea){border-radius:12px;box-sizing:border-box;line-height:1.35;min-height:44px}.yatoon-manage-wrap .yatoon-btn{text-align:center;white-space:normal}@media(max-width:640px){.yatoon-manage-wrap :is(input:not([type=checkbox]),select,textarea){font-size:16px}.yatoon-manage-wrap .yatoon-manage-row{align-items:flex-start}.yatoon-manage-wrap .ymr-label{flex-basis:85px}}.yatoon-manage-wrap #yatoon-reschedule-btn{background:#15803d!important;border-color:#15803d!important;color:#fff!important}.yatoon-manage-wrap #yatoon-change-services-btn{background:#1d4ed8!important;border-color:#1d4ed8!important;color:#fff!important}.yatoon-manage-wrap #yatoon-cancel-btn{background:#b91c1c!important;border-color:#b91c1c!important;color:#fff!important}.yatoon-manage-wrap #yatoon-reschedule-btn:hover{background:#166534!important}.yatoon-manage-wrap #yatoon-change-services-btn:hover{background:#1e40af!important}.yatoon-manage-wrap #yatoon-cancel-btn:hover{background:#991b1b!important}.yatoon-manage-wrap .yatoon-slot-chip{background:#fff!important;border:1px solid #cbd5e1!important;color:#111827!important;min-height:44px}.yatoon-manage-wrap .yatoon-slot-chip:hover{background:#f1f5f9!important}.yatoon-manage-wrap .yatoon-slot-chip.selected{background:#fce7f3!important;border:2px solid #be185d!important;color:#111827!important}.yatoon-manage-wrap .yatoon-manage-rebook{margin:0;padding:0 30px 18px}.yatoon-manage-wrap .yatoon-rebook-btn{background:#15803d!important;border-color:#15803d!important;color:#fff!important;justify-content:center;min-height:44px!important;text-decoration:none!important}.yatoon-manage-wrap .yatoon-rebook-btn:hover{background:#166534!important}@media(max-width:480px){.yatoon-manage-wrap .yatoon-manage-rebook{padding-inline:18px}.yatoon-manage-wrap .yatoon-rebook-btn{width:100%}} 2 3 /* Customer appointment management language menu. */ 4 .yatoon-manage-wrap .sbs-header-language{margin:0;position:relative;font-family:inherit} 5 .yatoon-manage-wrap .sbs-language-picker{position:relative;margin:0;padding:0;border:0} 6 .yatoon-manage-wrap .sbs-language-trigger{display:flex;align-items:center;gap:6px;min-height:40px;padding:7px 9px;border:0;border-radius:999px;background:transparent;color:#111827;font-family:inherit;font-size:13px;font-weight:600;line-height:1.4;cursor:pointer;list-style:none} 7 .yatoon-manage-wrap .sbs-language-trigger::-webkit-details-marker{display:none}.yatoon-manage-wrap .sbs-language-trigger::marker{content:''}.yatoon-manage-wrap .sbs-language-trigger::before,.yatoon-manage-wrap .sbs-language-trigger::after{content:none!important} 8 .yatoon-manage-wrap .sbs-language-flag{display:inline-flex!important;flex:0 0 21px;width:21px!important;height:21px!important;overflow:hidden;border-radius:50%;border:1px solid rgba(128,128,128,.22);box-sizing:border-box} 9 .yatoon-manage-wrap .sbs-language-flag svg{display:block;width:100%!important;height:100%!important;max-width:none!important} 10 .yatoon-manage-wrap .sbs-language-chevron{width:12px;height:12px;flex:0 0 12px}.yatoon-manage-wrap .sbs-language-picker[open] .sbs-language-chevron{transform:rotate(180deg)} 11 .yatoon-manage-wrap .sbs-language-panel{position:absolute;z-index:10004;right:0;top:calc(100% + 5px);box-sizing:border-box;width:min(220px,calc(100vw - 40px));max-height:65vh;overflow:auto;padding:5px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;box-shadow:0 8px 28px rgba(0,0,0,.16)} 12 .yatoon-manage-wrap .sbs-language-picker:not([open]) .sbs-language-panel{display:none!important} 13 .yatoon-manage-wrap .sbs-language-choice{display:flex!important;align-items:center;gap:9px;width:100%;min-height:42px;margin:0;padding:9px;border:0!important;border-radius:8px;background:transparent!important;color:#111827!important;box-shadow:none!important;font-family:inherit;font-size:13px;font-weight:500;line-height:1.4;text-align:left;text-transform:none;cursor:pointer} 14 .yatoon-manage-wrap .sbs-language-choice:hover,.yatoon-manage-wrap .sbs-language-choice[aria-current=true],.yatoon-manage-wrap .sbs-language-trigger:hover{background:#f3f4f6!important}.yatoon-manage-wrap .sbs-language-check{margin-left:auto}.yatoon-manage-wrap .sbs-language-trigger:focus-visible,.yatoon-manage-wrap .sbs-language-choice:focus-visible{outline:2px solid #2563eb;outline-offset:2px} -
yatoon-booking-system/trunk/assets/js/frontend-checkout.js
r3780403 r3780965 988 988 }) 989 989 .catch(function(error) { 990 // 4.10.2: the Stripe form could not open, so nothing was charged. 991 // On the first appointment, let the customer simply try again. 992 if (idx === 0 && error && error.data && error.data.preflight) { 993 self._showToast(error.message || __('Stripe payment could not be started.'), 'error'); 994 restoreSubmitButtons(); 995 return; 996 } 990 997 self._showBookingRecovery({reference:payload.client_reference,failedIndex:idx,message:error.message,uncertain:true}); 991 998 self._showToast(error && error.message ? error.message : __('Stripe payment could not be started.'), 'error'); -
yatoon-booking-system/trunk/assets/js/frontend-checkout.min.js
r3780403 r3780965 1 !function(e,t){"use strict";const o=e.wp?.i18n?.__?t=>e.wp.i18n.__(t,"yatoon-booking-system"):e=>e,{ysSiteNow:n,ysSiteOffsetMin:s,ysFormatMoney:a,ysPriceVaries:i,ysMoneyFrom:r,ysCalcDeposit:c,validateBookingPhone:d,validateUSPhone:l,showFieldError:u,showPhoneError:m,validateCustomerName:g,validateCustomerEmail:f,ysFocusTrap:p}=e.YatoonBookingHelpers;class _{_paidCheckoutKey(e){return"yatoon-checkout:"+location.pathname+":"+e}_forgetPaidCheckout(e){if(e)try{sessionStorage.removeItem(this._paidCheckoutKey(e))}catch(e){}}_unresolvedPaidCheckout(e){const t=this._paidCheckoutKey("");try{for(let o=0;o<sessionStorage.length;o++){const n=sessionStorage.key(o);if(!n||0!==n.indexOf(t))continue;const s=n.slice(t.length);if(!s||s===e)continue;const a=JSON.parse(sessionStorage.getItem(n)||"null");if(a&&a.payment&&a.payment.id&&!a.resolved)return s}}catch(e){}return""}_showPaidRecoveryNotice(e,n){const s=this,a=t("#sbs-booking-recovery");a.length&&(a.addClass("sbs-booking-recovery-paid"),a.find("h3").first().text(o("Payment received, appointment not confirmed yet")),a.find(".sbs-booking-recovery-guidance").text(o('Your payment went through, but this appointment could not be confirmed. Please do not pay again. Use "Check payment and appointment status" to finish it, or contact the salon with the reference below so they can confirm another time or refund you.')),n&&!a.find(".sbs-paid-recovery-resolved").length&&t("<button/>",{type:"button",class:"sbs-paid-recovery-resolved",text:o("The salon has resolved this payment")}).appendTo(a.find(".sbs-booking-recovery-actions")).on("click",function(){try{const t=s._paidCheckoutKey(e),o=JSON.parse(sessionStorage.getItem(t)||"null");o&&(o.resolved=!0,sessionStorage.setItem(t,JSON.stringify(o)))}catch(e){}s._clearBookingRecovery(),s._saveSession()}))}submitBooking(){const n=this;if(this._handleBookingRecoveryAttempt())return;if(this._paymentsConfigured()&&"function"!=typeof this._ensurePaymentSdk){if(this._submissionChunkPromise)return;const e=t(".sbs-btn-submit").prop("disabled",!0).text(o("Loading secure payment..."));return void(this._submissionChunkPromise=this._loadFeatureChunk("payments").then(function(){n._submissionChunkPromise=null,e.prop("disabled",!1),n._applyConfirmBtn(),n.submitBooking()}).catch(function(t){n._submissionChunkPromise=null,e.prop("disabled",!1),n._applyConfirmBtn(),n._showToast(t.message||o("The secure payment component could not be loaded."),"error")}))}if(this._isSubmitting)return;if(this.designUploadInProgress)return void this._showToast(o("Please wait for the reference photo to finish uploading."),"info");if(!this._paymentsConfigured()&&(!this._turnstileTokenFetched||Date.now()>(this._turnstileTokenExpires||0))&&"function"==typeof e.yatoonGetTurnstileToken)return this._turnstileTokenFetched=!0,void e.yatoonGetTurnstileToken().then(function(t){e.yatoonTurnstileToken=t,n._turnstileTokenFetched=!0,n._turnstileTokenExpires=Date.now()+9e4,n.submitBooking()}).catch(function(){n._turnstileTokenFetched=!1,n._turnstileTokenExpires=0,n._showToast(o("Verification could not finish. Please try again."),"error")});const s=document.getElementById("sbs-otp-section"),a="undefined"!=typeof yatoonData&&"1"===yatoonData.verifyEmailOtp,i="undefined"!=typeof yatoonData&&"1"===yatoonData.verifySmsOtp;if(s&&(a||i)){const e=(document.getElementById("sbs-customer-email")||{}).value||"",t=(document.getElementById("sbs-customer-phone")||{}).value||"",a=e.trim()+"|"+t.trim();s.dataset.sentContact&&s.dataset.sentContact!==a&&(s.dataset.sent="",s.dataset.sentContact="");const r="1"===s.dataset.verified&&s.dataset.verifiedContact===a;"1"!==s.dataset.verified||r||(s.dataset.verified="",s.dataset.verifiedKey="");const c=function(e){const t=String(e||"").replace(/\D/g,"");return 11===t.length&&"1"===t.charAt(0)?t.slice(1):t},l=i?""!==c(s.dataset.verifiedPhone)&&c(t)===c(s.dataset.verifiedPhone):!!s.dataset.verifiedEmail&&e.trim().toLowerCase()===s.dataset.verifiedEmail.toLowerCase(),g=s.dataset.deviceVerified===a;if(!r&&!l&&!g){const r=f(e);if(r){u("sbs-customer-email",r);const e=document.getElementById("sbs-customer-email");return void(e&&e.scrollIntoView({behavior:"smooth",block:"center"}))}if(i){const e=d(t);if(e){m(e);const t=document.getElementById("sbs-phone-display")||document.getElementById("sbs-customer-phone");return void(t&&t.scrollIntoView({behavior:"smooth",block:"center"}))}}if(s.dataset.deviceChecked!==a)return void jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_otp_device_check",nonce:yatoonData.nonce,email:e,phone:t},function(e){s.dataset.deviceChecked=a,e&&e.success&&e.data&&e.data.verified&&(s.dataset.deviceVerified=a),n.submitBooking()}).fail(function(){s.dataset.deviceChecked=a,n.submitBooking()});const c=(document.getElementById("sbs-customer-name")||{}).value||"",l=i?"sms":"email";s.style.display="block";const g=document.getElementById("sbs-otp-remember");if(g&&"1"===g.dataset.regionAuto&&!g.dataset.regionChecked){g.dataset.regionChecked="1";let e="";try{e=Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch(t){e=""}const t=/^Europe\/(Moscow|Minsk|Kaliningrad|Samara|Volgograd|Kirov|Astrakhan|Saratov|Ulyanovsk|Simferopol|Istanbul|Kiev|Kyiv|Uzhgorod|Zaporozhye|Chisinau|Tirane|Skopje|Sarajevo|Belgrade|Podgorica)$/;(/^Europe\//.test(e)&&!t.test(e)||/^Atlantic\/(Reykjavik|Madeira|Azores|Canary)$/.test(e))&&(g.checked=!1)}if(document.getElementById("sbs-otp-prompt").textContent="sms"===l?o("We are sending a verification code to your phone. Please enter it below."):o("We are sending a verification code to")+" "+e+". "+o("Please enter it below."),!s.dataset.sent){s.dataset.sent="1",s.dataset.sentContact=a;const n=document.getElementById("sbs-otp-msg"),i=document.getElementById("sbs-otp-resend-btn");n&&(n.textContent=o("Sending verification code..."),n.style.color=""),i&&(i.disabled=!0),jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_send_otp",nonce:yatoonData.nonce,channel:l,email:e,phone:t,name:c},function(e){const t=!(!e||!e.success);n&&(n.textContent=t?e.data&&e.data.message?e.data.message:o("Verification code sent."):e&&e.data&&e.data.message?e.data.message:o("Failed to send code.")),i&&(i.style.display=""),i&&(i.disabled=!1),t||(s.dataset.sent="",s.dataset.sentContact="",n&&(n.style.color="#dc2626"))}).fail(function(){s.dataset.sent="",s.dataset.sentContact="",n&&(n.textContent=o("Could not send the verification code. Please try again."),n.style.color="#dc2626"),i&&(i.style.display="",i.disabled=!1)})}const p=document.getElementById("sbs-otp-verify-btn");p&&!p.dataset.bound&&(p.dataset.bound="1",p.addEventListener("click",function(){const e=(document.getElementById("sbs-otp-input")||{}).value||"",t=document.getElementById("sbs-otp-msg"),a=(document.getElementById("sbs-customer-email")||{}).value||"",i=(document.getElementById("sbs-customer-phone")||{}).value||"",r=a.trim()+"|"+i.trim();e.trim()?(p.disabled=!0,p.dataset.pending="1",t&&(t.textContent=o("Verifying..."),t.style.color=""),jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_verify_otp",nonce:yatoonData.nonce,channel:l,email:a,phone:i,code:e,remember:document.getElementById("sbs-otp-remember")&&document.getElementById("sbs-otp-remember").checked?1:0},function(e){e.success?(s.dataset.verified="1",s.dataset.verifiedKey=e.data&&e.data.verified_key?e.data.verified_key:"",n._giftSubmissionQuote=null,n._dynamicQuoteKey="",s.dataset.verifiedContact=r,s.style.display="none",n.submitBooking()):(t&&(t.textContent=e.data&&e.data.message?e.data.message:o("Incorrect code.")),t&&(t.style.color="#dc2626"),p.disabled=!1,p.dataset.pending="")}).fail(function(){t&&(t.textContent=o("Could not verify the code. Please try again."),t.style.color="#dc2626"),p.disabled=!1,p.dataset.pending=""})):t&&(t.textContent=o("Enter the verification code first."),t.style.color="#dc2626")}));const _=document.getElementById("sbs-otp-resend-btn");return void(_&&!_.dataset.bound&&(_.dataset.bound="1",_.addEventListener("click",function(){if(_.disabled)return;s.dataset.sent="",s.dataset.sentContact="",s.dataset.verified="",s.dataset.verifiedKey="",s.dataset.verifiedContact="";const e=document.getElementById("sbs-otp-msg");e&&(e.textContent=""),n.submitBooking()})))}}if(this._isSubmitting=!0,this._clearBookingRecovery(),0===this.bookingCart.length&&this.selectedDateTime&&(this.pendingServices.length>0||this.selectedService)&&this.addToCart(),0===this.bookingCart.length)return this._isSubmitting=!1,void this._showToast(o("Please add at least one service to your booking."),"error");const r=t(".sbs-btn-submit"),c=t("#sbs-cart-next-btn"),l=t("#sbs-sidebar-next-btn"),g=r.text(),p=c.text(),_=l.text(),h=()=>{this._isSubmitting=!1,this._turnstileTokenFetched=!1,r.prop("disabled",!1).text(g),c.prop("disabled",!1).removeClass("sbs-submitting").text(p||o("Confirm Booking")),l.prop("disabled",!1).removeClass("sbs-submitting").text(_||o("Confirm Booking")),this._applyConfirmBtn(),this._updateMobileCartBar()};r.prop("disabled",!0).text(o("Confirming your booking...")),c.prop("disabled",!0).addClass("sbs-submitting").text("CONFIRMING..."),l.prop("disabled",!0).addClass("sbs-submitting").text("CONFIRMING..."),this._updateLegalBoxes();const y={customer_name:t("#sbs-customer-name").val(),customer_email:t("#sbs-customer-email").val(),customer_phone:t("#sbs-customer-phone").val(),client_timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||"",notes:t("#sbs-customer-notes").val(),coupon_code:t("#sbs-coupon-code").length?t("#sbs-coupon-code").val():"",marketing_email_optin:t("#sbs-marketing-email-optin").is(":checked")?1:0,marketing_sms_optin:t("#sbs-marketing-sms-optin").is(":checked")?1:0,consent_accepted:t("#sbs-consent-accepted").length&&t("#sbs-consent-accepted").is(":checked")?1:0,consent_signature:t("#sbs-consent-signature").length?t("#sbs-consent-signature").val():"",policy_acknowledged:t("#sbs-policy-acknowledged").length&&t("#sbs-policy-acknowledged").is(":checked")?1:0,tip_amount:parseFloat(t("#sbs-tip-amount").val())||0,gift_card_code:t("#sbs-gift-card-code-confirmed").val()||"",custom_fields:function(){const e={};return t('[name^="cf["]').each(function(){const o=t(this).attr("name").replace(/^cf\[|\]$/g,"");t(this).is(":checkbox")||t(this).is(":radio")?t(this).is(":checked")&&(e[o]=t(this).val()):e[o]=t(this).val()}),JSON.stringify(e)}()},b=this._collectGuestContacts(),k=f(y.customer_email);if(k)return h(),u("sbs-customer-email",k),void(document.getElementById("sbs-customer-email")&&document.getElementById("sbs-customer-email").scrollIntoView({behavior:"smooth",block:"center"}));"undefined"!=typeof yatoonData&&yatoonData.phoneMode&&yatoonData.phoneMode;if(y.customer_phone){const e=d(y.customer_phone);if(e)return h(),m(e),void(document.getElementById("sbs-customer-phone")&&document.getElementById("sbs-customer-phone").scrollIntoView({behavior:"smooth",block:"center"}))}if(this._needsPolicyAck()&&!y.policy_acknowledged)return h(),this._showToast(o("Please review and acknowledge the cancellation / no-show policy before booking."),"error"),void this._focusBookingValidation(t("#sbs-policy-acknowledged"),t(".sbs-policy-box:visible").first());if(this._needsConsent()&&(!y.consent_accepted||!y.consent_signature.trim())){h(),this._showToast(o("Please read and sign the consent form before booking."),"error");const e=y.consent_accepted?t("#sbs-consent-signature"):t("#sbs-consent-accepted");return void this._focusBookingValidation(e,t(".sbs-consent-box:visible").first())}const v=this.bookingCart.slice(),C=[],w=JSON.stringify(v.map(e=>({start:e.dateTime&&e.dateTime.start_at,guest:e.guestLabel||"Me",services:(e.services||[{service:e.service,options:e.options,staff:e.staff}]).map(t=>({service:t.service&&t.service.id,options:(t.options||[]).map(e=>e.id),staff:t.staff&&t.staff.id||0,guest:t.guestLabel||e.guestLabel||"Me"}))}))),T=this._newBookingReference(w), I="undefined"!=typeof yatoonData&&(yatoonData.ajax_url||yatoonData.ajaxUrl)?yatoonData.ajax_url||yatoonData.ajaxUrl:"";if(!I)return h(),void this._showToast(o("Booking could not start because the WordPress AJAX URL is missing. Please refresh and try again."),"error");if(!v.length)return h(),void this._showToast(o("Please choose a service and time before confirming."),"error");const S=v.some(e=>e&&e.services&&e.services.length>1),P=v.length>1||S?"yatoon-"+T:"";let x=this.designUploadAttachmentId||0,B=this.designUploadToken||"";const D=o=>{const s=v[o],a=s.services||[{service:s.service,options:s.options,staff:s.staff}],i=s.dateTime&&s.dateTime.staff_map?s.dateTime.staff_map:null,r="string"==typeof i?function(){try{return JSON.parse(i)}catch(e){return null}}():i,c={},d={};a.forEach(function(e,t){const o=void 0!==e._originalIndex?e._originalIndex:t;s.dateTime.local_staff_map&&Number(s.dateTime.local_staff_map[o])>0&&(d[t]=Number(s.dateTime.local_staff_map[o])),r&&void 0!==r[o]&&(c[t]=r[o])});const l=Object.keys(c).length?JSON.stringify(c):i?"string"==typeof i?i:JSON.stringify(i):"",u=s.guestLabel||a[0]&&a[0].guestLabel||"Me",m=b[u]||{};let g=y.notes||"";if("Me"!==u){const e=[`Guest: ${u}`];m.name&&e.push(`Name: ${m.name}`),m.phone&&e.push(`Phone: ${m.phone}`),g=`${g}${g?"\n\n":""}${e.join(" - ")}`}const f={},p=new Date(s.dateTime.start_at).getTime(),_=a.map(e=>{const t=e.guestLabel||s.guestLabel||"Me",o=f[t]||0,a=Number.isFinite(p)?new Date(p+6e4*o).toISOString():s.dateTime.start_at;return f[t]=o+n._serviceDuration(e),{service_id:e.service.id,staff_id:e.staff?e.staff.id:0,gender_preference:n._genderPreferenceFor(e),option_ids:e.options.map(e=>e.id),guest_label:t,start_at:a,design_attachment_id:parseInt(e.designAttachmentId||0,10)||0,design_upload_token:String(e.designUploadToken||"")}});return{action:"yatoon_create_booking",nonce:yatoonData.nonce,client_reference:`${T}-${o+1}`,start_at:s.dateTime.start_at,local_staff_map_json:JSON.stringify(d),staff_map_json:l,services_json:JSON.stringify(_),service_id:a[0].service.id,staff_id:a[0].staff?a[0].staff.id:0,gender_preference:n._genderPreferenceFor(a[0]),selected_options:a[0].options.map(e=>e.id),notes:g,guest_label:u,guest_name:m.name||"",guest_phone:m.phone||"",booking_group_id:P,coupon_code:y.coupon_code,tip_amount:0===o?y.tip_amount:0,gift_card_code:n._giftSubmissionQuote?.cart[o]?.gift_card_amount>0?y.gift_card_code||n._giftCode:"",gift_card_amount:n._giftSubmissionQuote?.cart[o]?.gift_card_amount||0,custom_fields:y.custom_fields,customer_name:y.customer_name,customer_email:y.customer_email,customer_phone:y.customer_phone,otp_channel:"undefined"!=typeof yatoonData&&"1"===yatoonData.verifySmsOtp?"sms":"email",otp_verified_key:document.getElementById("sbs-otp-section")&&document.getElementById("sbs-otp-section").dataset.verifiedKey?document.getElementById("sbs-otp-section").dataset.verifiedKey:"",marketing_email_optin:y.marketing_email_optin,marketing_sms_optin:y.marketing_sms_optin,consent_accepted:y.consent_accepted,consent_signature:y.consent_signature,policy_acknowledged:y.policy_acknowledged,client_timezone:y.client_timezone,design_attachment_id:x||"",design_upload_token:B||"",website:t("#sbs-website").val()||"",form_rendered_at:t("#sbs-form-rendered-at").val()||"",cf_turnstile_response:void 0!==e.yatoonTurnstileToken?e.yatoonTurnstileToken:"",yatoon_test_booking:t(".sbs-booking-container").hasClass("yatoon-test-mode")?"1":""}},E=()=>{v.length<2||!n._paymentsConfigured()?F(0):n._loadFeatureChunk("recovery").then(async()=>{for(let e=0;e<v.length;e++)try{await n._prepareCheckout(D(e))}catch(t){throw t.cartIndex=e,t}}).then(()=>F(0)).catch(e=>{const t=e&&"number"==typeof e.cartIndex?e.cartIndex:0;if(e&&e.data&&e.data.preflight)return n._showToast(e.message,"error"),void h();n._showBookingRecovery({reference:`${T}-${t+1}`,failedIndex:t,confirmedCount:0,message:e&&e.message||o("This appointment is no longer available. Please choose another time."),uncertain:!1}),h()})},F=s=>{if(s>=v.length){if(C.every(e=>e&&e.success)){const s=C.find(e=>e&&e.success&&e.data&&e.data.woocommerce_checkout_url);if(s&&s.data.woocommerce_checkout_url)return this.bookingConfirmed=!0,this._clearSession(),void e.location.assign(s.data.woocommerce_checkout_url);this.bookingConfirmed=!0,t(".sbs-form-step").removeClass("active"),t(".sbs-step-success").show(),this._updateStepAccordion(),this._markBookingFlowComplete(),t("#sbs-success-count").text(v.length);const a=1!==v.length;t("#sbs-success-booking-word").text(o(a?"Bookings":"Booking"));const i=this._confirmedBookingItems(v,C);this._renderSuccessBookingSummary(i);const r=C.filter(e=>e&&e.success&&e.data&&e.data.manage_url&&String(e.data.manage_url).length),d=r.length&&r[0].data?r[0].data.manage_url:"",u=C.find(e=>e&&e.success&&e.data&&e.data.calendar_url&&String(e.data.calendar_url).length),m=u&&u.data?u.data.calendar_url:"",g=yatoonData.portalUrl||"",f=yatoonData.portalLabel||o("My Appointments"),p=t("#sbs-success-actions").empty();if(t("<div/>",{class:"sbs-success-action-note",text:yatoonData.successNote||o("Your appointment is booked. Save this page or use the manage link below if you need to change services, reschedule, or cancel.")}).appendTo(p),d&&1===r.length&&t("<a/>",{class:"sbs-success-action-link primary",href:d,target:"_blank",rel:"noopener",text:"undefined"!=typeof yatoonData&&yatoonData.isPro?o("Change services, reschedule, or cancel"):o("Reschedule or cancel")}).appendTo(p),r.length>1){const e=t("<div/>",{class:"sbs-success-manage-list"}).appendTo(p),n=v.some(e=>e.guestLabel&&"Me"!==e.guestLabel);r.forEach((s,a)=>{const i=v[a],r=i&&i.guestLabel&&"Me"!==i.guestLabel?i.guestLabel:null;let c;if(r)c=o("Change or cancel for")+" "+r;else if(n)c=o("Change or cancel my appointment");else{const e=s.data&&s.data.service_name?s.data.service_name:o("Appointment")+" "+(a+1);c=o("Change or cancel:")+" "+e}t("<a/>",{class:"sbs-success-action-link compact",href:s.data.manage_url,target:"_blank",rel:"noopener",text:c}).appendTo(e)})}if(m&&!t("#sbs-success-cal-row").length&&t("<a/>",{class:"sbs-success-action-link",href:m,text:o("Add to calendar")}).appendTo(p),g&&t("<a/>",{class:"sbs-success-action-link",href:g,text:f}).appendTo(p),t("<button/>",{type:"button",class:"sbs-success-action-link sbs-success-book-again"+(d?"":" primary"),text:o("Book again")}).appendTo(p),p.show(),m){t("#sbs-cal-ics").attr("href",m);const e=C.find(e=>e&&e.success&&e.data&&(e.data.start_at||e.data.start_time)),n=i[0]||null,s=n&&n.dateTime?n.dateTime.start_at:"",a=n?this._getItemVisitDuration(n):0,r=s?new Date(s):null,c=r&&!isNaN(r.getTime())&&a?new Date(r.getTime()+6e4*a).toISOString():"",d=e&&e.data&&(e.data.start_at||e.data.start_time)||s,l=e&&e.data&&(e.data.end_at||e.data.end_time)||c;if(d&&l){const e=function(e){const t=new Date(e);return isNaN(t.getTime())?"":t.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"Z")},s=(n?n.services||[{service:n.service}]:[]).map(e=>e.service&&e.service.name).filter(Boolean).join(", "),a=encodeURIComponent((yatoonData.businessName||o("Appointment"))+(s?" - "+s:"")),i=encodeURIComponent(e(d)),r=encodeURIComponent(e(l)),c=encodeURIComponent(yatoonData&&yatoonData.siteTimezone?yatoonData.siteTimezone:Intl.DateTimeFormat().resolvedOptions().timeZone);i&&r?t("#sbs-cal-google").attr("href","https://calendar.google.com/calendar/render?action=TEMPLATE&text="+a+"&dates="+i+"/"+r+"&ctz="+c):t("#sbs-cal-google").attr("href",m)}else t("#sbs-cal-google").attr("href",m);t("#sbs-success-cal-row").show()}yatoonData.rebookingNudgeText&&(t("#sbs-rebooking-nudge .sbs-rebooking-text").text(yatoonData.rebookingNudgeText),t("#sbs-rebooking-nudge .sbs-rebooking-btn").text(yatoonData.rebookingNudgeBtn||o("Book next visit")),setTimeout(function(){t("#sbs-rebooking-nudge").fadeIn(400)},1200));const _=C.find(e=>e&&e.success&&e.data&&e.data.booking_id);if(_&&_.data.manage_token&&t("#sbs-recurring-setup").length){const e=_.data.booking_id,n=_.data.manage_token;let s=2;setTimeout(function(){t("#sbs-recurring-setup").fadeIn(400)},2e3),t(document).on("click",".sbs-freq-btn",function(){t(".sbs-freq-btn").removeClass("active"),t(this).addClass("active"),s=parseInt(t(this).data("weeks"))}),t(document).on("click","#sbs-recurring-confirm",function(){const a=t(this).prop("disabled",!0).text(o("Setting up...")),i=parseInt(t("#sbs-recurring-count").val())||6;t.post(ajaxurl,{action:"yatoon_setup_recurring",nonce:yatoonData.nonce,yatoon_location_id:parseInt(yatoonData.locationId||0,10),booking_id:e,manage_token:n,frequency_weeks:s,total_count:i},function(e){const n=t("#sbs-recurring-result");e.success?(a.text(o("Done")),n.removeClass("error").text(e.data.message).show()):(a.prop("disabled",!1).text(o("Try again")),n.addClass("error").text(e.data&&e.data.message||o("Could not set up recurring.")).show())}).fail(function(){a.prop("disabled",!1).text(o("Try again")),t("#sbs-recurring-result").addClass("error").text(o("Network error. Please try again.")).show()})})}n.bookingCart=[],n.pendingServices=[],n._clearSession(),n._clearBookingRecovery(),n._bookingAttemptReference="",n._bookingAttemptFingerprint="",n._giftCode="",n._giftSubmissionQuote=null,t("#sbs-gift-card-code-confirmed").val(""),n._hideMobileCartBar(),n._closeDrawer(),n._isSubmitting=!1,h(),c.hide(),l.hide()}else{const e=C.filter(e=>!e||!e.success),t=e.map(e=>e&&e.data&&e.data.message?e.data.message:"").filter(Boolean).join(" "),s=t?`\n\nDetails: ${t}`:"",a=C.length-e.length;n._showToast(`${a} booking(s) confirmed, but ${e.length} failed. Please contact us.${s}`,"error");const i=e[0]&&e[0].data?e[0].data:{};n._showBookingRecovery({reference:i.reference||T,failedIndex:a,confirmedCount:a,message:t||o("One or more appointments were not confirmed."),safeToRetry:!0===i.retry_safe}),h()}return}const a=D(s),i=document.getElementById("sbs-design-reference"),r=i&&i.files&&i.files[0]?i.files[0]:null;let d=a,u=!0,m="application/x-www-form-urlencoded; charset=UTF-8";r&&!x&&(d=new FormData,Object.keys(a).forEach(function(e){const t=a[e];Array.isArray(t)?t.forEach(function(t){d.append(e+"[]",t)}):d.append(e,t)}),d.append("design_reference",r),u=!1,m=!1);const g=function(){t.ajax({url:I,type:"POST",timeout:9e4,data:d,processData:u,contentType:m,success:function(e,i,r){try{if("string"==typeof e){const t=e.indexOf("{"),o=e.lastIndexOf("}"),n=t>=0&&o>t?e.slice(t,o+1):e;e=JSON.parse(n)}if(C.push(e),!e||!e.success){const t=e&&e.data&&e.data.message?e.data.message:"",i=t?`\n\nDetails: ${t}`:"",r=C.length-1;n._showToast(`${r} booking(s) confirmed, but appointment ${s+1} failed. Please contact us.${i}`,"error");const c=e&&e.data?e.data:{},l=!!function(){const e=["deposit_intent_id","paypal_order_id","square_payment_id"];for(let t=0;t<e.length;t++){const o=d instanceof FormData?d.get(e[t]):d[e[t]];if(o)return String(o)}return""}();return n._showBookingRecovery({reference:a.client_reference||c.reference||`${T}-${s+1}`,failedIndex:s,confirmedCount:r,message:t||o("The appointment was not confirmed."),safeToRetry:!0===c.retry_safe&&!l,uncertain:!0===c.outcome_uncertain||l}),l&&n._showPaidRecoveryNotice(a.client_reference),void h()}n._forgetPaidCheckout(a.client_reference),e.data&&e.data.design_attachment_id&&(x=parseInt(e.data.design_attachment_id,10)||x,n.designUploadAttachmentId=x),e.data&&e.data.design_upload_token&&(B=String(e.data.design_upload_token||""),n.designUploadToken=B),F(s+1)}catch(a){if(console.error(o("Yatoon booking submit failed after server response:"),a),n.bookingConfirmed||t(".sbs-step-success:visible").length>0)return;const i=r&&r.responseText?String(r.responseText):"string"==typeof e?e:"";if(i&&-1!==i.indexOf('"success":true'))return C.push({success:!0,data:{}}),void F(s+1);n._showToast(o("We could not read the booking confirmation response. Please check the booking list before trying again."),"error"),n._showBookingRecovery({reference:`${T}-${s+1}`,failedIndex:s,confirmedCount:C.filter(e=>e&&e.success).length,message:o("We could not verify the server response."),uncertain:!0}),h()}},error:function(e,t){C.push({success:!1});const a=C.length-1,i="timeout"===t?"the request timed out":"a network error";n._showToast(`${a} booking(s) confirmed, but appointment ${s+1} failed due to ${i}. Please contact us.`,"error"),n._showBookingRecovery({reference:`${T}-${s+1}`,failedIndex:s,confirmedCount:a,message:o("timeout"===t?"The request timed out.":"The network connection was interrupted."),uncertain:!0}),h()}})},f=function(){const e=(e,t)=>{n._rememberCheckoutPayment&&n._rememberCheckoutPayment(a.client_reference,e,t),n._giftSubmissionQuote&&(n._giftSubmissionQuote.payments=n._giftSubmissionQuote.payments||{},n._giftSubmissionQuote.payments[s]={field:e,id:t},n._saveSession())},t=n._checkoutSavedPayment||n._giftSubmissionQuote?.payments?.[s];n._checkoutSavedPayment=null;const i=t?"":n._unresolvedPaidCheckout(a.client_reference);if(i)return n._showBookingRecovery({reference:i,failedIndex:s,confirmedCount:s,message:o("A payment for an earlier attempt was received, but that appointment is not confirmed yet."),uncertain:!0}),n._showPaidRecoveryNotice(i,!0),void h();t?(d instanceof FormData?d.set(t.field,t.id):d[t.field]=t.id,g()):a.gift_card_code&&0===n._giftSubmissionQuote?.cart[s]?.amount_due?g():n._squarePreparedPaymentId&&n._squarePreparedPaymentReference===a.client_reference?(e("square_payment_id",n._squarePreparedPaymentId),d instanceof FormData?d.set("square_payment_id",n._squarePreparedPaymentId):d.square_payment_id=n._squarePreparedPaymentId,n._squarePreparedPaymentId="",n._squarePreparedPaymentReference="",g()):n._paymentProviderEnabled("square")?n._ensurePaymentSdk("square").then(function(){return n._createSquarePaymentForPayload(a)}).then(function(t){e("square_payment_id",t),d instanceof FormData?d.set("square_payment_id",t):d.square_payment_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("Square payment could not be started."),"error"),h()}):n._paymentProviderEnabled("paypal")?n._ensurePaymentSdk("paypal").then(function(){return n._createPayPalPaymentForPayload(a)}).then(function(t){e("paypal_order_id",t),d instanceof FormData?d.set("paypal_order_id",t):d.paypal_order_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("PayPal Checkout could not be started."),"error"),h()}):n._paymentProviderEnabled("stripe")?n._ensurePaymentSdk("stripe").then(function(){return n._createStripePaymentForPayload(a)}).then(function(t){e("deposit_intent_id",t),d instanceof FormData?d.set("deposit_intent_id",t):d.deposit_intent_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("Stripe payment could not be started."),"error"),h()}):g()};n._paymentsConfigured()?n._loadFeatureChunk("recovery").then(()=>n._prepareCheckout(a)).then(e=>{d instanceof FormData?d.set("checkout_token",a.checkout_token):d.checkout_token=a.checkout_token,n._checkoutSavedPayment=e.payment||null,f()}).catch(e=>{const t=!!(e&&e.data&&e.data.preflight);if(t&&0===s)return n._showToast(e.message,"error"),void h();n._showBookingRecovery({reference:a.client_reference,failedIndex:s,confirmedCount:s,message:e.message,uncertain:!t}),h()}):f()};try{if(y.gift_card_code||n._giftCode){(n._giftSubmissionQuote?Promise.resolve(n._giftSubmissionQuote):n._fetchGiftQuote(parseFloat(y.tip_amount)||0)).then(e=>{n._giftSubmissionQuote=e,n._saveSession(),n._renderGiftQuote(e),E()}).catch(e=>{n._showToast(e.message,"error"),n._isSubmitting=!1,h()})}else E()}catch(e){console.error(o("Yatoon booking submit error:"),e),this._showToast(o("Something went wrong before the booking could be sent. Please refresh and try again."),"error"),h()}}}Object.getOwnPropertyNames(_.prototype).filter(e=>"constructor"!==e).forEach(t=>e.YatoonSquareBookingForm.prototype[t]=_.prototype[t])}(window,window.jQuery);1 !function(e,t){"use strict";const o=e.wp?.i18n?.__?t=>e.wp.i18n.__(t,"yatoon-booking-system"):e=>e,{ysSiteNow:n,ysSiteOffsetMin:s,ysFormatMoney:a,ysPriceVaries:i,ysMoneyFrom:r,ysCalcDeposit:c,validateBookingPhone:d,validateUSPhone:l,showFieldError:u,showPhoneError:m,validateCustomerName:g,validateCustomerEmail:f,ysFocusTrap:p}=e.YatoonBookingHelpers;class _{_paidCheckoutKey(e){return"yatoon-checkout:"+location.pathname+":"+e}_forgetPaidCheckout(e){if(e)try{sessionStorage.removeItem(this._paidCheckoutKey(e))}catch(e){}}_unresolvedPaidCheckout(e){const t=this._paidCheckoutKey("");try{for(let o=0;o<sessionStorage.length;o++){const n=sessionStorage.key(o);if(!n||0!==n.indexOf(t))continue;const s=n.slice(t.length);if(!s||s===e)continue;const a=JSON.parse(sessionStorage.getItem(n)||"null");if(a&&a.payment&&a.payment.id&&!a.resolved)return s}}catch(e){}return""}_showPaidRecoveryNotice(e,n){const s=this,a=t("#sbs-booking-recovery");a.length&&(a.addClass("sbs-booking-recovery-paid"),a.find("h3").first().text(o("Payment received, appointment not confirmed yet")),a.find(".sbs-booking-recovery-guidance").text(o('Your payment went through, but this appointment could not be confirmed. Please do not pay again. Use "Check payment and appointment status" to finish it, or contact the salon with the reference below so they can confirm another time or refund you.')),n&&!a.find(".sbs-paid-recovery-resolved").length&&t("<button/>",{type:"button",class:"sbs-paid-recovery-resolved",text:o("The salon has resolved this payment")}).appendTo(a.find(".sbs-booking-recovery-actions")).on("click",function(){try{const t=s._paidCheckoutKey(e),o=JSON.parse(sessionStorage.getItem(t)||"null");o&&(o.resolved=!0,sessionStorage.setItem(t,JSON.stringify(o)))}catch(e){}s._clearBookingRecovery(),s._saveSession()}))}submitBooking(){const n=this;if(this._handleBookingRecoveryAttempt())return;if(this._paymentsConfigured()&&"function"!=typeof this._ensurePaymentSdk){if(this._submissionChunkPromise)return;const e=t(".sbs-btn-submit").prop("disabled",!0).text(o("Loading secure payment..."));return void(this._submissionChunkPromise=this._loadFeatureChunk("payments").then(function(){n._submissionChunkPromise=null,e.prop("disabled",!1),n._applyConfirmBtn(),n.submitBooking()}).catch(function(t){n._submissionChunkPromise=null,e.prop("disabled",!1),n._applyConfirmBtn(),n._showToast(t.message||o("The secure payment component could not be loaded."),"error")}))}if(this._isSubmitting)return;if(this.designUploadInProgress)return void this._showToast(o("Please wait for the reference photo to finish uploading."),"info");if(!this._paymentsConfigured()&&(!this._turnstileTokenFetched||Date.now()>(this._turnstileTokenExpires||0))&&"function"==typeof e.yatoonGetTurnstileToken)return this._turnstileTokenFetched=!0,void e.yatoonGetTurnstileToken().then(function(t){e.yatoonTurnstileToken=t,n._turnstileTokenFetched=!0,n._turnstileTokenExpires=Date.now()+9e4,n.submitBooking()}).catch(function(){n._turnstileTokenFetched=!1,n._turnstileTokenExpires=0,n._showToast(o("Verification could not finish. Please try again."),"error")});const s=document.getElementById("sbs-otp-section"),a="undefined"!=typeof yatoonData&&"1"===yatoonData.verifyEmailOtp,i="undefined"!=typeof yatoonData&&"1"===yatoonData.verifySmsOtp;if(s&&(a||i)){const e=(document.getElementById("sbs-customer-email")||{}).value||"",t=(document.getElementById("sbs-customer-phone")||{}).value||"",a=e.trim()+"|"+t.trim();s.dataset.sentContact&&s.dataset.sentContact!==a&&(s.dataset.sent="",s.dataset.sentContact="");const r="1"===s.dataset.verified&&s.dataset.verifiedContact===a;"1"!==s.dataset.verified||r||(s.dataset.verified="",s.dataset.verifiedKey="");const c=function(e){const t=String(e||"").replace(/\D/g,"");return 11===t.length&&"1"===t.charAt(0)?t.slice(1):t},l=i?""!==c(s.dataset.verifiedPhone)&&c(t)===c(s.dataset.verifiedPhone):!!s.dataset.verifiedEmail&&e.trim().toLowerCase()===s.dataset.verifiedEmail.toLowerCase(),g=s.dataset.deviceVerified===a;if(!r&&!l&&!g){const r=f(e);if(r){u("sbs-customer-email",r);const e=document.getElementById("sbs-customer-email");return void(e&&e.scrollIntoView({behavior:"smooth",block:"center"}))}if(i){const e=d(t);if(e){m(e);const t=document.getElementById("sbs-phone-display")||document.getElementById("sbs-customer-phone");return void(t&&t.scrollIntoView({behavior:"smooth",block:"center"}))}}if(s.dataset.deviceChecked!==a)return void jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_otp_device_check",nonce:yatoonData.nonce,email:e,phone:t},function(e){s.dataset.deviceChecked=a,e&&e.success&&e.data&&e.data.verified&&(s.dataset.deviceVerified=a),n.submitBooking()}).fail(function(){s.dataset.deviceChecked=a,n.submitBooking()});const c=(document.getElementById("sbs-customer-name")||{}).value||"",l=i?"sms":"email";s.style.display="block";const g=document.getElementById("sbs-otp-remember");if(g&&"1"===g.dataset.regionAuto&&!g.dataset.regionChecked){g.dataset.regionChecked="1";let e="";try{e=Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch(t){e=""}const t=/^Europe\/(Moscow|Minsk|Kaliningrad|Samara|Volgograd|Kirov|Astrakhan|Saratov|Ulyanovsk|Simferopol|Istanbul|Kiev|Kyiv|Uzhgorod|Zaporozhye|Chisinau|Tirane|Skopje|Sarajevo|Belgrade|Podgorica)$/;(/^Europe\//.test(e)&&!t.test(e)||/^Atlantic\/(Reykjavik|Madeira|Azores|Canary)$/.test(e))&&(g.checked=!1)}if(document.getElementById("sbs-otp-prompt").textContent="sms"===l?o("We are sending a verification code to your phone. Please enter it below."):o("We are sending a verification code to")+" "+e+". "+o("Please enter it below."),!s.dataset.sent){s.dataset.sent="1",s.dataset.sentContact=a;const n=document.getElementById("sbs-otp-msg"),i=document.getElementById("sbs-otp-resend-btn");n&&(n.textContent=o("Sending verification code..."),n.style.color=""),i&&(i.disabled=!0),jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_send_otp",nonce:yatoonData.nonce,channel:l,email:e,phone:t,name:c},function(e){const t=!(!e||!e.success);n&&(n.textContent=t?e.data&&e.data.message?e.data.message:o("Verification code sent."):e&&e.data&&e.data.message?e.data.message:o("Failed to send code.")),i&&(i.style.display=""),i&&(i.disabled=!1),t||(s.dataset.sent="",s.dataset.sentContact="",n&&(n.style.color="#dc2626"))}).fail(function(){s.dataset.sent="",s.dataset.sentContact="",n&&(n.textContent=o("Could not send the verification code. Please try again."),n.style.color="#dc2626"),i&&(i.style.display="",i.disabled=!1)})}const p=document.getElementById("sbs-otp-verify-btn");p&&!p.dataset.bound&&(p.dataset.bound="1",p.addEventListener("click",function(){const e=(document.getElementById("sbs-otp-input")||{}).value||"",t=document.getElementById("sbs-otp-msg"),a=(document.getElementById("sbs-customer-email")||{}).value||"",i=(document.getElementById("sbs-customer-phone")||{}).value||"",r=a.trim()+"|"+i.trim();e.trim()?(p.disabled=!0,p.dataset.pending="1",t&&(t.textContent=o("Verifying..."),t.style.color=""),jQuery.post(yatoonData.ajaxUrl,{action:"yatoon_verify_otp",nonce:yatoonData.nonce,channel:l,email:a,phone:i,code:e,remember:document.getElementById("sbs-otp-remember")&&document.getElementById("sbs-otp-remember").checked?1:0},function(e){e.success?(s.dataset.verified="1",s.dataset.verifiedKey=e.data&&e.data.verified_key?e.data.verified_key:"",n._giftSubmissionQuote=null,n._dynamicQuoteKey="",s.dataset.verifiedContact=r,s.style.display="none",n.submitBooking()):(t&&(t.textContent=e.data&&e.data.message?e.data.message:o("Incorrect code.")),t&&(t.style.color="#dc2626"),p.disabled=!1,p.dataset.pending="")}).fail(function(){t&&(t.textContent=o("Could not verify the code. Please try again."),t.style.color="#dc2626"),p.disabled=!1,p.dataset.pending=""})):t&&(t.textContent=o("Enter the verification code first."),t.style.color="#dc2626")}));const _=document.getElementById("sbs-otp-resend-btn");return void(_&&!_.dataset.bound&&(_.dataset.bound="1",_.addEventListener("click",function(){if(_.disabled)return;s.dataset.sent="",s.dataset.sentContact="",s.dataset.verified="",s.dataset.verifiedKey="",s.dataset.verifiedContact="";const e=document.getElementById("sbs-otp-msg");e&&(e.textContent=""),n.submitBooking()})))}}if(this._isSubmitting=!0,this._clearBookingRecovery(),0===this.bookingCart.length&&this.selectedDateTime&&(this.pendingServices.length>0||this.selectedService)&&this.addToCart(),0===this.bookingCart.length)return this._isSubmitting=!1,void this._showToast(o("Please add at least one service to your booking."),"error");const r=t(".sbs-btn-submit"),c=t("#sbs-cart-next-btn"),l=t("#sbs-sidebar-next-btn"),g=r.text(),p=c.text(),_=l.text(),h=()=>{this._isSubmitting=!1,this._turnstileTokenFetched=!1,r.prop("disabled",!1).text(g),c.prop("disabled",!1).removeClass("sbs-submitting").text(p||o("Confirm Booking")),l.prop("disabled",!1).removeClass("sbs-submitting").text(_||o("Confirm Booking")),this._applyConfirmBtn(),this._updateMobileCartBar()};r.prop("disabled",!0).text(o("Confirming your booking...")),c.prop("disabled",!0).addClass("sbs-submitting").text("CONFIRMING..."),l.prop("disabled",!0).addClass("sbs-submitting").text("CONFIRMING..."),this._updateLegalBoxes();const y={customer_name:t("#sbs-customer-name").val(),customer_email:t("#sbs-customer-email").val(),customer_phone:t("#sbs-customer-phone").val(),client_timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||"",notes:t("#sbs-customer-notes").val(),coupon_code:t("#sbs-coupon-code").length?t("#sbs-coupon-code").val():"",marketing_email_optin:t("#sbs-marketing-email-optin").is(":checked")?1:0,marketing_sms_optin:t("#sbs-marketing-sms-optin").is(":checked")?1:0,consent_accepted:t("#sbs-consent-accepted").length&&t("#sbs-consent-accepted").is(":checked")?1:0,consent_signature:t("#sbs-consent-signature").length?t("#sbs-consent-signature").val():"",policy_acknowledged:t("#sbs-policy-acknowledged").length&&t("#sbs-policy-acknowledged").is(":checked")?1:0,tip_amount:parseFloat(t("#sbs-tip-amount").val())||0,gift_card_code:t("#sbs-gift-card-code-confirmed").val()||"",custom_fields:function(){const e={};return t('[name^="cf["]').each(function(){const o=t(this).attr("name").replace(/^cf\[|\]$/g,"");t(this).is(":checkbox")||t(this).is(":radio")?t(this).is(":checked")&&(e[o]=t(this).val()):e[o]=t(this).val()}),JSON.stringify(e)}()},b=this._collectGuestContacts(),k=f(y.customer_email);if(k)return h(),u("sbs-customer-email",k),void(document.getElementById("sbs-customer-email")&&document.getElementById("sbs-customer-email").scrollIntoView({behavior:"smooth",block:"center"}));"undefined"!=typeof yatoonData&&yatoonData.phoneMode&&yatoonData.phoneMode;if(y.customer_phone){const e=d(y.customer_phone);if(e)return h(),m(e),void(document.getElementById("sbs-customer-phone")&&document.getElementById("sbs-customer-phone").scrollIntoView({behavior:"smooth",block:"center"}))}if(this._needsPolicyAck()&&!y.policy_acknowledged)return h(),this._showToast(o("Please review and acknowledge the cancellation / no-show policy before booking."),"error"),void this._focusBookingValidation(t("#sbs-policy-acknowledged"),t(".sbs-policy-box:visible").first());if(this._needsConsent()&&(!y.consent_accepted||!y.consent_signature.trim())){h(),this._showToast(o("Please read and sign the consent form before booking."),"error");const e=y.consent_accepted?t("#sbs-consent-signature"):t("#sbs-consent-accepted");return void this._focusBookingValidation(e,t(".sbs-consent-box:visible").first())}const v=this.bookingCart.slice(),C=[],w=JSON.stringify(v.map(e=>({start:e.dateTime&&e.dateTime.start_at,guest:e.guestLabel||"Me",services:(e.services||[{service:e.service,options:e.options,staff:e.staff}]).map(t=>({service:t.service&&t.service.id,options:(t.options||[]).map(e=>e.id),staff:t.staff&&t.staff.id||0,guest:t.guestLabel||e.guestLabel||"Me"}))}))),T=this._newBookingReference(w),S="undefined"!=typeof yatoonData&&(yatoonData.ajax_url||yatoonData.ajaxUrl)?yatoonData.ajax_url||yatoonData.ajaxUrl:"";if(!S)return h(),void this._showToast(o("Booking could not start because the WordPress AJAX URL is missing. Please refresh and try again."),"error");if(!v.length)return h(),void this._showToast(o("Please choose a service and time before confirming."),"error");const I=v.some(e=>e&&e.services&&e.services.length>1),P=v.length>1||I?"yatoon-"+T:"";let x=this.designUploadAttachmentId||0,B=this.designUploadToken||"";const D=o=>{const s=v[o],a=s.services||[{service:s.service,options:s.options,staff:s.staff}],i=s.dateTime&&s.dateTime.staff_map?s.dateTime.staff_map:null,r="string"==typeof i?function(){try{return JSON.parse(i)}catch(e){return null}}():i,c={},d={};a.forEach(function(e,t){const o=void 0!==e._originalIndex?e._originalIndex:t;s.dateTime.local_staff_map&&Number(s.dateTime.local_staff_map[o])>0&&(d[t]=Number(s.dateTime.local_staff_map[o])),r&&void 0!==r[o]&&(c[t]=r[o])});const l=Object.keys(c).length?JSON.stringify(c):i?"string"==typeof i?i:JSON.stringify(i):"",u=s.guestLabel||a[0]&&a[0].guestLabel||"Me",m=b[u]||{};let g=y.notes||"";if("Me"!==u){const e=[`Guest: ${u}`];m.name&&e.push(`Name: ${m.name}`),m.phone&&e.push(`Phone: ${m.phone}`),g=`${g}${g?"\n\n":""}${e.join(" - ")}`}const f={},p=new Date(s.dateTime.start_at).getTime(),_=a.map(e=>{const t=e.guestLabel||s.guestLabel||"Me",o=f[t]||0,a=Number.isFinite(p)?new Date(p+6e4*o).toISOString():s.dateTime.start_at;return f[t]=o+n._serviceDuration(e),{service_id:e.service.id,staff_id:e.staff?e.staff.id:0,gender_preference:n._genderPreferenceFor(e),option_ids:e.options.map(e=>e.id),guest_label:t,start_at:a,design_attachment_id:parseInt(e.designAttachmentId||0,10)||0,design_upload_token:String(e.designUploadToken||"")}});return{action:"yatoon_create_booking",nonce:yatoonData.nonce,client_reference:`${T}-${o+1}`,start_at:s.dateTime.start_at,local_staff_map_json:JSON.stringify(d),staff_map_json:l,services_json:JSON.stringify(_),service_id:a[0].service.id,staff_id:a[0].staff?a[0].staff.id:0,gender_preference:n._genderPreferenceFor(a[0]),selected_options:a[0].options.map(e=>e.id),notes:g,guest_label:u,guest_name:m.name||"",guest_phone:m.phone||"",booking_group_id:P,coupon_code:y.coupon_code,tip_amount:0===o?y.tip_amount:0,gift_card_code:n._giftSubmissionQuote?.cart[o]?.gift_card_amount>0?y.gift_card_code||n._giftCode:"",gift_card_amount:n._giftSubmissionQuote?.cart[o]?.gift_card_amount||0,custom_fields:y.custom_fields,customer_name:y.customer_name,customer_email:y.customer_email,customer_phone:y.customer_phone,otp_channel:"undefined"!=typeof yatoonData&&"1"===yatoonData.verifySmsOtp?"sms":"email",otp_verified_key:document.getElementById("sbs-otp-section")&&document.getElementById("sbs-otp-section").dataset.verifiedKey?document.getElementById("sbs-otp-section").dataset.verifiedKey:"",marketing_email_optin:y.marketing_email_optin,marketing_sms_optin:y.marketing_sms_optin,consent_accepted:y.consent_accepted,consent_signature:y.consent_signature,policy_acknowledged:y.policy_acknowledged,client_timezone:y.client_timezone,design_attachment_id:x||"",design_upload_token:B||"",website:t("#sbs-website").val()||"",form_rendered_at:t("#sbs-form-rendered-at").val()||"",cf_turnstile_response:void 0!==e.yatoonTurnstileToken?e.yatoonTurnstileToken:"",yatoon_test_booking:t(".sbs-booking-container").hasClass("yatoon-test-mode")?"1":""}},E=()=>{v.length<2||!n._paymentsConfigured()?F(0):n._loadFeatureChunk("recovery").then(async()=>{for(let e=0;e<v.length;e++)try{await n._prepareCheckout(D(e))}catch(t){throw t.cartIndex=e,t}}).then(()=>F(0)).catch(e=>{const t=e&&"number"==typeof e.cartIndex?e.cartIndex:0;if(e&&e.data&&e.data.preflight)return n._showToast(e.message,"error"),void h();n._showBookingRecovery({reference:`${T}-${t+1}`,failedIndex:t,confirmedCount:0,message:e&&e.message||o("This appointment is no longer available. Please choose another time."),uncertain:!1}),h()})},F=s=>{if(s>=v.length){if(C.every(e=>e&&e.success)){const s=C.find(e=>e&&e.success&&e.data&&e.data.woocommerce_checkout_url);if(s&&s.data.woocommerce_checkout_url)return this.bookingConfirmed=!0,this._clearSession(),void e.location.assign(s.data.woocommerce_checkout_url);this.bookingConfirmed=!0,t(".sbs-form-step").removeClass("active"),t(".sbs-step-success").show(),this._updateStepAccordion(),this._markBookingFlowComplete(),t("#sbs-success-count").text(v.length);const a=1!==v.length;t("#sbs-success-booking-word").text(o(a?"Bookings":"Booking"));const i=this._confirmedBookingItems(v,C);this._renderSuccessBookingSummary(i);const r=C.filter(e=>e&&e.success&&e.data&&e.data.manage_url&&String(e.data.manage_url).length),d=r.length&&r[0].data?r[0].data.manage_url:"",u=C.find(e=>e&&e.success&&e.data&&e.data.calendar_url&&String(e.data.calendar_url).length),m=u&&u.data?u.data.calendar_url:"",g=yatoonData.portalUrl||"",f=yatoonData.portalLabel||o("My Appointments"),p=t("#sbs-success-actions").empty();if(t("<div/>",{class:"sbs-success-action-note",text:yatoonData.successNote||o("Your appointment is booked. Save this page or use the manage link below if you need to change services, reschedule, or cancel.")}).appendTo(p),d&&1===r.length&&t("<a/>",{class:"sbs-success-action-link primary",href:d,target:"_blank",rel:"noopener",text:"undefined"!=typeof yatoonData&&yatoonData.isPro?o("Change services, reschedule, or cancel"):o("Reschedule or cancel")}).appendTo(p),r.length>1){const e=t("<div/>",{class:"sbs-success-manage-list"}).appendTo(p),n=v.some(e=>e.guestLabel&&"Me"!==e.guestLabel);r.forEach((s,a)=>{const i=v[a],r=i&&i.guestLabel&&"Me"!==i.guestLabel?i.guestLabel:null;let c;if(r)c=o("Change or cancel for")+" "+r;else if(n)c=o("Change or cancel my appointment");else{const e=s.data&&s.data.service_name?s.data.service_name:o("Appointment")+" "+(a+1);c=o("Change or cancel:")+" "+e}t("<a/>",{class:"sbs-success-action-link compact",href:s.data.manage_url,target:"_blank",rel:"noopener",text:c}).appendTo(e)})}if(m&&!t("#sbs-success-cal-row").length&&t("<a/>",{class:"sbs-success-action-link",href:m,text:o("Add to calendar")}).appendTo(p),g&&t("<a/>",{class:"sbs-success-action-link",href:g,text:f}).appendTo(p),t("<button/>",{type:"button",class:"sbs-success-action-link sbs-success-book-again"+(d?"":" primary"),text:o("Book again")}).appendTo(p),p.show(),m){t("#sbs-cal-ics").attr("href",m);const e=C.find(e=>e&&e.success&&e.data&&(e.data.start_at||e.data.start_time)),n=i[0]||null,s=n&&n.dateTime?n.dateTime.start_at:"",a=n?this._getItemVisitDuration(n):0,r=s?new Date(s):null,c=r&&!isNaN(r.getTime())&&a?new Date(r.getTime()+6e4*a).toISOString():"",d=e&&e.data&&(e.data.start_at||e.data.start_time)||s,l=e&&e.data&&(e.data.end_at||e.data.end_time)||c;if(d&&l){const e=function(e){const t=new Date(e);return isNaN(t.getTime())?"":t.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}Z$/,"Z")},s=(n?n.services||[{service:n.service}]:[]).map(e=>e.service&&e.service.name).filter(Boolean).join(", "),a=encodeURIComponent((yatoonData.businessName||o("Appointment"))+(s?" - "+s:"")),i=encodeURIComponent(e(d)),r=encodeURIComponent(e(l)),c=encodeURIComponent(yatoonData&&yatoonData.siteTimezone?yatoonData.siteTimezone:Intl.DateTimeFormat().resolvedOptions().timeZone);i&&r?t("#sbs-cal-google").attr("href","https://calendar.google.com/calendar/render?action=TEMPLATE&text="+a+"&dates="+i+"/"+r+"&ctz="+c):t("#sbs-cal-google").attr("href",m)}else t("#sbs-cal-google").attr("href",m);t("#sbs-success-cal-row").show()}yatoonData.rebookingNudgeText&&(t("#sbs-rebooking-nudge .sbs-rebooking-text").text(yatoonData.rebookingNudgeText),t("#sbs-rebooking-nudge .sbs-rebooking-btn").text(yatoonData.rebookingNudgeBtn||o("Book next visit")),setTimeout(function(){t("#sbs-rebooking-nudge").fadeIn(400)},1200));const _=C.find(e=>e&&e.success&&e.data&&e.data.booking_id);if(_&&_.data.manage_token&&t("#sbs-recurring-setup").length){const e=_.data.booking_id,n=_.data.manage_token;let s=2;setTimeout(function(){t("#sbs-recurring-setup").fadeIn(400)},2e3),t(document).on("click",".sbs-freq-btn",function(){t(".sbs-freq-btn").removeClass("active"),t(this).addClass("active"),s=parseInt(t(this).data("weeks"))}),t(document).on("click","#sbs-recurring-confirm",function(){const a=t(this).prop("disabled",!0).text(o("Setting up...")),i=parseInt(t("#sbs-recurring-count").val())||6;t.post(ajaxurl,{action:"yatoon_setup_recurring",nonce:yatoonData.nonce,yatoon_location_id:parseInt(yatoonData.locationId||0,10),booking_id:e,manage_token:n,frequency_weeks:s,total_count:i},function(e){const n=t("#sbs-recurring-result");e.success?(a.text(o("Done")),n.removeClass("error").text(e.data.message).show()):(a.prop("disabled",!1).text(o("Try again")),n.addClass("error").text(e.data&&e.data.message||o("Could not set up recurring.")).show())}).fail(function(){a.prop("disabled",!1).text(o("Try again")),t("#sbs-recurring-result").addClass("error").text(o("Network error. Please try again.")).show()})})}n.bookingCart=[],n.pendingServices=[],n._clearSession(),n._clearBookingRecovery(),n._bookingAttemptReference="",n._bookingAttemptFingerprint="",n._giftCode="",n._giftSubmissionQuote=null,t("#sbs-gift-card-code-confirmed").val(""),n._hideMobileCartBar(),n._closeDrawer(),n._isSubmitting=!1,h(),c.hide(),l.hide()}else{const e=C.filter(e=>!e||!e.success),t=e.map(e=>e&&e.data&&e.data.message?e.data.message:"").filter(Boolean).join(" "),s=t?`\n\nDetails: ${t}`:"",a=C.length-e.length;n._showToast(`${a} booking(s) confirmed, but ${e.length} failed. Please contact us.${s}`,"error");const i=e[0]&&e[0].data?e[0].data:{};n._showBookingRecovery({reference:i.reference||T,failedIndex:a,confirmedCount:a,message:t||o("One or more appointments were not confirmed."),safeToRetry:!0===i.retry_safe}),h()}return}const a=D(s),i=document.getElementById("sbs-design-reference"),r=i&&i.files&&i.files[0]?i.files[0]:null;let d=a,u=!0,m="application/x-www-form-urlencoded; charset=UTF-8";r&&!x&&(d=new FormData,Object.keys(a).forEach(function(e){const t=a[e];Array.isArray(t)?t.forEach(function(t){d.append(e+"[]",t)}):d.append(e,t)}),d.append("design_reference",r),u=!1,m=!1);const g=function(){t.ajax({url:S,type:"POST",timeout:9e4,data:d,processData:u,contentType:m,success:function(e,i,r){try{if("string"==typeof e){const t=e.indexOf("{"),o=e.lastIndexOf("}"),n=t>=0&&o>t?e.slice(t,o+1):e;e=JSON.parse(n)}if(C.push(e),!e||!e.success){const t=e&&e.data&&e.data.message?e.data.message:"",i=t?`\n\nDetails: ${t}`:"",r=C.length-1;n._showToast(`${r} booking(s) confirmed, but appointment ${s+1} failed. Please contact us.${i}`,"error");const c=e&&e.data?e.data:{},l=!!function(){const e=["deposit_intent_id","paypal_order_id","square_payment_id"];for(let t=0;t<e.length;t++){const o=d instanceof FormData?d.get(e[t]):d[e[t]];if(o)return String(o)}return""}();return n._showBookingRecovery({reference:a.client_reference||c.reference||`${T}-${s+1}`,failedIndex:s,confirmedCount:r,message:t||o("The appointment was not confirmed."),safeToRetry:!0===c.retry_safe&&!l,uncertain:!0===c.outcome_uncertain||l}),l&&n._showPaidRecoveryNotice(a.client_reference),void h()}n._forgetPaidCheckout(a.client_reference),e.data&&e.data.design_attachment_id&&(x=parseInt(e.data.design_attachment_id,10)||x,n.designUploadAttachmentId=x),e.data&&e.data.design_upload_token&&(B=String(e.data.design_upload_token||""),n.designUploadToken=B),F(s+1)}catch(a){if(console.error(o("Yatoon booking submit failed after server response:"),a),n.bookingConfirmed||t(".sbs-step-success:visible").length>0)return;const i=r&&r.responseText?String(r.responseText):"string"==typeof e?e:"";if(i&&-1!==i.indexOf('"success":true'))return C.push({success:!0,data:{}}),void F(s+1);n._showToast(o("We could not read the booking confirmation response. Please check the booking list before trying again."),"error"),n._showBookingRecovery({reference:`${T}-${s+1}`,failedIndex:s,confirmedCount:C.filter(e=>e&&e.success).length,message:o("We could not verify the server response."),uncertain:!0}),h()}},error:function(e,t){C.push({success:!1});const a=C.length-1,i="timeout"===t?"the request timed out":"a network error";n._showToast(`${a} booking(s) confirmed, but appointment ${s+1} failed due to ${i}. Please contact us.`,"error"),n._showBookingRecovery({reference:`${T}-${s+1}`,failedIndex:s,confirmedCount:a,message:o("timeout"===t?"The request timed out.":"The network connection was interrupted."),uncertain:!0}),h()}})},f=function(){const e=(e,t)=>{n._rememberCheckoutPayment&&n._rememberCheckoutPayment(a.client_reference,e,t),n._giftSubmissionQuote&&(n._giftSubmissionQuote.payments=n._giftSubmissionQuote.payments||{},n._giftSubmissionQuote.payments[s]={field:e,id:t},n._saveSession())},t=n._checkoutSavedPayment||n._giftSubmissionQuote?.payments?.[s];n._checkoutSavedPayment=null;const i=t?"":n._unresolvedPaidCheckout(a.client_reference);if(i)return n._showBookingRecovery({reference:i,failedIndex:s,confirmedCount:s,message:o("A payment for an earlier attempt was received, but that appointment is not confirmed yet."),uncertain:!0}),n._showPaidRecoveryNotice(i,!0),void h();t?(d instanceof FormData?d.set(t.field,t.id):d[t.field]=t.id,g()):a.gift_card_code&&0===n._giftSubmissionQuote?.cart[s]?.amount_due?g():n._squarePreparedPaymentId&&n._squarePreparedPaymentReference===a.client_reference?(e("square_payment_id",n._squarePreparedPaymentId),d instanceof FormData?d.set("square_payment_id",n._squarePreparedPaymentId):d.square_payment_id=n._squarePreparedPaymentId,n._squarePreparedPaymentId="",n._squarePreparedPaymentReference="",g()):n._paymentProviderEnabled("square")?n._ensurePaymentSdk("square").then(function(){return n._createSquarePaymentForPayload(a)}).then(function(t){e("square_payment_id",t),d instanceof FormData?d.set("square_payment_id",t):d.square_payment_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("Square payment could not be started."),"error"),h()}):n._paymentProviderEnabled("paypal")?n._ensurePaymentSdk("paypal").then(function(){return n._createPayPalPaymentForPayload(a)}).then(function(t){e("paypal_order_id",t),d instanceof FormData?d.set("paypal_order_id",t):d.paypal_order_id=t,g()}).catch(function(e){n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("PayPal Checkout could not be started."),"error"),h()}):n._paymentProviderEnabled("stripe")?n._ensurePaymentSdk("stripe").then(function(){return n._createStripePaymentForPayload(a)}).then(function(t){e("deposit_intent_id",t),d instanceof FormData?d.set("deposit_intent_id",t):d.deposit_intent_id=t,g()}).catch(function(e){if(0===s&&e&&e.data&&e.data.preflight)return n._showToast(e.message||o("Stripe payment could not be started."),"error"),void h();n._showBookingRecovery({reference:a.client_reference,failedIndex:s,message:e.message,uncertain:!0}),n._showToast(e&&e.message?e.message:o("Stripe payment could not be started."),"error"),h()}):g()};n._paymentsConfigured()?n._loadFeatureChunk("recovery").then(()=>n._prepareCheckout(a)).then(e=>{d instanceof FormData?d.set("checkout_token",a.checkout_token):d.checkout_token=a.checkout_token,n._checkoutSavedPayment=e.payment||null,f()}).catch(e=>{const t=!!(e&&e.data&&e.data.preflight);if(t&&0===s)return n._showToast(e.message,"error"),void h();n._showBookingRecovery({reference:a.client_reference,failedIndex:s,confirmedCount:s,message:e.message,uncertain:!t}),h()}):f()};try{if(y.gift_card_code||n._giftCode){(n._giftSubmissionQuote?Promise.resolve(n._giftSubmissionQuote):n._fetchGiftQuote(parseFloat(y.tip_amount)||0)).then(e=>{n._giftSubmissionQuote=e,n._saveSession(),n._renderGiftQuote(e),E()}).catch(e=>{n._showToast(e.message,"error"),n._isSubmitting=!1,h()})}else E()}catch(e){console.error(o("Yatoon booking submit error:"),e),this._showToast(o("Something went wrong before the booking could be sent. Please refresh and try again."),"error"),h()}}}Object.getOwnPropertyNames(_.prototype).filter(e=>"constructor"!==e).forEach(t=>e.YatoonSquareBookingForm.prototype[t]=_.prototype[t])}(window,window.jQuery); -
yatoon-booking-system/trunk/assets/js/frontend-payments.js
r3780403 r3780965 87 87 return new Promise(function(resolve, reject) { 88 88 if (!self._stripePaymentsReady()) { 89 reject(new Error(__('Stripe payment form is not ready. Please refresh and try again.'))); 89 const notReady = new Error(__('Stripe payment form is not ready. Please refresh and try again.')); 90 notReady.data = { preflight: true }; 91 reject(notReady); 90 92 return; 91 93 } … … 126 128 paymentElement.mount('#sbs-stripe-payment-element'); 127 129 const $status = $('#sbs-stripe-payment-status'); 130 const payLabel = yatoonData.nativePaymentMode === 'full' ? __('Pay total') : __('Pay deposit'); 131 // 4.10.2: the box is reused for the next appointment in a cart. 132 // Start each payment with a fresh, clickable button and no old status. 133 $status.text(''); 134 $('#sbs-stripe-pay-button').prop('disabled', false).text(payLabel); 128 135 $('#sbs-stripe-pay-button').off('.yatoonStripe').on('click.yatoonStripe', function() { 129 136 const $button = $(this).prop('disabled', true).text(__('Processing...')); 130 137 $status.text(__('Confirming your payment securely...')); 138 // 4.10.2: a Stripe error (no payment method chosen, card declined, 139 // failed verification) means nothing was charged. Keep the customer 140 // in this payment box so they can fix it and pay again, instead of 141 // ending the checkout and sending them to the booking-status panel. 142 const retryHere = function(message) { 143 $button.prop('disabled', false).text(payLabel); 144 $status.text(message); 145 self._showToast(message, 'error'); 146 }; 131 147 stripe.confirmPayment({ 132 148 elements: elements, 133 149 redirect: 'if_required' 134 150 }).then(function(result) { 135 if (result.error) throw new Error(result.error.message || __('Stripe could not complete the payment.')); 151 let intent = result.paymentIntent || null; 152 // A repeat click after a lost response: Stripe reports the intent 153 // is already paid. Treat that as success, not as an error. 154 if (result.error && result.error.payment_intent) { 155 const already = result.error.payment_intent.status; 156 if (already === 'succeeded' || already === 'processing') intent = result.error.payment_intent; 157 } 158 if (result.error && !intent) { 159 retryHere(result.error.message || __('Stripe could not complete the payment.')); 160 return; 161 } 136 162 // 4.10.2: bank debits stay "processing" for a few days. The 137 163 // appointment is booked now and marked paid when the bank clears. 138 const intentStatus = result.paymentIntent ? result.paymentIntent.status : '';164 const intentStatus = intent ? intent.status : ''; 139 165 if (intentStatus !== 'succeeded' && intentStatus !== 'processing') { 140 throw new Error(__('Stripe payment is not complete.')); 166 retryHere(__('Stripe payment is not complete. Please check your payment details and try again.')); 167 return; 141 168 } 142 169 $status.text(intentStatus === 'processing' … … 144 171 : __('Payment approved. Confirming your appointment...')); 145 172 $box.hide(); 146 resolve( result.paymentIntent.id);173 resolve(intent.id); 147 174 }).catch(function(error) { 148 $button.prop('disabled', false).text(yatoonData.nativePaymentMode === 'full' ? __('Pay total') : __('Pay deposit'));149 $status.text(error.message || __('Stripe payment failed.'));150 self._showToast(error.message || __('Stripe payment failed.'), 'error');151 re ject(error);175 // Stripe.js itself failed (network). The charge state is unknown, 176 // so let the customer press Pay again: Stripe answers a repeat 177 // confirm of a paid intent with its paid status (handled above). 178 retryHere((error && error.message) || __('We could not reach Stripe. Please check your connection and press Pay again.')); 152 179 }); 153 180 }); 154 181 $box.show(); 155 182 if ($box[0] && $box[0].scrollIntoView) $box[0].scrollIntoView({ behavior: 'smooth', block: 'center' }); 156 }).catch(reject); 183 }).catch(function(error) { 184 // The payment form could not be opened, so nothing was charged. 185 if (error && typeof error === 'object') error.data = Object.assign({}, error.data, { preflight: true }); 186 reject(error); 187 }); 157 188 }); 158 189 } -
yatoon-booking-system/trunk/assets/js/frontend-payments.min.js
r3780403 r3780965 1 !function(e,t){"use strict";const a=e.wp&&e.wp.i18n&&"function"==typeof e.wp.i18n.__?function(t){return e.wp.i18n.__(t,"yatoon-booking-system")}:function(e){return e},n=e.YatoonSquareBookingForm;if(n&&t){class o{_squarePaymentsReady(){return!!("undefined"!=typeof yatoonData&&yatoonData.squarePaymentsEnabled&&yatoonData.squareApplicationId&&yatoonData.squareLocationId&&e.Square&&"function"==typeof e.Square.payments)}_paymentProviderEnabled(e){return"undefined"!=typeof yatoonData&&("square"===e?!!yatoonData.squarePaymentsEnabled:"paypal"===e?!!yatoonData.paypalPaymentsEnabled:"stripe"===e&&!!yatoonData.depositEnabled)}_ensurePaymentSdk(e){const t={square:()=>this._squarePaymentsReady(),paypal:()=>this._paypalPaymentsReady(),stripe:()=>this._stripePaymentsReady()}[e],n={square:yatoonData.squareSdkUrl,paypal:yatoonData.paypalSdkUrl,stripe:yatoonData.stripeSdkUrl}[e];return t&&t()?Promise.resolve():n?(this._paymentSdkPromises=this._paymentSdkPromises||{},this._paymentSdkPromises[e]||(this._paymentSdkPromises[e]=new Promise(function(o,r){const s=document.createElement("script");s.src=n,s.async=!0,s.dataset.yatoonPaymentSdk=e,s.onload=function(){t&&t()?o():r(new Error(a("The secure payment service did not initialize.")))},s.onerror=function(){r(new Error(a("The secure payment service could not be loaded. Check your connection and try again.")))},document.head.appendChild(s)}).catch(t=>{throw delete this._paymentSdkPromises[e],t})),this._paymentSdkPromises[e]):Promise.reject(new Error(a("The secure payment service is not configured.")))}_paypalPaymentsReady(){return!("undefined"==typeof yatoonData||!yatoonData.paypalPaymentsEnabled||!e.paypal||"function"!=typeof e.paypal.Buttons)}_stripePaymentsReady(){return!("undefined"==typeof yatoonData||!yatoonData.depositEnabled||!yatoonData.stripePublishableKey||"function"!=typeof e.Stripe)}_createStripePaymentForPayload(n){const o=this;return new Promise(function(r,s){if(!o._stripePaymentsReady()) return void s(new Error(a("Stripe payment form is not ready. Please refresh and try again.")));const i=new FormData;Object.keys(n).forEach(function(e){const t=n[e];Array.isArray(t)?t.forEach(function(t){i.append(e+"[]",t)}):i.append(e,null==t?"":t)}),i.set("action","yatoon_stripe_create_intent"),i.set("nonce",yatoonData.nonce),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:i,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(n){if(n?.success&&n.data?.already_paid&&n.data.intent_id)return void r(n.data.intent_id);if(!(n&&n.success&&n.data&&n.data.client_secret))throw new Error(n&&n.data&&n.data.message?n.data.message:a("Could not start the Stripe payment."));let i=t("#sbs-stripe-payment-box");if(!i.length){i=t(`\n <div id="sbs-stripe-payment-box" style="margin:16px 0;padding:16px;border:1px solid #ddd6fe;border-radius:14px;background:#f5f3ff;">\n <div style="font-size:14px;font-weight:800;color:#2e1065;margin-bottom:6px;">Secure Stripe Payment</div>\n <div id="sbs-stripe-payment-amount" style="font-size:13px;color:#475569;margin-bottom:12px;"></div>\n <div id="sbs-stripe-payment-element"></div>\n <button type="button" id="sbs-stripe-pay-button" style="width:100%;min-height:46px;margin-top:14px;border:0;border-radius:9px;background:#635bff;color:#fff;font-weight:800;cursor:pointer;">${"full"===yatoonData.nativePaymentMode?a("Pay total"):a("Pay deposit")}</button>\n <div id="sbs-stripe-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>`);const e=t("#sbs-booking-form");e.length?e.prepend(i):t(".sbs-step-5").prepend(i)}t("#sbs-stripe-payment-element").empty(),t("#sbs-stripe-payment-amount").text(("full"===yatoonData.nativePaymentMode?a("Full payment due now:"):a("Deposit due now:"))+" "+(n.data.deposit_display||""));const p=e.Stripe(yatoonData.stripePublishableKey),d=p.elements({clientSecret:n.data.client_secret});d.create("payment").mount("#sbs-stripe-payment-element");const u=t("#sbs-stripe-payment-status");t("#sbs-stripe-pay-button").off(".yatoonStripe").on("click.yatoonStripe",function(){const e=t(this).prop("disabled",!0).text(a("Processing..."));u.text(a("Confirming your payment securely...")),p.confirmPayment({elements:d,redirect:"if_required"}).then(function(e){if(e.error)throw new Error(e.error.message||a("Stripe could not complete the payment."));const t=e.paymentIntent?e.paymentIntent.status:"";if("succeeded"!==t&&"processing"!==t)throw new Error(a("Stripe payment is not complete."));u.text(a("processing"===t?"Bank payment submitted. Confirming your appointment...":"Payment approved. Confirming your appointment...")),i.hide(),r(e.paymentIntent.id)}).catch(function(t){e.prop("disabled",!1).text("full"===yatoonData.nativePaymentMode?a("Pay total"):a("Pay deposit")),u.text(t.message||a("Stripe payment failed.")),o._showToast(t.message||a("Stripe payment failed."),"error"),s(t)})}),i.show(),i[0]&&i[0].scrollIntoView&&i[0].scrollIntoView({behavior:"smooth",block:"center"})}).catch(s)})}_createPayPalPaymentForPayload(n){const o=this;return new Promise(function(r,s){if(!o._paypalPaymentsReady())return void s(new Error(a("PayPal Checkout is not ready. Please refresh and try again.")));let i=t("#sbs-paypal-payment-box");if(!i.length){i=t(`\n <div id="sbs-paypal-payment-box" style="margin:16px 0;padding:16px;border:1px solid #bfdbfe;border-radius:14px;background:#eff6ff;">\n <div style="font-size:14px;font-weight:800;color:#172554;margin-bottom:6px;">Secure PayPal Payment</div>\n <div style="font-size:13px;color:#475569;margin-bottom:12px;">${"full"===yatoonData.nativePaymentMode?a("Pay the full appointment total with PayPal to confirm your booking."):a("Choose PayPal below to pay the deposit and confirm your appointment.")}</div>\n <div id="sbs-paypal-button-container"></div>\n <div id="sbs-paypal-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>`);const e=t("#sbs-booking-form");e.length?e.prepend(i):t(".sbs-step-5").prepend(i)}const p=t("#sbs-paypal-payment-status"),d=yatoonData.ajax_url||yatoonData.ajaxUrl;function u(e,t){const o=new FormData;return Object.keys(n).forEach(function(e){const t=n[e];Array.isArray(t)?t.forEach(function(t){o.append(e+"[]",t)}):o.append(e,null==t?"":t)}),o.set("action",e),o.set("nonce",yatoonData.nonce),Object.keys(t||{}).forEach(function(e){o.set(e,t[e])}),fetch(d,{method:"POST",body:o,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!e||!e.success||!e.data)throw new Error(e&&e.data&&e.data.message?e.data.message:a("PayPal payment failed."));return e.data})}t("#sbs-paypal-button-container").empty(),e.paypal.Buttons({style:{layout:"vertical",shape:"rect",label:"paypal"},createOrder:function(){return p.text(a("Preparing secure PayPal Checkout...")),u("yatoon_paypal_create_order").then(function(e){return e.amount_display&&p.text(("full"===yatoonData.nativePaymentMode?a("Full payment due now:"):a("Deposit due now:"))+" "+e.amount_display),e.order_id})},onApprove:function(e){return p.text(a("Confirming your PayPal payment...")),u("yatoon_paypal_capture_order",{order_id:e.orderID}).then(function(t){p.text(a("Payment approved. Confirming your appointment...")),i.hide(),r(t.order_id||e.orderID)}).catch(function(e){p.text(e.message||a("PayPal could not capture the payment.")),o._showToast(e.message||a("PayPal could not capture the payment."),"error"),s(e)})},onCancel:function(){const e=new Error(a("PayPal Checkout was cancelled."));p.text(e.message),s(e)},onError:function(e){p.text(a("PayPal Checkout could not be opened. Please try again.")),o._showToast(e&&e.message?e.message:a("PayPal Checkout failed."),"error"),s(e instanceof Error?e:new Error(a("PayPal Checkout failed.")))}}).render("#sbs-paypal-button-container").then(function(){i.show(),i[0]&&i[0].scrollIntoView&&i[0].scrollIntoView({behavior:"smooth",block:"center"})}).catch(s)})}_squareMethods(){const e=yatoonData&&Array.isArray(yatoonData.squarePaymentMethods)?yatoonData.squarePaymentMethods:["card"];return e.length?e:["card"]}_previewSquarePayment(e){const t=new FormData;return Object.keys(e).forEach(function(a){const n=e[a];Array.isArray(n)?n.forEach(function(e){t.append(a+"[]",e)}):t.append(a,null==n?"":n)}),t.set("action","yatoon_square_preview_payment"),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:t,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!e||!e.success||!e.data){const t=e&&e.data&&e.data.message?e.data.message:a("Could not calculate the Square payment amount.");throw new Error(t)}return e.data})}_buildSquarePaymentRequest(e,t){return e.paymentRequest({countryCode:(yatoonData.squareCountryCode||"US").toUpperCase(),currencyCode:(t.currency||yatoonData.currency||"USD").toUpperCase(),total:{amount:t.amount||"0.00",label:"full"===yatoonData.squarePaymentMode?a("Appointment total"):a("Booking deposit")}})}_ensureSquarePaymentCard(n){const o=this,r=JSON.stringify({services_json:n.services_json||"",service_id:n.service_id||"",selected_options:n.selected_options||[],coupon_code:n.coupon_code||"",customer_email:n.customer_email||"",customer_phone:n.customer_phone||"",client_reference:n.client_reference||"",checkout_token:n.checkout_token||"",start_at:n.start_at||"",location:n.yatoon_location_id||0,tip_amount:n.tip_amount||0,gift_card_code:n.gift_card_code||""});return this._squareCardPromise&&this._squarePaymentPayloadKey===r||(this._squarePaymentPayloadKey=r,this._squareCardPromise=new Promise(function(r,s){if(!o._squarePaymentsReady())return void s(new Error(a("Square payment form is not ready. Please refresh and try again.")));let i=t("#sbs-square-payment-box");if(!i.length){const e="full"===yatoonData.squarePaymentMode?a("Pay securely now to confirm your appointment."):a("Pay your deposit securely now to confirm your appointment.");i=t(`\n <div id="sbs-square-payment-box" class="sbs-square-payment-box" style="margin:16px 0;padding:16px;border:1px solid #dbeafe;border-radius:14px;background:#eff6ff;">\n <div style="font-size:14px;font-weight:800;color:#1e3a8a;margin-bottom:6px;">Secure Square Payment</div>\n <div style="font-size:13px;color:#475569;margin-bottom:12px;">${e}</div>\n <div id="sbs-square-payment-amount" style="font-size:13px;font-weight:800;color:#0f172a;margin-bottom:12px;"></div>\n <div id="sbs-square-method-tabs" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;"></div>\n <button id="sbs-square-apple-pay-button" type="button" class="sbs-square-method-panel" data-method-panel="apple_pay" style="display:none;width:100%;min-height:44px;border-radius:8px;border:0;background:#000;color:#fff;font-weight:800;">Apple Pay</button>\n <div id="sbs-square-google-pay" class="sbs-square-method-panel" data-method-panel="google_pay" style="display:none;"></div>\n <div id="sbs-square-cash-app-pay" class="sbs-square-method-panel" data-method-panel="cash_app_pay" style="display:none;"></div>\n <div id="sbs-square-gift-card-container" class="sbs-square-method-panel" data-method-panel="gift_card" style="display:none;"></div>\n <div id="sbs-square-card-container"></div>\n <div id="sbs-square-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>\n `);const n=t("#sbs-booking-form");n.length?n.prepend(i):t(".sbs-step-5").prepend(i)}t("#sbs-square-payment-status").text(a("Loading secure Square card form...")),o._previewSquarePayment(n).then(function(s){return t("#sbs-square-payment-amount").text(("full"===s.payment_mode?a("Pay now:"):a("Deposit due now:"))+" "+s.amount_display),Promise.resolve(e.Square.payments(yatoonData.squareApplicationId,yatoonData.squareLocationId)).then(function(i){const p=o._squareMethods(),d={payments:i,preview:s,methods:{},selected:p[0]||"card"},u=o._buildSquarePaymentRequest(i,s),c={card:"Card",apple_pay:a("Apple Pay"),google_pay:a("Google Pay"),cash_app_pay:a("Cash App"),gift_card:a("Gift Card")},y=t("#sbs-square-method-tabs").empty();function l(e){d.selected=e,t(".sbs-square-method-tab").each(function(){const a=t(this).data("method")===e;t(this).css({background:a?"#1d4ed8":"#fff",color:a?"#fff":"#1e3a8a"})}),t(".sbs-square-method-panel").hide(),t("#sbs-square-card-container").toggle("card"===e),t('[data-method-panel="'+e+'"]').show(),t("#sbs-square-payment-status").text(a("apple_pay"===e||"cash_app_pay"===e?"Tap the wallet button above to authorize payment, then booking will continue automatically.":"Payment details are encrypted by Square."))}p.forEach(function(e){t("<button/>",{type:"button",class:"sbs-square-method-tab","data-method":e,text:c[e]||e}).css({border:"1px solid #bfdbfe",background:e===d.selected?"#1d4ed8":"#fff",color:e===d.selected?"#fff":"#1e3a8a",borderRadius:"999px",padding:"8px 12px",fontWeight:"800",cursor:"pointer"}).appendTo(y)}),t(document).off("click.squareMethod").on("click.squareMethod",".sbs-square-method-tab",function(){l(t(this).data("method"))});const m=[];return p.includes("card")&&m.push(i.card().then(function(e){return d.methods.card=e,e.attach("#sbs-square-card-container")})),p.includes("gift_card")&&"function"==typeof i.giftCard&&m.push(i.giftCard().then(function(e){return d.methods.gift_card=e,e.attach("#sbs-square-gift-card-container")}).catch(function(){})),p.includes("apple_pay")&&"function"==typeof i.applePay&&m.push(i.applePay(u).then(function(e){d.methods.apple_pay=e,t("#sbs-square-apple-pay-button").off("click.squareApple").on("click.squareApple",function(t){t.preventDefault(),o._handleSquareWalletButton(n,e,"apple_pay")})}).catch(function(){t('[data-method="apple_pay"], [data-method-panel="apple_pay"]').hide()})),p.includes("google_pay")&&"function"==typeof i.googlePay&&m.push(i.googlePay(u).then(function(e){return d.methods.google_pay=e,e.attach("#sbs-square-google-pay")}).catch(function(){t('[data-method="google_pay"], [data-method-panel="google_pay"]').hide()})),p.includes("cash_app_pay")&&"function"==typeof i.cashAppPay&&m.push(i.cashAppPay(u,{redirectURL:e.location.href,referenceId:"yatoon-"+Date.now()}).then(function(e){return d.methods.cash_app_pay=e,e.addEventListener("ontokenization",function(e){const t=e.detail||{};t.error?o._showToast(a("Cash App Pay could not be authorized."),"error"):t.tokenResult&&"OK"===t.tokenResult.status&&o._finishSquareTokenPayment(n,t.tokenResult.token,"cash_app_pay")}),e.attach("#sbs-square-cash-app-pay")}).catch(function(){t('[data-method="cash_app_pay"], [data-method-panel="cash_app_pay"]').hide()})),Promise.all(m).then(function(){o._squarePaymentState=d,l(d.methods[d.selected]?d.selected:d.methods.card?"card":Object.keys(d.methods)[0]),r(d)})})}).catch(function(e){o._squareCardPromise=null,s(e)})})),this._squareCardPromise}_finishSquareTokenPayment(e,n,o){const r=this;return t("#sbs-square-payment-status").text(a("Completing")+" "+(o||a("Square"))+" "+a("payment...")),this._sendSquareTokenPayment(e,n).then(function(n){return r._squarePreparedPaymentId=n,r._squarePreparedPaymentReference=e.client_reference,r._rememberCheckoutPayment&&r._rememberCheckoutPayment(e.client_reference,"square_payment_id",n),t("#sbs-square-payment-status").text(a("Payment approved by Square. Confirming your booking...")),r._isSubmitting=!1,r.submitBooking(),n}).catch(function(e){throw r._showToast(e&&e.message?e.message:a("Square payment failed. Please try again."),"error"),e})}_handleSquareWalletButton(e,n,o){const r=this;return t("#sbs-square-payment-status").text(a("Opening")+" "+a("apple_pay"===o?"Apple Pay":"Square wallet")+"..."),n.tokenize().then(function(t){if(!t||"OK"!==t.status||!t.token){const e=t&&t.errors&&t.errors.length?t.errors.map(function(e){return e.message}).join(" "):a("The wallet payment was not authorized.");throw new Error(e)}return r._finishSquareTokenPayment(e,t.token,o)}).catch(function(e){t("#sbs-square-payment-status").text(e&&e.message?e.message:a("Wallet payment failed.")),r._showToast(e&&e.message?e.message:a("Wallet payment failed. Please try again."),"error")})}_sendSquareTokenPayment(e,t){const n=new FormData;return Object.keys(e).forEach(function(t){const a=e[t];Array.isArray(a)?a.forEach(function(e){n.append(t+"[]",e)}):n.append(t,null==a?"":a)}),n.set("action","yatoon_square_create_payment"),n.set("source_id",t),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:n,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!(e&&e.success&&e.data&&e.data.payment_id)){const t=e&&e.data&&e.data.message?e.data.message:a("Square payment failed. Please try again.");throw new Error(t)}return e.data.payment_id})}_createSquarePaymentForPayload(e){const n=this;return this._squarePaymentsReady()?this._ensureSquarePaymentCard(e).then(function(e){t("#sbs-square-payment-box").show();const n=document.getElementById("sbs-square-payment-box");n&&n.scrollIntoView({behavior:"smooth",block:"center"});const o=e.selected||"card",r=e.methods[o];if(!r)throw new Error(a("This Square payment method is not available on this device. Please choose another method."));return"cash_app_pay"===o?(t("#sbs-square-payment-status").text(a("Tap the Cash App Pay button above to authorize payment.")),new Promise(function(){})):(t("#sbs-square-payment-status").text(a("Securing your payment with Square...")),r.tokenize())}).then(function(t){if(!t||"OK"!==t.status||!t.token){const e=t&&t.errors&&t.errors.length?t.errors.map(function(e){return e.message}).join(" "):a("Please check your card details and try again.");throw new Error(e)}return n._sendSquareTokenPayment(e,t.token)}).then(function(e){return t("#sbs-square-payment-status").text(a("Payment approved by Square.")),e}).catch(function(e){throw t("#sbs-square-payment-status").text(e&&e.message?e.message:a("Square payment failed.")),n._showToast(e&&e.message?e.message:a("Square payment failed. Please try again."),"error"),e}):Promise.reject(new Error(a("Square payment is enabled but the secure payment form is unavailable.")))}}Object.getOwnPropertyNames(o.prototype).forEach(function(e){"constructor"!==e&&Object.defineProperty(n.prototype,e,Object.getOwnPropertyDescriptor(o.prototype,e))})}}(window,window.jQuery);1 !function(e,t){"use strict";const a=e.wp&&e.wp.i18n&&"function"==typeof e.wp.i18n.__?function(t){return e.wp.i18n.__(t,"yatoon-booking-system")}:function(e){return e},n=e.YatoonSquareBookingForm;if(n&&t){class o{_squarePaymentsReady(){return!!("undefined"!=typeof yatoonData&&yatoonData.squarePaymentsEnabled&&yatoonData.squareApplicationId&&yatoonData.squareLocationId&&e.Square&&"function"==typeof e.Square.payments)}_paymentProviderEnabled(e){return"undefined"!=typeof yatoonData&&("square"===e?!!yatoonData.squarePaymentsEnabled:"paypal"===e?!!yatoonData.paypalPaymentsEnabled:"stripe"===e&&!!yatoonData.depositEnabled)}_ensurePaymentSdk(e){const t={square:()=>this._squarePaymentsReady(),paypal:()=>this._paypalPaymentsReady(),stripe:()=>this._stripePaymentsReady()}[e],n={square:yatoonData.squareSdkUrl,paypal:yatoonData.paypalSdkUrl,stripe:yatoonData.stripeSdkUrl}[e];return t&&t()?Promise.resolve():n?(this._paymentSdkPromises=this._paymentSdkPromises||{},this._paymentSdkPromises[e]||(this._paymentSdkPromises[e]=new Promise(function(o,r){const s=document.createElement("script");s.src=n,s.async=!0,s.dataset.yatoonPaymentSdk=e,s.onload=function(){t&&t()?o():r(new Error(a("The secure payment service did not initialize.")))},s.onerror=function(){r(new Error(a("The secure payment service could not be loaded. Check your connection and try again.")))},document.head.appendChild(s)}).catch(t=>{throw delete this._paymentSdkPromises[e],t})),this._paymentSdkPromises[e]):Promise.reject(new Error(a("The secure payment service is not configured.")))}_paypalPaymentsReady(){return!("undefined"==typeof yatoonData||!yatoonData.paypalPaymentsEnabled||!e.paypal||"function"!=typeof e.paypal.Buttons)}_stripePaymentsReady(){return!("undefined"==typeof yatoonData||!yatoonData.depositEnabled||!yatoonData.stripePublishableKey||"function"!=typeof e.Stripe)}_createStripePaymentForPayload(n){const o=this;return new Promise(function(r,s){if(!o._stripePaymentsReady()){const e=new Error(a("Stripe payment form is not ready. Please refresh and try again."));return e.data={preflight:!0},void s(e)}const i=new FormData;Object.keys(n).forEach(function(e){const t=n[e];Array.isArray(t)?t.forEach(function(t){i.append(e+"[]",t)}):i.append(e,null==t?"":t)}),i.set("action","yatoon_stripe_create_intent"),i.set("nonce",yatoonData.nonce),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:i,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(n){if(n?.success&&n.data?.already_paid&&n.data.intent_id)return void r(n.data.intent_id);if(!(n&&n.success&&n.data&&n.data.client_secret))throw new Error(n&&n.data&&n.data.message?n.data.message:a("Could not start the Stripe payment."));let s=t("#sbs-stripe-payment-box");if(!s.length){s=t(`\n <div id="sbs-stripe-payment-box" style="margin:16px 0;padding:16px;border:1px solid #ddd6fe;border-radius:14px;background:#f5f3ff;">\n <div style="font-size:14px;font-weight:800;color:#2e1065;margin-bottom:6px;">Secure Stripe Payment</div>\n <div id="sbs-stripe-payment-amount" style="font-size:13px;color:#475569;margin-bottom:12px;"></div>\n <div id="sbs-stripe-payment-element"></div>\n <button type="button" id="sbs-stripe-pay-button" style="width:100%;min-height:46px;margin-top:14px;border:0;border-radius:9px;background:#635bff;color:#fff;font-weight:800;cursor:pointer;">${"full"===yatoonData.nativePaymentMode?a("Pay total"):a("Pay deposit")}</button>\n <div id="sbs-stripe-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>`);const e=t("#sbs-booking-form");e.length?e.prepend(s):t(".sbs-step-5").prepend(s)}t("#sbs-stripe-payment-element").empty(),t("#sbs-stripe-payment-amount").text(("full"===yatoonData.nativePaymentMode?a("Full payment due now:"):a("Deposit due now:"))+" "+(n.data.deposit_display||""));const i=e.Stripe(yatoonData.stripePublishableKey),p=i.elements({clientSecret:n.data.client_secret});p.create("payment").mount("#sbs-stripe-payment-element");const d=t("#sbs-stripe-payment-status"),c="full"===yatoonData.nativePaymentMode?a("Pay total"):a("Pay deposit");d.text(""),t("#sbs-stripe-pay-button").prop("disabled",!1).text(c),t("#sbs-stripe-pay-button").off(".yatoonStripe").on("click.yatoonStripe",function(){const e=t(this).prop("disabled",!0).text(a("Processing..."));d.text(a("Confirming your payment securely..."));const n=function(t){e.prop("disabled",!1).text(c),d.text(t),o._showToast(t,"error")};i.confirmPayment({elements:p,redirect:"if_required"}).then(function(e){let t=e.paymentIntent||null;if(e.error&&e.error.payment_intent){const a=e.error.payment_intent.status;"succeeded"!==a&&"processing"!==a||(t=e.error.payment_intent)}if(e.error&&!t)return void n(e.error.message||a("Stripe could not complete the payment."));const o=t?t.status:"";"succeeded"===o||"processing"===o?(d.text(a("processing"===o?"Bank payment submitted. Confirming your appointment...":"Payment approved. Confirming your appointment...")),s.hide(),r(t.id)):n(a("Stripe payment is not complete. Please check your payment details and try again."))}).catch(function(e){n(e&&e.message||a("We could not reach Stripe. Please check your connection and press Pay again."))})}),s.show(),s[0]&&s[0].scrollIntoView&&s[0].scrollIntoView({behavior:"smooth",block:"center"})}).catch(function(e){e&&"object"==typeof e&&(e.data=Object.assign({},e.data,{preflight:!0})),s(e)})})}_createPayPalPaymentForPayload(n){const o=this;return new Promise(function(r,s){if(!o._paypalPaymentsReady())return void s(new Error(a("PayPal Checkout is not ready. Please refresh and try again.")));let i=t("#sbs-paypal-payment-box");if(!i.length){i=t(`\n <div id="sbs-paypal-payment-box" style="margin:16px 0;padding:16px;border:1px solid #bfdbfe;border-radius:14px;background:#eff6ff;">\n <div style="font-size:14px;font-weight:800;color:#172554;margin-bottom:6px;">Secure PayPal Payment</div>\n <div style="font-size:13px;color:#475569;margin-bottom:12px;">${"full"===yatoonData.nativePaymentMode?a("Pay the full appointment total with PayPal to confirm your booking."):a("Choose PayPal below to pay the deposit and confirm your appointment.")}</div>\n <div id="sbs-paypal-button-container"></div>\n <div id="sbs-paypal-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>`);const e=t("#sbs-booking-form");e.length?e.prepend(i):t(".sbs-step-5").prepend(i)}const p=t("#sbs-paypal-payment-status"),d=yatoonData.ajax_url||yatoonData.ajaxUrl;function c(e,t){const o=new FormData;return Object.keys(n).forEach(function(e){const t=n[e];Array.isArray(t)?t.forEach(function(t){o.append(e+"[]",t)}):o.append(e,null==t?"":t)}),o.set("action",e),o.set("nonce",yatoonData.nonce),Object.keys(t||{}).forEach(function(e){o.set(e,t[e])}),fetch(d,{method:"POST",body:o,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!e||!e.success||!e.data)throw new Error(e&&e.data&&e.data.message?e.data.message:a("PayPal payment failed."));return e.data})}t("#sbs-paypal-button-container").empty(),e.paypal.Buttons({style:{layout:"vertical",shape:"rect",label:"paypal"},createOrder:function(){return p.text(a("Preparing secure PayPal Checkout...")),c("yatoon_paypal_create_order").then(function(e){return e.amount_display&&p.text(("full"===yatoonData.nativePaymentMode?a("Full payment due now:"):a("Deposit due now:"))+" "+e.amount_display),e.order_id})},onApprove:function(e){return p.text(a("Confirming your PayPal payment...")),c("yatoon_paypal_capture_order",{order_id:e.orderID}).then(function(t){p.text(a("Payment approved. Confirming your appointment...")),i.hide(),r(t.order_id||e.orderID)}).catch(function(e){p.text(e.message||a("PayPal could not capture the payment.")),o._showToast(e.message||a("PayPal could not capture the payment."),"error"),s(e)})},onCancel:function(){const e=new Error(a("PayPal Checkout was cancelled."));p.text(e.message),s(e)},onError:function(e){p.text(a("PayPal Checkout could not be opened. Please try again.")),o._showToast(e&&e.message?e.message:a("PayPal Checkout failed."),"error"),s(e instanceof Error?e:new Error(a("PayPal Checkout failed.")))}}).render("#sbs-paypal-button-container").then(function(){i.show(),i[0]&&i[0].scrollIntoView&&i[0].scrollIntoView({behavior:"smooth",block:"center"})}).catch(s)})}_squareMethods(){const e=yatoonData&&Array.isArray(yatoonData.squarePaymentMethods)?yatoonData.squarePaymentMethods:["card"];return e.length?e:["card"]}_previewSquarePayment(e){const t=new FormData;return Object.keys(e).forEach(function(a){const n=e[a];Array.isArray(n)?n.forEach(function(e){t.append(a+"[]",e)}):t.append(a,null==n?"":n)}),t.set("action","yatoon_square_preview_payment"),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:t,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!e||!e.success||!e.data){const t=e&&e.data&&e.data.message?e.data.message:a("Could not calculate the Square payment amount.");throw new Error(t)}return e.data})}_buildSquarePaymentRequest(e,t){return e.paymentRequest({countryCode:(yatoonData.squareCountryCode||"US").toUpperCase(),currencyCode:(t.currency||yatoonData.currency||"USD").toUpperCase(),total:{amount:t.amount||"0.00",label:"full"===yatoonData.squarePaymentMode?a("Appointment total"):a("Booking deposit")}})}_ensureSquarePaymentCard(n){const o=this,r=JSON.stringify({services_json:n.services_json||"",service_id:n.service_id||"",selected_options:n.selected_options||[],coupon_code:n.coupon_code||"",customer_email:n.customer_email||"",customer_phone:n.customer_phone||"",client_reference:n.client_reference||"",checkout_token:n.checkout_token||"",start_at:n.start_at||"",location:n.yatoon_location_id||0,tip_amount:n.tip_amount||0,gift_card_code:n.gift_card_code||""});return this._squareCardPromise&&this._squarePaymentPayloadKey===r||(this._squarePaymentPayloadKey=r,this._squareCardPromise=new Promise(function(r,s){if(!o._squarePaymentsReady())return void s(new Error(a("Square payment form is not ready. Please refresh and try again.")));let i=t("#sbs-square-payment-box");if(!i.length){const e="full"===yatoonData.squarePaymentMode?a("Pay securely now to confirm your appointment."):a("Pay your deposit securely now to confirm your appointment.");i=t(`\n <div id="sbs-square-payment-box" class="sbs-square-payment-box" style="margin:16px 0;padding:16px;border:1px solid #dbeafe;border-radius:14px;background:#eff6ff;">\n <div style="font-size:14px;font-weight:800;color:#1e3a8a;margin-bottom:6px;">Secure Square Payment</div>\n <div style="font-size:13px;color:#475569;margin-bottom:12px;">${e}</div>\n <div id="sbs-square-payment-amount" style="font-size:13px;font-weight:800;color:#0f172a;margin-bottom:12px;"></div>\n <div id="sbs-square-method-tabs" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;"></div>\n <button id="sbs-square-apple-pay-button" type="button" class="sbs-square-method-panel" data-method-panel="apple_pay" style="display:none;width:100%;min-height:44px;border-radius:8px;border:0;background:#000;color:#fff;font-weight:800;">Apple Pay</button>\n <div id="sbs-square-google-pay" class="sbs-square-method-panel" data-method-panel="google_pay" style="display:none;"></div>\n <div id="sbs-square-cash-app-pay" class="sbs-square-method-panel" data-method-panel="cash_app_pay" style="display:none;"></div>\n <div id="sbs-square-gift-card-container" class="sbs-square-method-panel" data-method-panel="gift_card" style="display:none;"></div>\n <div id="sbs-square-card-container"></div>\n <div id="sbs-square-payment-status" style="font-size:12px;color:#64748b;margin-top:10px;"></div>\n </div>\n `);const n=t("#sbs-booking-form");n.length?n.prepend(i):t(".sbs-step-5").prepend(i)}t("#sbs-square-payment-status").text(a("Loading secure Square card form...")),o._previewSquarePayment(n).then(function(s){return t("#sbs-square-payment-amount").text(("full"===s.payment_mode?a("Pay now:"):a("Deposit due now:"))+" "+s.amount_display),Promise.resolve(e.Square.payments(yatoonData.squareApplicationId,yatoonData.squareLocationId)).then(function(i){const p=o._squareMethods(),d={payments:i,preview:s,methods:{},selected:p[0]||"card"},c=o._buildSquarePaymentRequest(i,s),u={card:"Card",apple_pay:a("Apple Pay"),google_pay:a("Google Pay"),cash_app_pay:a("Cash App"),gift_card:a("Gift Card")},y=t("#sbs-square-method-tabs").empty();function l(e){d.selected=e,t(".sbs-square-method-tab").each(function(){const a=t(this).data("method")===e;t(this).css({background:a?"#1d4ed8":"#fff",color:a?"#fff":"#1e3a8a"})}),t(".sbs-square-method-panel").hide(),t("#sbs-square-card-container").toggle("card"===e),t('[data-method-panel="'+e+'"]').show(),t("#sbs-square-payment-status").text(a("apple_pay"===e||"cash_app_pay"===e?"Tap the wallet button above to authorize payment, then booking will continue automatically.":"Payment details are encrypted by Square."))}p.forEach(function(e){t("<button/>",{type:"button",class:"sbs-square-method-tab","data-method":e,text:u[e]||e}).css({border:"1px solid #bfdbfe",background:e===d.selected?"#1d4ed8":"#fff",color:e===d.selected?"#fff":"#1e3a8a",borderRadius:"999px",padding:"8px 12px",fontWeight:"800",cursor:"pointer"}).appendTo(y)}),t(document).off("click.squareMethod").on("click.squareMethod",".sbs-square-method-tab",function(){l(t(this).data("method"))});const m=[];return p.includes("card")&&m.push(i.card().then(function(e){return d.methods.card=e,e.attach("#sbs-square-card-container")})),p.includes("gift_card")&&"function"==typeof i.giftCard&&m.push(i.giftCard().then(function(e){return d.methods.gift_card=e,e.attach("#sbs-square-gift-card-container")}).catch(function(){})),p.includes("apple_pay")&&"function"==typeof i.applePay&&m.push(i.applePay(c).then(function(e){d.methods.apple_pay=e,t("#sbs-square-apple-pay-button").off("click.squareApple").on("click.squareApple",function(t){t.preventDefault(),o._handleSquareWalletButton(n,e,"apple_pay")})}).catch(function(){t('[data-method="apple_pay"], [data-method-panel="apple_pay"]').hide()})),p.includes("google_pay")&&"function"==typeof i.googlePay&&m.push(i.googlePay(c).then(function(e){return d.methods.google_pay=e,e.attach("#sbs-square-google-pay")}).catch(function(){t('[data-method="google_pay"], [data-method-panel="google_pay"]').hide()})),p.includes("cash_app_pay")&&"function"==typeof i.cashAppPay&&m.push(i.cashAppPay(c,{redirectURL:e.location.href,referenceId:"yatoon-"+Date.now()}).then(function(e){return d.methods.cash_app_pay=e,e.addEventListener("ontokenization",function(e){const t=e.detail||{};t.error?o._showToast(a("Cash App Pay could not be authorized."),"error"):t.tokenResult&&"OK"===t.tokenResult.status&&o._finishSquareTokenPayment(n,t.tokenResult.token,"cash_app_pay")}),e.attach("#sbs-square-cash-app-pay")}).catch(function(){t('[data-method="cash_app_pay"], [data-method-panel="cash_app_pay"]').hide()})),Promise.all(m).then(function(){o._squarePaymentState=d,l(d.methods[d.selected]?d.selected:d.methods.card?"card":Object.keys(d.methods)[0]),r(d)})})}).catch(function(e){o._squareCardPromise=null,s(e)})})),this._squareCardPromise}_finishSquareTokenPayment(e,n,o){const r=this;return t("#sbs-square-payment-status").text(a("Completing")+" "+(o||a("Square"))+" "+a("payment...")),this._sendSquareTokenPayment(e,n).then(function(n){return r._squarePreparedPaymentId=n,r._squarePreparedPaymentReference=e.client_reference,r._rememberCheckoutPayment&&r._rememberCheckoutPayment(e.client_reference,"square_payment_id",n),t("#sbs-square-payment-status").text(a("Payment approved by Square. Confirming your booking...")),r._isSubmitting=!1,r.submitBooking(),n}).catch(function(e){throw r._showToast(e&&e.message?e.message:a("Square payment failed. Please try again."),"error"),e})}_handleSquareWalletButton(e,n,o){const r=this;return t("#sbs-square-payment-status").text(a("Opening")+" "+a("apple_pay"===o?"Apple Pay":"Square wallet")+"..."),n.tokenize().then(function(t){if(!t||"OK"!==t.status||!t.token){const e=t&&t.errors&&t.errors.length?t.errors.map(function(e){return e.message}).join(" "):a("The wallet payment was not authorized.");throw new Error(e)}return r._finishSquareTokenPayment(e,t.token,o)}).catch(function(e){t("#sbs-square-payment-status").text(e&&e.message?e.message:a("Wallet payment failed.")),r._showToast(e&&e.message?e.message:a("Wallet payment failed. Please try again."),"error")})}_sendSquareTokenPayment(e,t){const n=new FormData;return Object.keys(e).forEach(function(t){const a=e[t];Array.isArray(a)?a.forEach(function(e){n.append(t+"[]",e)}):n.append(t,null==a?"":a)}),n.set("action","yatoon_square_create_payment"),n.set("source_id",t),fetch(yatoonData.ajax_url||yatoonData.ajaxUrl,{method:"POST",body:n,credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){if(!(e&&e.success&&e.data&&e.data.payment_id)){const t=e&&e.data&&e.data.message?e.data.message:a("Square payment failed. Please try again.");throw new Error(t)}return e.data.payment_id})}_createSquarePaymentForPayload(e){const n=this;return this._squarePaymentsReady()?this._ensureSquarePaymentCard(e).then(function(e){t("#sbs-square-payment-box").show();const n=document.getElementById("sbs-square-payment-box");n&&n.scrollIntoView({behavior:"smooth",block:"center"});const o=e.selected||"card",r=e.methods[o];if(!r)throw new Error(a("This Square payment method is not available on this device. Please choose another method."));return"cash_app_pay"===o?(t("#sbs-square-payment-status").text(a("Tap the Cash App Pay button above to authorize payment.")),new Promise(function(){})):(t("#sbs-square-payment-status").text(a("Securing your payment with Square...")),r.tokenize())}).then(function(t){if(!t||"OK"!==t.status||!t.token){const e=t&&t.errors&&t.errors.length?t.errors.map(function(e){return e.message}).join(" "):a("Please check your card details and try again.");throw new Error(e)}return n._sendSquareTokenPayment(e,t.token)}).then(function(e){return t("#sbs-square-payment-status").text(a("Payment approved by Square.")),e}).catch(function(e){throw t("#sbs-square-payment-status").text(e&&e.message?e.message:a("Square payment failed.")),n._showToast(e&&e.message?e.message:a("Square payment failed. Please try again."),"error"),e}):Promise.reject(new Error(a("Square payment is enabled but the secure payment form is unavailable.")))}}Object.getOwnPropertyNames(o.prototype).forEach(function(e){"constructor"!==e&&Object.defineProperty(n.prototype,e,Object.getOwnPropertyDescriptor(o.prototype,e))})}}(window,window.jQuery); -
yatoon-booking-system/trunk/assets/js/yatoon-asset-manifest.json
r3780403 r3780965 1 { 2 "version": "4.10.0", 3 "builder": "terser-5.50.0 + postcss-8.5.6/cssnano-7.1.2/rtlcss-4.3.0", 4 "inputs": { 5 "yatoon-category-bar-423-path16.js": { 6 "sha256": "d9d21e398c540a08d8e07c291b54a5f670616e5c5da35fbff9f3b579b7424cc7", 7 "bytes": 11121 8 }, 9 "frontend.js": { 10 "sha256": "338ebe2b74415737c7616e1e36b62a28028dae5aa2037f6a4b1a5b2bc68a7ded", 11 "bytes": 182985 12 }, 13 "manage-booking.js": { 14 "sha256": "aadbdf0f0c0b4e26eaa5dd4625d79387d7e0f9906cb9a6403cf3626d7d4907c7", 15 "bytes": 36499 16 }, 17 "customer-portal.js": { 18 "sha256": "c139f4be47fa849e90565371e16c10919c697736b0d22dd33ef6d85d3f005707", 19 "bytes": 83590 20 }, 21 "admin-services.js": { 22 "sha256": "7f8c293589fc1f2a4d9be24b19c78668e9b73106ec1eb8cd111f31b5ff88f376", 23 "bytes": 79799 24 }, 25 "admin.js": { 26 "sha256": "4b0851842309bc4e794d67c903f8ae777f93f455a6b69e1729d2f813a88e4b9a", 27 "bytes": 23364 28 }, 29 "admin-settings.js": { 30 "sha256": "0f6928ef9a7c2967f5759ff846bc2492af4faf8490352b9d01f7af4491dc2a64", 31 "bytes": 58129 32 }, 33 "admin-option-groups.js": { 34 "sha256": "dab46594bdf73d1eea2a85e79f976570c34185d9434633483bb086facc2c3f9c", 35 "bytes": 15069 36 }, 37 "frontend-payments.js": { 38 "sha256": "17b903150a7629e803d3c8664642a7a4c3b693f7473bff24216e35375a70cf5c", 39 "bytes": 35380 40 }, 41 "yatoon-concierge-4766.js": { 42 "sha256": "079493bf51ced34a809eb3fbc06079f507070627e247d1955019297acbcb59a1", 43 "bytes": 131985 44 }, 45 "admin-calendar.js": { 46 "sha256": "46ecdfa78ad656102c720dd6deb0e0ef97ca94e758c1b56f5ba9c33b38ce7c9a", 47 "bytes": 36565 48 }, 49 "admin-clients.js": { 50 "sha256": "a42717f6b0c4f1f6515040a218cfa681be7e7d44d82261f6a7e1402c1cb3b2ce", 51 "bytes": 29292 52 }, 53 "admin-bookings.js": { 54 "sha256": "c1f8b151b6d7e097443634572aad2714aeb36cda507f525f7fe5842a6f1d467f", 55 "bytes": 41934 56 }, 57 "admin-staff.js": { 58 "sha256": "b6b6e56b538ed9f2b6768104c7b7cc2bda2d94ffa48ff00932e964b1fe454b89", 59 "bytes": 54358 60 }, 61 "staff-portal.js": { 62 "sha256": "2e36384d5c6d37a7f50d02b21505bdff0cc4c4bb39e247fe9f1edf4f62ceef68", 63 "bytes": 220988 64 }, 65 "frontend-availability.js": { 66 "sha256": "4a271e0ecb0db8a4385331c67ba27776c3c7212aafe4e29e9f9ae49eace017c8", 67 "bytes": 70358 68 }, 69 "frontend-checkout.js": { 70 "sha256": "44d9771ecd3505f72066e6eae910998ff38a2cb5dd4ff8363276f71549e062d2", 71 "bytes": 68665 72 }, 73 "frontend-recovery.js": { 74 "sha256": "f96d9a84be0724732eb6baf4292fa0f5a81a6523f53456de5e880c7cca1ccef8", 75 "bytes": 4566 76 }, 77 "frontend-glass.js": { 78 "sha256": "595c0c6c539d1495470f9597465a863e913fe81f726c7c7824c4f92d5051d66d", 79 "bytes": 1416 80 }, 81 "client-merge-ui.js": { 82 "sha256": "a4f80bea59a75459b0625f295ba486753fd266c8e410d847a640b7f2d9fb31fe", 83 "bytes": 7635 84 }, 85 "staff-hours-editor.js": { 86 "sha256": "9c8f00b26da3dd8c26b9160f5e8e3dd55507743aebaaf84895faa584fce27a96", 87 "bytes": 8209 88 }, 89 "admin-tools.js": { 90 "sha256": "d084fac962bd24d074f636ae04a3e084bf6e22ff4458ba79f57854647cd9c206", 91 "bytes": 6818 92 }, 93 "yatoon-app-shell.js": { 94 "sha256": "801018f7cf5f30cfade4ed8ae3905624df97d3a714a6cf3ec335db094edfc877", 95 "bytes": 9793 96 }, 97 "yatoon-category-bar-4721.js": { 98 "sha256": "3596279a0fb230ed54ae6fc8ba7f7f0dc207c81891ea345b758bc9397085ff68", 99 "bytes": 14196 100 }, 101 "frontend-flow.js": { 102 "sha256": "1529602f4b91c5be53f8c84f3fcd63b10e8f7e295d46697ad1edada2afc62392", 103 "bytes": 233386 104 }, 105 "frontend-cart.js": { 106 "sha256": "24fd1e3756f95e3e9715f5945ee201e1095df68c12fd24d57dbc14a3184296d4", 107 "bytes": 120622 108 }, 109 "frontend-boot.js": { 110 "sha256": "c0d60031a8f1da307ea5e896a747f96616a76de18fa6021e5ddcb8d74fe8ae37", 111 "bytes": 30947 112 }, 113 "yatoon-booking-header.js": { 114 "sha256": "2bb689d5bf4e08a80d27582ee5a4474c029c45b67a7c12da1401bb8e3bdc8aaf", 115 "bytes": 11913 116 }, 117 "yatoon-language-order.js": { 118 "sha256": "599194bba4daf0a4258843f43df0082d3aae7f78c0e0432efc1f281d6527e9d4", 119 "bytes": 2125 120 } 121 }, 122 "outputs": { 123 "frontend.min.js": { 124 "sha256": "2358e461fd346486cc1d89f8702c1bca3e762ffd68863288166a93c03dd38773", 125 "bytes": 78688 126 }, 127 "manage-booking.min.js": { 128 "sha256": "aadbdf0f0c0b4e26eaa5dd4625d79387d7e0f9906cb9a6403cf3626d7d4907c7", 129 "bytes": 36499 130 }, 131 "customer-portal.min.js": { 132 "sha256": "c139f4be47fa849e90565371e16c10919c697736b0d22dd33ef6d85d3f005707", 133 "bytes": 83590 134 }, 135 "admin-services.min.js": { 136 "sha256": "18c487c0411571490cf721d0b30b49f2eff8e60d3d6c662e36d3920b7120c32f", 137 "bytes": 46201 138 }, 139 "admin.min.js": { 140 "sha256": "ff2b431a9d6dc0f5e8c391ca762c27172461acfcf4ff85773bc865e5e9f75c37", 141 "bytes": 10612 142 }, 143 "admin-settings.min.js": { 144 "sha256": "38db0164f533a4edfe41d999727e1f67705d498a8f50f50af0532e10e656ccb0", 145 "bytes": 31390 146 }, 147 "admin-option-groups.min.js": { 148 "sha256": "7bc60b7c3208f3dc3d6380207ed551ed1619d00924c5a62cafa071958fbcef3e", 149 "bytes": 11420 150 }, 151 "frontend-payments.min.js": { 152 "sha256": "e2c70a3d8bde13b32d4016a02835d6a2b2dc63e0171f74ef06ce829609f40925", 153 "bytes": 18861 154 }, 155 "frontend-availability.min.js": { 156 "sha256": "aaa225d5ee3a114a82e1af57be8180d866d140f0ddbab2f81c3059f7c4fdeefb", 157 "bytes": 29644 158 }, 159 "yatoon-category-bar-423-path16.min.js": { 160 "sha256": "a5608fd4415c1dbf4e851a4f207e60c8dd48e96f8ff9e7da3b396f6c71673b7d", 161 "bytes": 6115 162 }, 163 "yatoon-concierge-4766.min.js": { 164 "sha256": "091e689701686070f21841c298121cd67163b6a0214b39a002d4bf96aa5e7652", 165 "bytes": 51279 166 }, 167 "admin-calendar.min.js": { 168 "sha256": "ff82d1459da6b1f422dfd4437df106919891ed8fcc05e756c708513c87cb54d7", 169 "bytes": 18956 170 }, 171 "admin-clients.min.js": { 172 "sha256": "9dea7f478d7b3d9310a1f9c0375bf18ccde5857ce0402a712407d48227dd7dda", 173 "bytes": 17378 174 }, 175 "admin-bookings.min.js": { 176 "sha256": "f6046d4ee5b556126f2ea5d91511dc69d1fef81827bcf9177d14e99344dbe5e1", 177 "bytes": 28731 178 }, 179 "admin-staff.min.js": { 180 "sha256": "3316771f28e0e574ad1ee09f68e993db71dc5943060c7b7a97ed39312a90a7a2", 181 "bytes": 33428 182 }, 183 "staff-portal.min.js": { 184 "sha256": "2e36384d5c6d37a7f50d02b21505bdff0cc4c4bb39e247fe9f1edf4f62ceef68", 185 "bytes": 220988 186 }, 187 "frontend-checkout.min.js": { 188 "sha256": "d45284aad5790bd63b1880dcc05fcb84c600fb771c04ce29dd2e68259b63c51f", 189 "bytes": 27884 190 }, 191 "frontend-recovery.min.js": { 192 "sha256": "fcc85f9e563b837cab4f76d417b20efb3004378b16f34d81e6cc4af405588ff7", 193 "bytes": 3081 194 }, 195 "yatoon-app-shell.min.js": { 196 "sha256": "801018f7cf5f30cfade4ed8ae3905624df97d3a714a6cf3ec335db094edfc877", 197 "bytes": 9793 198 }, 199 "yatoon-category-bar-4721.min.js": { 200 "sha256": "cc9730273303f106ad4ca0a8d11a9723f00d2f4d0ab2d3fd7bccb6f80c2a70aa", 201 "bytes": 7178 202 }, 203 "frontend-flow.min.js": { 204 "sha256": "1529602f4b91c5be53f8c84f3fcd63b10e8f7e295d46697ad1edada2afc62392", 205 "bytes": 233386 206 }, 207 "frontend-cart.min.js": { 208 "sha256": "24fd1e3756f95e3e9715f5945ee201e1095df68c12fd24d57dbc14a3184296d4", 209 "bytes": 120622 210 }, 211 "frontend-boot.min.js": { 212 "sha256": "b83003f71f6a02c18efa96508552fffd4087da007b02ac7a34eb86552b35b234", 213 "bytes": 15656 214 }, 215 "frontend-steps.min.js": { 216 "sha256": "5244218e1cc8c6eda02c5ca557c104a66594ab53b95c1ec740972f2d9b103180", 217 "bytes": 81847 218 }, 219 "frontend.bundle.min.js": { 220 "sha256": "c3a8002ca40541d6d7fc5534d2a8b24aed5a6816e134dcb28b094a7a9ce109ce", 221 "bytes": 448361 222 } 223 }, 224 "css_inputs": { 225 "frontend.css": { 226 "sha256": "41a3b2b765cf4a4a6646664009bbc55e6b848c351061169449290751c94caf5c", 227 "bytes": 274924 228 }, 229 "yatoon-booking-bundle.css": { 230 "sha256": "2b9f874ee912d2a42e2fedb93d045eb82c813e8713301f0a757b0f18cf144473", 231 "bytes": 416 232 }, 233 "yatoon-booking-final.css": { 234 "sha256": "810d51757acea75ec0dbabac87dca581bf4c866dbee37c5d8937bfdbc5991d2b", 235 "bytes": 71386 236 }, 237 "apple-polish.css": { 238 "sha256": "66aefa6e5e9daa980fac6f33ffe95b878f26a2cb50c791222fc368007c6afdb5", 239 "bytes": 10131 240 }, 241 "yatoon-ui-polish.css": { 242 "sha256": "7bfb8a792cadb7412456e45d5e74f30b34749426ce3a8551573c4dedc5e976fb", 243 "bytes": 111082 244 }, 245 "yatoon-design-system.css": { 246 "sha256": "981bbb291a331dff7529dfddec6a3ab176f79f599bb8b983dc76c987109da310", 247 "bytes": 42448 248 }, 249 "yatoon-motion-polish.css": { 250 "sha256": "c7a758608be1b9272933ef4e9cbf0f5d23a4348e5e09731bbc5e51732e14ede7", 251 "bytes": 2103 252 }, 253 "yatoon-category-bar-423-path16.css": { 254 "sha256": "e8b85960ff07b991b0f1b6714358a913a7097537c2a883020e153cb7d9a16c2c", 255 "bytes": 4871 256 }, 257 "yatoon-concierge-4757.css": { 258 "sha256": "8e08fee86c08d37e4dc90787f28a375c0c32bc83ed8dee328336f4e368ab2373", 259 "bytes": 26524 260 }, 261 "admin-calendar.css": { 262 "sha256": "39c78d8120ae664b4c4205c4306c377dc344f948624336dba63a74272823b8d0", 263 "bytes": 21529 264 }, 265 "admin-calendar-rtl.css": { 266 "sha256": "9b3b47f492056ae3186f7ad278955cb154218dfb5f8557c644d29e0ad17e13d2", 267 "bytes": 21529 268 }, 269 "admin-clients.css": { 270 "sha256": "9f38abe8dcb60ad4ee74af66839fffe730e84a1eb9474ca06f1db4374f1e0149", 271 "bytes": 11234 272 }, 273 "admin-clients-rtl.css": { 274 "sha256": "00fe481c7c305a9cd07daf1af8609e276ab05ae32c3bb15f37f32888b28bfeca", 275 "bytes": 11237 276 }, 277 "admin-dashboard.css": { 278 "sha256": "e9e2c37b664f26d1791977676453c6e125bc86330db03566a42348c8354a3fd9", 279 "bytes": 12570 280 }, 281 "yatoon-color-schemes.css": { 282 "sha256": "784d7e6dd912894c3fef4a278e90eb75350f2a3dd0bb12319d5d4e98cbfca872", 283 "bytes": 71724 284 }, 285 "yatoon-theme-preview.css": { 286 "sha256": "707ece181bfb8eb30eb2c54384d02cae9b8638ece567e8150c548dc5ecc01e56", 287 "bytes": 22155 288 }, 289 "yatoon-app-shell.css": { 290 "sha256": "79fe24a1d2852409a46796fa5b6a42a2ca9dfb8be4ed06fbbef4b639eaaff474", 291 "bytes": 32896 292 }, 293 "manage-booking.css": { 294 "sha256": "ccde50e15dc10671de366575dcfa1bc93319aed409a1771d05dd4ec6ed7c76e9", 295 "bytes": 19507 296 }, 297 "staff-portal.css": { 298 "sha256": "b60f1cd59069ad536b5088293f883aa41afa35d0bbcd2c3127783d4e04cb49a9", 299 "bytes": 123789 300 }, 301 "yatoon-seasonal-viewport-4781.css": { 302 "sha256": "347ddefa10bba3327b1918be78913125e55164c643128caac5ceac81a5ca2723", 303 "bytes": 8190 304 }, 305 "frontend-glass.css": { 306 "sha256": "060681cdf1a6b9805f40a6d788b12b39c00e2a6e0007ea57c69e17e9142374a3", 307 "bytes": 664 308 }, 309 "customer-portal.css": { 310 "sha256": "f881d319ad2873eaa0de81cbb060c429744d334a8cfdcfd4e3444623a923d8ab", 311 "bytes": 35043 312 }, 313 "client-merge-ui.css": { 314 "sha256": "d328401272323ca1026ef0928573c09aa3151f16e4d95388362a3dd3f9b0b5ac", 315 "bytes": 2336 316 }, 317 "staff-hours-editor.css": { 318 "sha256": "70a2fac16897f3d9f523a1581f23de04d392f4110841229f064844432be39cd9", 319 "bytes": 2226 320 }, 321 "admin-tools.css": { 322 "sha256": "f3f79f99b46c3e2613175254f54ce06454c952bebbdde278fa05c68ac923e464", 323 "bytes": 14457 324 }, 325 "admin-setup-wizard.css": { 326 "sha256": "11b02bc28c20df7a5189165173103ebab2dba28318ead2520a261f7068953b66", 327 "bytes": 7499 328 }, 329 "yatoon-booking-discovery.css": { 330 "sha256": "8c33bc55568bfd39b9acf0fe0ee1e380e69d475e992477a6909fccac0525b9a0", 331 "bytes": 1231 332 }, 333 "yatoon-booking-header.css": { 334 "sha256": "597726d71d1e251243a7d56ddb6c81a2e51f0af33a345404b87f1b75443a3268", 335 "bytes": 48073 336 } 337 }, 338 "css_outputs": { 339 "frontend-rtl.css": { 340 "sha256": "4fcc61fab31b13e36746b260f9a8658f784ebe5838527d00df96eabd372cf596", 341 "bytes": 274828 342 }, 343 "frontend.min.css": { 344 "sha256": "d755cf890841367223dd97f290d8b933c80681f60cf85f6bcf8100a2373b7662", 345 "bytes": 190078 346 }, 347 "frontend.min-rtl.css": { 348 "sha256": "576231fe623f4559e2cd918368e2d786276f1764680146544cfbf7bf14ae6c2e", 349 "bytes": 189980 350 }, 351 "yatoon-booking-final-rtl.css": { 352 "sha256": "b1846d748cbe4fbc2d95be026aac1e111abe0481e4ec5b1bb11c5d8482bf0506", 353 "bytes": 71396 354 }, 355 "yatoon-booking-final.min.css": { 356 "sha256": "fe13d8069725b96b098a0d233c871c89003553b72b2a677ca8203a8879f3179a", 357 "bytes": 51544 358 }, 359 "yatoon-booking-final.min-rtl.css": { 360 "sha256": "78e4f83c38324104f7c09c6cc3305135741e03feba84077f008402bf04966aec", 361 "bytes": 51554 362 }, 363 "yatoon-booking-core.min.css": { 364 "sha256": "2fe2d03c4426ca02ffefd11ffdbe1477b5f198913b4a8692c62a711884c6dd51", 365 "bytes": 198836 366 }, 367 "yatoon-booking-core.min-rtl.css": { 368 "sha256": "2bbcea4c58e4b31386906c38ef89b5dc3e49bd7d219d24cc669c715e4d2808b6", 369 "bytes": 198905 370 }, 371 "yatoon-booking-flow.min.css": { 372 "sha256": "6e6c980791ec4f5bcc4e09562700835fd86e23c532b5bc6a0654cbef12e1a5f5", 373 "bytes": 90325 374 }, 375 "yatoon-booking-flow.min-rtl.css": { 376 "sha256": "3386631ef8de2623df26cd4f56c077859da5a5b753fef5bfedca98d625fde3b0", 377 "bytes": 90334 378 }, 379 "yatoon-design-system.min.css": { 380 "sha256": "c2cbc79b447e9696a1c82dce32ca5c2acfe40c215f538ff1041856761c036c65", 381 "bytes": 36073 382 }, 383 "yatoon-design-system.min-rtl.css": { 384 "sha256": "570028fe4afa537e34609ec8b6138f0287e2d9364bc057132f23287d249f3bd3", 385 "bytes": 36079 386 }, 387 "yatoon-design-system-rtl.css": { 388 "sha256": "bb8a615fa8d19330e40b55622a4118764e83c5ea5b3ef5db8ae12f2dc2e3d5e8", 389 "bytes": 42454 390 }, 391 "yatoon-concierge-4757.min.css": { 392 "sha256": "c03e6af34c28a629f11f891b00ae6323d81c12ea884fe91a4658855c485a6136", 393 "bytes": 18402 394 }, 395 "admin-calendar.min.css": { 396 "sha256": "33404dd42bf72e0288d745e47835c77a8f943c65cbc975f542581ae1a2cc4116", 397 "bytes": 20844 398 }, 399 "admin-calendar.min-rtl.css": { 400 "sha256": "893162b877b8db9281a895e3de1507b4ce80073e43e1ec969189d8ce6d20ea14", 401 "bytes": 20846 402 }, 403 "admin-clients.min.css": { 404 "sha256": "ce423fecaf41cb6ce16a1caa9c90e7c167169a92ac14d0d8fa67ddf02a618eaa", 405 "bytes": 10182 406 }, 407 "admin-clients.min-rtl.css": { 408 "sha256": "f68db34ec24385cdb44a8e53f21a0d576fa9ae12ac6d8f92ccabff3de3a8278d", 409 "bytes": 10185 410 }, 411 "admin-dashboard.min.css": { 412 "sha256": "0037bfdb2dfaa0bda06d72c6bfb7861dc29a2c85d326857009f1efa7cd361c98", 413 "bytes": 11515 414 }, 415 "admin-dashboard.min-rtl.css": { 416 "sha256": "c8cbf59d96754f7f5d18085462e3ddaf4d6795bfd4980d80ecaf39d13984c80f", 417 "bytes": 11516 418 }, 419 "yatoon-color-schemes.min.css": { 420 "sha256": "2947b3269dad3bfecffd53e411987326c0cf72248955edfe1c6ecb26a88d339e", 421 "bytes": 64203 422 }, 423 "yatoon-color-schemes.min-rtl.css": { 424 "sha256": "2947b3269dad3bfecffd53e411987326c0cf72248955edfe1c6ecb26a88d339e", 425 "bytes": 64203 426 }, 427 "yatoon-theme-preview.min.css": { 428 "sha256": "d7eac486f0adced3d552784675de7c21cef46844c385f80b395c7f8f06441c11", 429 "bytes": 19897 430 }, 431 "yatoon-theme-preview.min-rtl.css": { 432 "sha256": "b0580176744c9922574ce8629527c0a43fa533b095ddcc9769b4d25f64206a2a", 433 "bytes": 19908 434 }, 435 "yatoon-color-schemes-rtl.css": { 436 "sha256": "784d7e6dd912894c3fef4a278e90eb75350f2a3dd0bb12319d5d4e98cbfca872", 437 "bytes": 71724 438 }, 439 "yatoon-theme-preview-rtl.css": { 440 "sha256": "5042c873ed908a826c434c6c83c4ebd053b02942a8e46c70bd9957cb51aabf57", 441 "bytes": 22166 442 }, 443 "yatoon-app-shell-rtl.css": { 444 "sha256": "5bfff9f1a2487fb1f78279a7ac5cd80c67d692012808bc3f8f50cad3bf5c78d0", 445 "bytes": 32908 446 }, 447 "yatoon-app-shell.min.css": { 448 "sha256": "cd9ccb19cbef6a0d42feb7c0c2ae70a23eb04b8693df459778cdc3624d4e439c", 449 "bytes": 23417 450 }, 451 "yatoon-app-shell.min-rtl.css": { 452 "sha256": "c5c52c43dedfa22859427bed065649e2e57df6ea9d6e0ead55ece2b2be1e292f", 453 "bytes": 23425 454 }, 455 "manage-booking-rtl.css": { 456 "sha256": "3ebdcf5de5c267e52ad3cbd47fd7a743501b298cb97532bbfa9dde6001f5777f", 457 "bytes": 19510 458 }, 459 "manage-booking.min.css": { 460 "sha256": "f5d7287ca0ac4cf55a6b63e1fc8b04b63e6e70f043f1f23d32c5bdd52ea8b9ca", 461 "bytes": 13560 462 }, 463 "manage-booking.min-rtl.css": { 464 "sha256": "92c6d808efd9c37c87a618ee97430688d4a8478d28648953b41dff28670a7570", 465 "bytes": 13563 466 }, 467 "staff-portal-rtl.css": { 468 "sha256": "8af62f4563b1ab40a95eb2be04c547ae7e16d9ffa94e7b15d2c8aa8baf3088ac", 469 "bytes": 123823 470 }, 471 "staff-portal.min.css": { 472 "sha256": "b33d5f555a6d1eda7aff23aa4c4ba926143fcad79a5fe68bd6384c44d8a5951e", 473 "bytes": 92450 474 }, 475 "staff-portal.min-rtl.css": { 476 "sha256": "a9d3af72734dd81db4d5ddff67a0b044bb8d2ce041a4d69a66405cfb05f7a788", 477 "bytes": 92481 478 }, 479 "customer-portal-rtl.css": { 480 "sha256": "3a3533ba65af2f364016e4e4ca30ecdc03f47b84a325835ce6b3fc84cc818581", 481 "bytes": 34643 482 }, 483 "customer-portal.min.css": { 484 "sha256": "e886e0d65396c4dd202c93703547e3ec1f111f3be6910f135a951e392615733e", 485 "bytes": 26556 486 }, 487 "customer-portal.min-rtl.css": { 488 "sha256": "dba031b25b63dbcde7ecd9004a71ef4174ba202aceb4e69e9f8590a879cedbf5", 489 "bytes": 26343 490 }, 491 "admin-setup-wizard-rtl.css": { 492 "sha256": "8c2381f5b07e05067b316c10ce4a9333f1ab62714d197bcb85c7ce67e967d676", 493 "bytes": 7502 494 }, 495 "admin-setup-wizard.min.css": { 496 "sha256": "4a9ef36fa5a16fd188b6db80e86a3d825bc786d844a3f1905bcc2facc504d0ba", 497 "bytes": 7046 498 }, 499 "admin-setup-wizard.min-rtl.css": { 500 "sha256": "9cf36af333dae3b82ca7bc98f99ae297e5e59c34ac1766fafb4fa5364bd6e818", 501 "bytes": 7048 502 } 503 }, 504 "frontend_builder": "terser-5.50.0", 505 "staff_portal_builder": "Source-equivalent production JS/CSS; inherited assets retain their original build.", 506 "internal_build": "490-free-20261025-theme-header-lang-picker-compact-languages-ordered-language-picker-mobile-single-brand-row", 507 "css_note": "4.8.2: yatoon-booking-core/flow/final min bundles and frontend/ui-polish/final sources had declarations removed that a later same-selector rule in the same stylesheet always overrides; outputs were edited in place (not rebuilt with cssnano), so hashes are of the shipped files. 4.8.5: core/flow/final min files also had declarations removed that never take effect in the captured cascade and rules for class names the plugin never outputs; outputs edited in place.", 508 "css_bundles": { 509 "yatoon-booking-core.bundle.min.css": { 510 "sha256": "bd16143171cd19aa9b2ef73ee546de2846fe78a8b4b3566d26ec9af34bd85de6", 511 "bytes": 208911, 512 "parts": [ 513 "yatoon-theme-isolation.css", 514 "yatoon-booking-core.min.css" 515 ] 516 }, 517 "yatoon-booking-core.bundle.min-rtl.css": { 518 "sha256": "95a8512c82e3839ce88cae5aaf50236a52e9c57b9abad0bc1a04e62bdbd6d399", 519 "bytes": 208984, 520 "parts": [ 521 "yatoon-theme-isolation.css", 522 "yatoon-booking-core.min-rtl.css" 523 ] 524 }, 525 "yatoon-booking-layers.bundle.min.css": { 526 "sha256": "319ec68f7b14bc6ccb1997f747d36bbab8f985cc73b0c21be51460ba60f96595", 527 "bytes": 79694, 528 "parts": [ 529 "yatoon-color-schemes.min.css", 530 "yatoon-service-image-frame.css", 531 "yatoon-theme-armor-4723.min.css", 532 "yatoon-booking-responsive.min.css" 533 ] 534 }, 535 "yatoon-booking-layers.bundle.min-rtl.css": { 536 "sha256": "0361d779e153376c92d30f991c2ffe1b20f9c39bd6ccd8130ac97f968765d74f", 537 "bytes": 79698, 538 "parts": [ 539 "yatoon-color-schemes.min.css", 540 "yatoon-service-image-frame.css", 541 "yatoon-theme-armor-4723.min.css", 542 "yatoon-booking-responsive.min-rtl.css" 543 ] 544 }, 545 "yatoon-booking-extras.bundle.min.css": { 546 "sha256": "8eb2ad13592a630dc19ff24101d4c69aead136eee39fef404ef6322a46d7d508", 547 "bytes": 9565, 548 "parts": [ 549 "yatoon-seasonal-viewport-4781.css", 550 "yatoon-booking-discovery.css" 551 ] 552 } 553 }, 554 "js_note": "4.8.5: the booking form is split into frontend.js, frontend-flow.js, frontend-cart.js and frontend-boot.js (sources). build_frontend.js generates the lazy chunks frontend-availability.js and frontend-steps.js, every .min.js, and frontend.bundle.min.js.", 555 "css_sources": "4.9.0: assets/css/src/yatoon-booking-core.css and yatoon-booking-flow.css are readable sources with exactly the rules of the shipped .min files; rebuild with csso --no-restructure (keeps rule order), then rtlcss.", 556 "header_note": "Compact local SVG country flags with native details navigation and a circular account control. Header remains visible on step one only.", 557 "cart_note": "Single section dividers and aligned total/duration rows in the mobile drawer; booking calculations are unchanged." 558 } 1 {"version":"4.10.0","builder":"terser-5.50.0 + postcss-8.5.6/cssnano-7.1.2/rtlcss-4.3.0","inputs":{"yatoon-category-bar-423-path16.js":{"sha256":"d9d21e398c540a08d8e07c291b54a5f670616e5c5da35fbff9f3b579b7424cc7","bytes":11121},"frontend.js":{"sha256":"338ebe2b74415737c7616e1e36b62a28028dae5aa2037f6a4b1a5b2bc68a7ded","bytes":182985},"manage-booking.js":{"sha256":"aadbdf0f0c0b4e26eaa5dd4625d79387d7e0f9906cb9a6403cf3626d7d4907c7","bytes":36499},"customer-portal.js":{"sha256":"c139f4be47fa849e90565371e16c10919c697736b0d22dd33ef6d85d3f005707","bytes":83590},"admin-services.js":{"sha256":"7f8c293589fc1f2a4d9be24b19c78668e9b73106ec1eb8cd111f31b5ff88f376","bytes":79799},"admin.js":{"sha256":"4b0851842309bc4e794d67c903f8ae777f93f455a6b69e1729d2f813a88e4b9a","bytes":23364},"admin-settings.js":{"sha256":"0f6928ef9a7c2967f5759ff846bc2492af4faf8490352b9d01f7af4491dc2a64","bytes":58129},"admin-option-groups.js":{"sha256":"dab46594bdf73d1eea2a85e79f976570c34185d9434633483bb086facc2c3f9c","bytes":15069},"frontend-payments.js":{"sha256":"01bcee85136bc3826c39688d57df9082676556080e97185c884c3a63d5497d42","bytes":37720},"yatoon-concierge-4766.js":{"sha256":"079493bf51ced34a809eb3fbc06079f507070627e247d1955019297acbcb59a1","bytes":131985},"admin-calendar.js":{"sha256":"46ecdfa78ad656102c720dd6deb0e0ef97ca94e758c1b56f5ba9c33b38ce7c9a","bytes":36565},"admin-clients.js":{"sha256":"a42717f6b0c4f1f6515040a218cfa681be7e7d44d82261f6a7e1402c1cb3b2ce","bytes":29292},"admin-bookings.js":{"sha256":"c1f8b151b6d7e097443634572aad2714aeb36cda507f525f7fe5842a6f1d467f","bytes":41934},"admin-staff.js":{"sha256":"b6b6e56b538ed9f2b6768104c7b7cc2bda2d94ffa48ff00932e964b1fe454b89","bytes":54358},"staff-portal.js":{"sha256":"2e36384d5c6d37a7f50d02b21505bdff0cc4c4bb39e247fe9f1edf4f62ceef68","bytes":220988},"frontend-availability.js":{"sha256":"4a271e0ecb0db8a4385331c67ba27776c3c7212aafe4e29e9f9ae49eace017c8","bytes":70358},"frontend-checkout.js":{"sha256":"710c9ca74997dd979c4556910328d04a1db66a90a8974282d456701178c7c027","bytes":69189},"frontend-recovery.js":{"sha256":"f96d9a84be0724732eb6baf4292fa0f5a81a6523f53456de5e880c7cca1ccef8","bytes":4566},"frontend-glass.js":{"sha256":"595c0c6c539d1495470f9597465a863e913fe81f726c7c7824c4f92d5051d66d","bytes":1416},"client-merge-ui.js":{"sha256":"a4f80bea59a75459b0625f295ba486753fd266c8e410d847a640b7f2d9fb31fe","bytes":7635},"staff-hours-editor.js":{"sha256":"9c8f00b26da3dd8c26b9160f5e8e3dd55507743aebaaf84895faa584fce27a96","bytes":8209},"admin-tools.js":{"sha256":"d084fac962bd24d074f636ae04a3e084bf6e22ff4458ba79f57854647cd9c206","bytes":6818},"yatoon-app-shell.js":{"sha256":"801018f7cf5f30cfade4ed8ae3905624df97d3a714a6cf3ec335db094edfc877","bytes":9793},"yatoon-category-bar-4721.js":{"sha256":"3596279a0fb230ed54ae6fc8ba7f7f0dc207c81891ea345b758bc9397085ff68","bytes":14196},"frontend-flow.js":{"sha256":"1529602f4b91c5be53f8c84f3fcd63b10e8f7e295d46697ad1edada2afc62392","bytes":233386},"frontend-cart.js":{"sha256":"24fd1e3756f95e3e9715f5945ee201e1095df68c12fd24d57dbc14a3184296d4","bytes":120622},"frontend-boot.js":{"sha256":"c0d60031a8f1da307ea5e896a747f96616a76de18fa6021e5ddcb8d74fe8ae37","bytes":30947},"yatoon-booking-header.js":{"sha256":"2bb689d5bf4e08a80d27582ee5a4474c029c45b67a7c12da1401bb8e3bdc8aaf","bytes":11913},"yatoon-language-order.js":{"sha256":"599194bba4daf0a4258843f43df0082d3aae7f78c0e0432efc1f281d6527e9d4","bytes":2125}},"outputs":{"frontend.min.js":{"sha256":"2358e461fd346486cc1d89f8702c1bca3e762ffd68863288166a93c03dd38773","bytes":78688},"manage-booking.min.js":{"sha256":"aadbdf0f0c0b4e26eaa5dd4625d79387d7e0f9906cb9a6403cf3626d7d4907c7","bytes":36499},"customer-portal.min.js":{"sha256":"c139f4be47fa849e90565371e16c10919c697736b0d22dd33ef6d85d3f005707","bytes":83590},"admin-services.min.js":{"sha256":"18c487c0411571490cf721d0b30b49f2eff8e60d3d6c662e36d3920b7120c32f","bytes":46201},"admin.min.js":{"sha256":"ff2b431a9d6dc0f5e8c391ca762c27172461acfcf4ff85773bc865e5e9f75c37","bytes":10612},"admin-settings.min.js":{"sha256":"38db0164f533a4edfe41d999727e1f67705d498a8f50f50af0532e10e656ccb0","bytes":31390},"admin-option-groups.min.js":{"sha256":"7bc60b7c3208f3dc3d6380207ed551ed1619d00924c5a62cafa071958fbcef3e","bytes":11420},"frontend-payments.min.js":{"sha256":"52b59f072af0b0df01b6d3505820515db57c968c2835c402e8af7fb05365b9d3","bytes":19251},"frontend-availability.min.js":{"sha256":"aaa225d5ee3a114a82e1af57be8180d866d140f0ddbab2f81c3059f7c4fdeefb","bytes":29644},"yatoon-category-bar-423-path16.min.js":{"sha256":"a5608fd4415c1dbf4e851a4f207e60c8dd48e96f8ff9e7da3b396f6c71673b7d","bytes":6115},"yatoon-concierge-4766.min.js":{"sha256":"091e689701686070f21841c298121cd67163b6a0214b39a002d4bf96aa5e7652","bytes":51279},"admin-calendar.min.js":{"sha256":"ff82d1459da6b1f422dfd4437df106919891ed8fcc05e756c708513c87cb54d7","bytes":18956},"admin-clients.min.js":{"sha256":"9dea7f478d7b3d9310a1f9c0375bf18ccde5857ce0402a712407d48227dd7dda","bytes":17378},"admin-bookings.min.js":{"sha256":"f6046d4ee5b556126f2ea5d91511dc69d1fef81827bcf9177d14e99344dbe5e1","bytes":28731},"admin-staff.min.js":{"sha256":"3316771f28e0e574ad1ee09f68e993db71dc5943060c7b7a97ed39312a90a7a2","bytes":33428},"staff-portal.min.js":{"sha256":"2e36384d5c6d37a7f50d02b21505bdff0cc4c4bb39e247fe9f1edf4f62ceef68","bytes":220988},"frontend-checkout.min.js":{"sha256":"bcfbd71409007b50fd60aa869c6bcd1cbad18b86c21b98a9c70696032e1217db","bytes":28012},"frontend-recovery.min.js":{"sha256":"fcc85f9e563b837cab4f76d417b20efb3004378b16f34d81e6cc4af405588ff7","bytes":3081},"yatoon-app-shell.min.js":{"sha256":"801018f7cf5f30cfade4ed8ae3905624df97d3a714a6cf3ec335db094edfc877","bytes":9793},"yatoon-category-bar-4721.min.js":{"sha256":"cc9730273303f106ad4ca0a8d11a9723f00d2f4d0ab2d3fd7bccb6f80c2a70aa","bytes":7178},"frontend-flow.min.js":{"sha256":"1529602f4b91c5be53f8c84f3fcd63b10e8f7e295d46697ad1edada2afc62392","bytes":233386},"frontend-cart.min.js":{"sha256":"24fd1e3756f95e3e9715f5945ee201e1095df68c12fd24d57dbc14a3184296d4","bytes":120622},"frontend-boot.min.js":{"sha256":"b83003f71f6a02c18efa96508552fffd4087da007b02ac7a34eb86552b35b234","bytes":15656},"frontend-steps.min.js":{"sha256":"5244218e1cc8c6eda02c5ca557c104a66594ab53b95c1ec740972f2d9b103180","bytes":81847},"frontend.bundle.min.js":{"sha256":"c3a8002ca40541d6d7fc5534d2a8b24aed5a6816e134dcb28b094a7a9ce109ce","bytes":448361}},"css_inputs":{"frontend.css":{"sha256":"41a3b2b765cf4a4a6646664009bbc55e6b848c351061169449290751c94caf5c","bytes":274924},"yatoon-booking-bundle.css":{"sha256":"2b9f874ee912d2a42e2fedb93d045eb82c813e8713301f0a757b0f18cf144473","bytes":416},"yatoon-booking-final.css":{"sha256":"810d51757acea75ec0dbabac87dca581bf4c866dbee37c5d8937bfdbc5991d2b","bytes":71386},"apple-polish.css":{"sha256":"66aefa6e5e9daa980fac6f33ffe95b878f26a2cb50c791222fc368007c6afdb5","bytes":10131},"yatoon-ui-polish.css":{"sha256":"7bfb8a792cadb7412456e45d5e74f30b34749426ce3a8551573c4dedc5e976fb","bytes":111082},"yatoon-design-system.css":{"sha256":"981bbb291a331dff7529dfddec6a3ab176f79f599bb8b983dc76c987109da310","bytes":42448},"yatoon-motion-polish.css":{"sha256":"c7a758608be1b9272933ef4e9cbf0f5d23a4348e5e09731bbc5e51732e14ede7","bytes":2103},"yatoon-category-bar-423-path16.css":{"sha256":"e8b85960ff07b991b0f1b6714358a913a7097537c2a883020e153cb7d9a16c2c","bytes":4871},"yatoon-concierge-4757.css":{"sha256":"8e08fee86c08d37e4dc90787f28a375c0c32bc83ed8dee328336f4e368ab2373","bytes":26524},"admin-calendar.css":{"sha256":"39c78d8120ae664b4c4205c4306c377dc344f948624336dba63a74272823b8d0","bytes":21529},"admin-calendar-rtl.css":{"sha256":"9b3b47f492056ae3186f7ad278955cb154218dfb5f8557c644d29e0ad17e13d2","bytes":21529},"admin-clients.css":{"sha256":"9f38abe8dcb60ad4ee74af66839fffe730e84a1eb9474ca06f1db4374f1e0149","bytes":11234},"admin-clients-rtl.css":{"sha256":"00fe481c7c305a9cd07daf1af8609e276ab05ae32c3bb15f37f32888b28bfeca","bytes":11237},"admin-dashboard.css":{"sha256":"e9e2c37b664f26d1791977676453c6e125bc86330db03566a42348c8354a3fd9","bytes":12570},"yatoon-color-schemes.css":{"sha256":"784d7e6dd912894c3fef4a278e90eb75350f2a3dd0bb12319d5d4e98cbfca872","bytes":71724},"yatoon-theme-preview.css":{"sha256":"707ece181bfb8eb30eb2c54384d02cae9b8638ece567e8150c548dc5ecc01e56","bytes":22155},"yatoon-app-shell.css":{"sha256":"79fe24a1d2852409a46796fa5b6a42a2ca9dfb8be4ed06fbbef4b639eaaff474","bytes":32896},"manage-booking.css":{"sha256":"ccfdd6c0adbaad8fa3ed2dc8902f0911a65cea4dcecce99bc481ba4306cabc35","bytes":21975},"staff-portal.css":{"sha256":"b60f1cd59069ad536b5088293f883aa41afa35d0bbcd2c3127783d4e04cb49a9","bytes":123789},"yatoon-seasonal-viewport-4781.css":{"sha256":"347ddefa10bba3327b1918be78913125e55164c643128caac5ceac81a5ca2723","bytes":8190},"frontend-glass.css":{"sha256":"060681cdf1a6b9805f40a6d788b12b39c00e2a6e0007ea57c69e17e9142374a3","bytes":664},"customer-portal.css":{"sha256":"f881d319ad2873eaa0de81cbb060c429744d334a8cfdcfd4e3444623a923d8ab","bytes":35043},"client-merge-ui.css":{"sha256":"d328401272323ca1026ef0928573c09aa3151f16e4d95388362a3dd3f9b0b5ac","bytes":2336},"staff-hours-editor.css":{"sha256":"70a2fac16897f3d9f523a1581f23de04d392f4110841229f064844432be39cd9","bytes":2226},"admin-tools.css":{"sha256":"f3f79f99b46c3e2613175254f54ce06454c952bebbdde278fa05c68ac923e464","bytes":14457},"admin-setup-wizard.css":{"sha256":"11b02bc28c20df7a5189165173103ebab2dba28318ead2520a261f7068953b66","bytes":7499},"yatoon-booking-discovery.css":{"sha256":"8c33bc55568bfd39b9acf0fe0ee1e380e69d475e992477a6909fccac0525b9a0","bytes":1231},"yatoon-booking-header.css":{"sha256":"597726d71d1e251243a7d56ddb6c81a2e51f0af33a345404b87f1b75443a3268","bytes":48073}},"css_outputs":{"frontend-rtl.css":{"sha256":"4fcc61fab31b13e36746b260f9a8658f784ebe5838527d00df96eabd372cf596","bytes":274828},"frontend.min.css":{"sha256":"d755cf890841367223dd97f290d8b933c80681f60cf85f6bcf8100a2373b7662","bytes":190078},"frontend.min-rtl.css":{"sha256":"576231fe623f4559e2cd918368e2d786276f1764680146544cfbf7bf14ae6c2e","bytes":189980},"yatoon-booking-final-rtl.css":{"sha256":"b1846d748cbe4fbc2d95be026aac1e111abe0481e4ec5b1bb11c5d8482bf0506","bytes":71396},"yatoon-booking-final.min.css":{"sha256":"fe13d8069725b96b098a0d233c871c89003553b72b2a677ca8203a8879f3179a","bytes":51544},"yatoon-booking-final.min-rtl.css":{"sha256":"78e4f83c38324104f7c09c6cc3305135741e03feba84077f008402bf04966aec","bytes":51554},"yatoon-booking-core.min.css":{"sha256":"2fe2d03c4426ca02ffefd11ffdbe1477b5f198913b4a8692c62a711884c6dd51","bytes":198836},"yatoon-booking-core.min-rtl.css":{"sha256":"2bbcea4c58e4b31386906c38ef89b5dc3e49bd7d219d24cc669c715e4d2808b6","bytes":198905},"yatoon-booking-flow.min.css":{"sha256":"6e6c980791ec4f5bcc4e09562700835fd86e23c532b5bc6a0654cbef12e1a5f5","bytes":90325},"yatoon-booking-flow.min-rtl.css":{"sha256":"3386631ef8de2623df26cd4f56c077859da5a5b753fef5bfedca98d625fde3b0","bytes":90334},"yatoon-design-system.min.css":{"sha256":"c2cbc79b447e9696a1c82dce32ca5c2acfe40c215f538ff1041856761c036c65","bytes":36073},"yatoon-design-system.min-rtl.css":{"sha256":"570028fe4afa537e34609ec8b6138f0287e2d9364bc057132f23287d249f3bd3","bytes":36079},"yatoon-design-system-rtl.css":{"sha256":"bb8a615fa8d19330e40b55622a4118764e83c5ea5b3ef5db8ae12f2dc2e3d5e8","bytes":42454},"yatoon-concierge-4757.min.css":{"sha256":"c03e6af34c28a629f11f891b00ae6323d81c12ea884fe91a4658855c485a6136","bytes":18402},"admin-calendar.min.css":{"sha256":"33404dd42bf72e0288d745e47835c77a8f943c65cbc975f542581ae1a2cc4116","bytes":20844},"admin-calendar.min-rtl.css":{"sha256":"893162b877b8db9281a895e3de1507b4ce80073e43e1ec969189d8ce6d20ea14","bytes":20846},"admin-clients.min.css":{"sha256":"ce423fecaf41cb6ce16a1caa9c90e7c167169a92ac14d0d8fa67ddf02a618eaa","bytes":10182},"admin-clients.min-rtl.css":{"sha256":"f68db34ec24385cdb44a8e53f21a0d576fa9ae12ac6d8f92ccabff3de3a8278d","bytes":10185},"admin-dashboard.min.css":{"sha256":"0037bfdb2dfaa0bda06d72c6bfb7861dc29a2c85d326857009f1efa7cd361c98","bytes":11515},"admin-dashboard.min-rtl.css":{"sha256":"c8cbf59d96754f7f5d18085462e3ddaf4d6795bfd4980d80ecaf39d13984c80f","bytes":11516},"yatoon-color-schemes.min.css":{"sha256":"2947b3269dad3bfecffd53e411987326c0cf72248955edfe1c6ecb26a88d339e","bytes":64203},"yatoon-color-schemes.min-rtl.css":{"sha256":"2947b3269dad3bfecffd53e411987326c0cf72248955edfe1c6ecb26a88d339e","bytes":64203},"yatoon-theme-preview.min.css":{"sha256":"d7eac486f0adced3d552784675de7c21cef46844c385f80b395c7f8f06441c11","bytes":19897},"yatoon-theme-preview.min-rtl.css":{"sha256":"b0580176744c9922574ce8629527c0a43fa533b095ddcc9769b4d25f64206a2a","bytes":19908},"yatoon-color-schemes-rtl.css":{"sha256":"784d7e6dd912894c3fef4a278e90eb75350f2a3dd0bb12319d5d4e98cbfca872","bytes":71724},"yatoon-theme-preview-rtl.css":{"sha256":"5042c873ed908a826c434c6c83c4ebd053b02942a8e46c70bd9957cb51aabf57","bytes":22166},"yatoon-app-shell-rtl.css":{"sha256":"5bfff9f1a2487fb1f78279a7ac5cd80c67d692012808bc3f8f50cad3bf5c78d0","bytes":32908},"yatoon-app-shell.min.css":{"sha256":"cd9ccb19cbef6a0d42feb7c0c2ae70a23eb04b8693df459778cdc3624d4e439c","bytes":23417},"yatoon-app-shell.min-rtl.css":{"sha256":"c5c52c43dedfa22859427bed065649e2e57df6ea9d6e0ead55ece2b2be1e292f","bytes":23425},"manage-booking-rtl.css":{"sha256":"3ebdcf5de5c267e52ad3cbd47fd7a743501b298cb97532bbfa9dde6001f5777f","bytes":19510},"manage-booking.min.css":{"sha256":"431d40da00dd526cb762ebddf10377431e1982b465a3a0943124a28b17c8f444","bytes":16028},"manage-booking.min-rtl.css":{"sha256":"92c6d808efd9c37c87a618ee97430688d4a8478d28648953b41dff28670a7570","bytes":13563},"staff-portal-rtl.css":{"sha256":"8af62f4563b1ab40a95eb2be04c547ae7e16d9ffa94e7b15d2c8aa8baf3088ac","bytes":123823},"staff-portal.min.css":{"sha256":"b33d5f555a6d1eda7aff23aa4c4ba926143fcad79a5fe68bd6384c44d8a5951e","bytes":92450},"staff-portal.min-rtl.css":{"sha256":"a9d3af72734dd81db4d5ddff67a0b044bb8d2ce041a4d69a66405cfb05f7a788","bytes":92481},"customer-portal-rtl.css":{"sha256":"3a3533ba65af2f364016e4e4ca30ecdc03f47b84a325835ce6b3fc84cc818581","bytes":34643},"customer-portal.min.css":{"sha256":"e886e0d65396c4dd202c93703547e3ec1f111f3be6910f135a951e392615733e","bytes":26556},"customer-portal.min-rtl.css":{"sha256":"dba031b25b63dbcde7ecd9004a71ef4174ba202aceb4e69e9f8590a879cedbf5","bytes":26343},"admin-setup-wizard-rtl.css":{"sha256":"8c2381f5b07e05067b316c10ce4a9333f1ab62714d197bcb85c7ce67e967d676","bytes":7502},"admin-setup-wizard.min.css":{"sha256":"4a9ef36fa5a16fd188b6db80e86a3d825bc786d844a3f1905bcc2facc504d0ba","bytes":7046},"admin-setup-wizard.min-rtl.css":{"sha256":"9cf36af333dae3b82ca7bc98f99ae297e5e59c34ac1766fafb4fa5364bd6e818","bytes":7048}},"frontend_builder":"terser-5.50.0","staff_portal_builder":"Source-equivalent production JS/CSS; inherited assets retain their original build.","internal_build":"490-free-20261025-theme-header-lang-picker-compact-languages-ordered-language-picker-mobile-single-brand-row","css_note":"4.8.2: yatoon-booking-core/flow/final min bundles and frontend/ui-polish/final sources had declarations removed that a later same-selector rule in the same stylesheet always overrides; outputs were edited in place (not rebuilt with cssnano), so hashes are of the shipped files. 4.8.5: core/flow/final min files also had declarations removed that never take effect in the captured cascade and rules for class names the plugin never outputs; outputs edited in place.","css_bundles":{"yatoon-booking-core.bundle.min.css":{"sha256":"bd16143171cd19aa9b2ef73ee546de2846fe78a8b4b3566d26ec9af34bd85de6","bytes":208911,"parts":["yatoon-theme-isolation.css","yatoon-booking-core.min.css"]},"yatoon-booking-core.bundle.min-rtl.css":{"sha256":"95a8512c82e3839ce88cae5aaf50236a52e9c57b9abad0bc1a04e62bdbd6d399","bytes":208984,"parts":["yatoon-theme-isolation.css","yatoon-booking-core.min-rtl.css"]},"yatoon-booking-layers.bundle.min.css":{"sha256":"319ec68f7b14bc6ccb1997f747d36bbab8f985cc73b0c21be51460ba60f96595","bytes":79694,"parts":["yatoon-color-schemes.min.css","yatoon-service-image-frame.css","yatoon-theme-armor-4723.min.css","yatoon-booking-responsive.min.css"]},"yatoon-booking-layers.bundle.min-rtl.css":{"sha256":"0361d779e153376c92d30f991c2ffe1b20f9c39bd6ccd8130ac97f968765d74f","bytes":79698,"parts":["yatoon-color-schemes.min.css","yatoon-service-image-frame.css","yatoon-theme-armor-4723.min.css","yatoon-booking-responsive.min-rtl.css"]},"yatoon-booking-extras.bundle.min.css":{"sha256":"8eb2ad13592a630dc19ff24101d4c69aead136eee39fef404ef6322a46d7d508","bytes":9565,"parts":["yatoon-seasonal-viewport-4781.css","yatoon-booking-discovery.css"]}},"js_note":"4.8.5: the booking form is split into frontend.js, frontend-flow.js, frontend-cart.js and frontend-boot.js (sources). build_frontend.js generates the lazy chunks frontend-availability.js and frontend-steps.js, every .min.js, and frontend.bundle.min.js.","css_sources":"4.9.0: assets/css/src/yatoon-booking-core.css and yatoon-booking-flow.css are readable sources with exactly the rules of the shipped .min files; rebuild with csso --no-restructure (keeps rule order), then rtlcss.","header_note":"Compact local SVG country flags with native details navigation and a circular account control. Header remains visible on step one only.","cart_note":"Single section dividers and aligned total/duration rows in the mobile drawer; booking calculations are unchanged."} -
yatoon-booking-system/trunk/changelog.txt
r3780403 r3780965 6 6 * Security check: with Strict mode off, a Turnstile check that cannot load (for example behind an ad blocker) no longer blocks a real customer; Strict mode on still blocks. 7 7 * Checkout: a refusal before any payment (security check, booking limit) now shows a message and keeps the form editable instead of switching to the booking-status panel. 8 * Stripe checkout: a payment Stripe refuses (no payment method chosen, card declined, failed verification) now shows the reason and keeps the payment form open so the customer can pay again; it no longer ends the checkout in the booking-status panel. 9 * Orders: a cancelled appointment no longer counts toward the balance due. When every appointment on an order is cancelled the order shows as Cancelled with nothing owed; any deposit kept or refunded stays in the payment history. 10 * Stripe checkout: in a cart with two paid appointments, the second payment form now starts with a working Pay button. Before, it kept the first payment's "Processing..." state and the customer could not pay for the second appointment. 11 * Bookings list: a cart with appointments on different days shows the date range, and each expanded row shows its own day, instead of one long block on the first day. 8 12 * Manage booking: date and time follow the appointments that are still booked after a partial cancel; carts on different days show each day. 9 13 -
yatoon-booking-system/trunk/includes/class-yatoon-commerce.php
r3780403 r3780965 81 81 add_action( 'yatoon_booking_created', array( __CLASS__, 'create_for_booking' ), 70, 1 ); 82 82 add_action( 'yatoon_payment_status_changed', array( __CLASS__, 'sync_payment_status' ), 20, 4 ); 83 // 4.10.2: after the cancellation refund (priority 20) so the order shows what is really owed. 84 add_action( 'yatoon_booking_status_changed', array( __CLASS__, 'booking_status_changed' ), 30, 3 ); 83 85 add_action( 'admin_menu', array( __CLASS__, 'add_menu' ), 23 ); 84 86 add_action( 'admin_post_yatoon_record_order_payment', array( __CLASS__, 'record_payment' ) ); … … 602 604 ) ) ); 603 605 $net_paid = max( 0, $paid - $refunds ); 604 $balance = max( 0, (float) $order->total - $net_paid ); 605 $status = $refunds >= $paid && $paid > 0 ? 'refunded' : ( $balance <= 0 ? 'paid' : ( $net_paid > 0 ? 'partial' : 'open' ) ); 606 // 4.10.2: a cancelled appointment is no longer owed. Its line stays on the 607 // order for the record, but it does not count toward the balance due. When 608 // every appointment is cancelled nothing is owed (a tip line included) and 609 // the order is marked cancelled; money kept or refunded stays in the ledger. 610 $lines = yatoon_db_get_row( $wpdb->prepare( 611 "SELECT COUNT(i.booking_id) AS booked, 612 COALESCE(SUM(CASE WHEN LOWER(b.status) IN ('cancelled','canceled','cancelled_by_customer','cancelled_by_seller','declined') THEN 1 ELSE 0 END),0) AS voided, 613 COALESCE(SUM(CASE WHEN LOWER(b.status) IN ('cancelled','canceled','cancelled_by_customer','cancelled_by_seller','declined') THEN i.line_total ELSE 0 END),0) AS voided_total 614 FROM {$wpdb->prefix}yatoon_order_items i 615 LEFT JOIN {$wpdb->prefix}yatoon_bookings b ON b.id=i.booking_id 616 WHERE i.order_id=%d", 617 $order_id 618 ) ); 619 $all_cancelled = $lines && (int) $lines->booked > 0 && (int) $lines->voided >= (int) $lines->booked; 620 $owed = $all_cancelled ? 0.0 : max( 0, (float) $order->total - ( $lines ? (float) $lines->voided_total : 0 ) ); 621 $balance = max( 0, round( $owed - $net_paid, 2 ) ); 622 $status = $refunds >= $paid && $paid > 0 ? 'refunded' : ( $all_cancelled ? 'cancelled' : ( $balance <= 0 ? 'paid' : ( $net_paid > 0 ? 'partial' : 'open' ) ) ); 606 623 $saved_order = yatoon_db_update( 607 624 $wpdb->prefix . 'yatoon_orders', … … 615 632 ); 616 633 return false !== $saved_order && false !== $saved_invoice; 634 } 635 636 /** 4.10.2: refresh the order balance when one of its appointments is cancelled or restored. */ 637 public static function booking_status_changed( $booking_id, $new_status = '', $old_status = '' ) { 638 global $wpdb; 639 $booking_id = absint( $booking_id ); 640 if ( ! $booking_id || (string) $new_status === (string) $old_status ) { 641 return; 642 } 643 $order_ids = array_map( 'absint', (array) yatoon_db_get_col( $wpdb->prepare( 644 "SELECT DISTINCT order_id FROM {$wpdb->prefix}yatoon_order_items WHERE booking_id=%d", 645 $booking_id 646 ) ) ); 647 foreach ( array_filter( $order_ids ) as $order_id ) { 648 self::recalculate( $order_id ); 649 } 617 650 } 618 651 -
yatoon-booking-system/trunk/readme.txt
r3780403 r3780965 212 212 * Security check: with Strict mode off, a Turnstile check that cannot load (for example behind an ad blocker) no longer blocks a real customer; Strict mode on still blocks. 213 213 * Checkout: a refusal before any payment (security check, booking limit) now shows a message and keeps the form editable instead of switching to the booking-status panel. 214 * Stripe checkout: a payment Stripe refuses (no payment method chosen, card declined, failed verification) now shows the reason and keeps the payment form open so the customer can pay again; it no longer ends the checkout in the booking-status panel. 215 * Orders: a cancelled appointment no longer counts toward the balance due. When every appointment on an order is cancelled the order shows as Cancelled with nothing owed; any deposit kept or refunded stays in the payment history. 216 * Stripe checkout: in a cart with two paid appointments, the second payment form now starts with a working Pay button. Before, it kept the first payment's "Processing..." state and the customer could not pay for the second appointment. 217 * Bookings list: a cart with appointments on different days shows the date range, and each expanded row shows its own day, instead of one long block on the first day. 214 218 * Manage booking: date and time follow the appointments that are still booked after a partial cancel; carts on different days show each day. 215 219
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)