PluginProbe
Booking Calendar / 11.5
Booking Calendar v11.5
11.9 11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 All 205 releases
booking / includes / page-availability-timeslots / availability_timeslots__page.php

availability_timeslots__page.php in Booking Calendar 11.5, at includes/page-availability-timeslots/availability_timeslots__page.php

812 lines 31.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Time slots availability admin page.
4 *
5 * @package Booking Calendar
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 if ( ! defined( 'WPBC_AVAILABILITY_TIMESLOTS_DEFAULT_DAYS_COUNT' ) ) {
13 define( 'WPBC_AVAILABILITY_TIMESLOTS_DEFAULT_DAYS_COUNT', 30 );
14 }
15
16 /**
17 * Check whether the reusable Time Slots Availability component is rendered on current admin page.
18 *
19 * @return bool
20 */
21 function wpbc_availability_timeslots__is_component_page() {
22
23 if ( ! is_admin() ) {
24 return false;
25 }
26
27 if ( function_exists( 'wpbc_is_availability_page' ) && wpbc_is_availability_page() ) {
28 return true;
29 }
30
31 if (
32 function_exists( 'wpbc_is_bookings_page' )
33 && wpbc_is_bookings_page()
34 && function_exists( 'wpbc_get_default_saved_view_mode_for_wpbc_page' )
35 ) {
36 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
37 $requested_tab = isset( $_REQUEST['tab'] ) ? sanitize_key( wp_unslash( $_REQUEST['tab'] ) ) : '';
38 if ( '' !== $requested_tab ) {
39 return ( 'vm_booking_listing' === $requested_tab );
40 }
41
42 return ( 'vm_booking_listing' === wpbc_get_default_saved_view_mode_for_wpbc_page() );
43 }
44
45 return false;
46 }
47
48 /**
49 * Enqueue CSS for Time Slots Availability.
50 *
51 * @param string $where_to_load Where assets are loaded.
52 *
53 * @return void
54 */
55 function wpbc_availability_timeslots_enqueue_css_files( $where_to_load ) {
56
57 if ( ( ! is_admin() ) || ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) ) ) {
58 return;
59 }
60
61 if ( ! wpbc_availability_timeslots__is_component_page() ) {
62 return;
63 }
64
65 wp_enqueue_style(
66 'wpbc-availability-timeslots-page',
67 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/availability_timeslots_page.css',
68 array( 'wpbc-calendar', 'wpbc-all-admin' ),
69 WP_BK_VERSION_NUM
70 );
71 }
72 add_action( 'wpbc_enqueue_css_files', 'wpbc_availability_timeslots_enqueue_css_files', 66 );
73
74 /**
75 * Print the same datepicker support CSS that the Booking Listing filter uses.
76 *
77 * @return void
78 */
79 function wpbc_availability_timeslots_print_datepicker_css() {
80
81 if ( ! wpbc_availability_timeslots__is_component_page() ) {
82 return;
83 }
84
85 if ( function_exists( 'wpbc_is_availability_page' ) && wpbc_is_availability_page() ) {
86 $active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
87 if ( 'time_slots_availability' !== $active_tab ) {
88 return;
89 }
90 }
91
92 if ( function_exists( 'wpbc_datepicker_css' ) ) {
93 wpbc_datepicker_css();
94 }
95 }
96 add_action( 'admin_footer', 'wpbc_availability_timeslots_print_datepicker_css', 66 );
97
98 /**
99 * Print tooltip initializer for Time Slots Availability.
100 *
101 * @return void
102 */
103 function wpbc_availability_timeslots_print_tooltip_js() {
104
105 if ( ! wpbc_availability_timeslots__is_component_page() ) {
106 return;
107 }
108
109 if ( function_exists( 'wpbc_is_availability_page' ) && wpbc_is_availability_page() ) {
110 $active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
111 if ( 'time_slots_availability' !== $active_tab ) {
112 return;
113 }
114 }
115
116 if ( function_exists( 'wpbc_bs_javascript_tooltips' ) ) {
117 wpbc_bs_javascript_tooltips();
118 }
119 }
120 add_action( 'admin_footer', 'wpbc_availability_timeslots_print_tooltip_js', 67 );
121
122 /**
123 * Enqueue JS for Time Slots Availability.
124 *
125 * @param string $where_to_load Where assets are loaded.
126 *
127 * @return void
128 */
129 function wpbc_availability_timeslots_enqueue_js_files( $where_to_load ) {
130
131 if ( ( ! is_admin() ) || ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) ) ) {
132 return;
133 }
134
135 if ( ! wpbc_availability_timeslots__is_component_page() ) {
136 return;
137 }
138
139 wp_enqueue_script(
140 'wpbc-availability-timeslots-page',
141 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/availability_timeslots_page.js',
142 array( 'jquery', 'wpbc_all', 'wpbc-datepick' ),
143 WP_BK_VERSION_NUM,
144 array( 'in_footer' => WPBC_JS_IN_FOOTER )
145 );
146
147 wp_localize_script(
148 'wpbc-availability-timeslots-page',
149 'wpbc_availability_timeslots_page',
150 array(
151 'ajax_url' => admin_url( 'admin-ajax.php' ),
152 'nonce' => wp_create_nonce( 'wpbc_availability_timeslots_ajax_nonce' ),
153 'i18n' => array(
154 'select_slots_first' => __( 'Select one or more time ranges first.', 'booking' ),
155 'block_success' => __( 'Selected time ranges have been blocked.', 'booking' ),
156 'unblock_success' => __( 'Selected time ranges have been unblocked.', 'booking' ),
157 'save_error' => __( 'Unable to save time-slot availability.', 'booking' ),
158 'loading' => __( 'Loading', 'booking' ),
159 'open_booking' => __( 'Open booking in Booking Listing', 'booking' ),
160 'open_availability_rule' => __( 'Open availability settings', 'booking' ),
161 'select_one_slot_for_booking' => __( 'Select one time range on one date first.', 'booking' ),
162 'add_booking_modal_missing' => __( 'Add Booking popup is not available on this page.', 'booking' ),
163 'saving' => __( 'Saving', 'booking' ),
164 ),
165 )
166 );
167 }
168 add_action( 'wpbc_enqueue_js_files', 'wpbc_availability_timeslots_enqueue_js_files', 66 );
169
170 /**
171 * Get resource options for the Time Slots Availability component.
172 *
173 * @return array
174 */
175 function wpbc_availability_timeslots__get_resources() {
176
177 $resources = array();
178
179 if ( function_exists( 'wpbc_ajx_get_sorted_booking_resources_arr' ) && function_exists( 'wpbc_ajx_get_all_booking_resources_arr' ) ) {
180 $resource_rows = wpbc_ajx_get_sorted_booking_resources_arr( wpbc_ajx_get_all_booking_resources_arr() );
181 foreach ( $resource_rows as $resource ) {
182 $resources[] = array(
183 'id' => isset( $resource['booking_type_id'] ) ? (int) $resource['booking_type_id'] : 1,
184 'title' => isset( $resource['title'] ) ? $resource['title'] : __( 'Booking resource', 'booking' ),
185 );
186 }
187 }
188
189 if ( empty( $resources ) ) {
190 $resources[] = array(
191 'id' => wpbc_get_default_resource(),
192 'title' => '---', //__( 'Default Resource', 'booking' ),
193 );
194 }
195
196 return $resources;
197 }
198
199 /**
200 * Get initial timeline rows. Real booked and blocked bars are loaded by AJAX.
201 *
202 * @param int $start_ts Start timestamp.
203 * @param int $days_count Number of days.
204 *
205 * @return array
206 */
207 function wpbc_availability_timeslots__get_initial_rows( $start_ts, $days_count = WPBC_AVAILABILITY_TIMESLOTS_DEFAULT_DAYS_COUNT ) {
208
209 $rows = array();
210 $days_count = max( 1, intval( $days_count ) );
211
212 for ( $i = 0; $i < $days_count; $i++ ) {
213 $ts = strtotime( '+' . $i . ' days', $start_ts );
214 $rows[] = array(
215 'date' => wp_date( 'Y-m-d', $ts ),
216 'label' => wp_date( 'D M j', $ts ),
217 );
218 }
219
220 return $rows;
221 }
222
223 /**
224 * Get selectable time options from 00:00 to 24:00.
225 *
226 * @param int $selected_minutes Selected minute value.
227 *
228 * @return string
229 */
230 function wpbc_availability_timeslots__get_time_options( $selected_minutes ) {
231
232 $html = '';
233 for ( $minutes = 0; $minutes <= 1440; $minutes += 60 ) {
234 $hours = (int) floor( $minutes / 60 );
235 $mins = $minutes % 60;
236 $label = sprintf( '%02d:%02d', $hours, $mins );
237 $html .= sprintf(
238 '<option value="%1$d"%2$s>%3$s</option>',
239 (int) $minutes,
240 selected( $selected_minutes, $minutes, false ),
241 esc_html( $label )
242 );
243 }
244
245 return $html;
246 }
247
248 /**
249 * Print slot step options.
250 *
251 * @param int $selected_step Selected step.
252 *
253 * @return void
254 */
255 function wpbc_availability_timeslots__render_slot_step_options( $selected_step = 15 ) {
256
257 $steps = array(
258 5 => __( '5 min', 'booking' ),
259 10 => __( '10 min', 'booking' ),
260 15 => __( '15 min', 'booking' ),
261 30 => __( '30 min', 'booking' ),
262 60 => __( '1 hour', 'booking' ),
263 );
264
265 foreach ( $steps as $step => $label ) {
266 ?>
267 <option value="<?php echo esc_attr( $step ); ?>" <?php selected( (int) $selected_step, (int) $step ); ?>><?php echo esc_html( $label ); ?></option>
268 <?php
269 }
270 }
271
272 /**
273 * Render zoom control.
274 *
275 * @param string $control_id Control ID.
276 * @param int $selected_step Selected step.
277 * @param string $control_name Control name for JS.
278 *
279 * @return void
280 */
281 function wpbc_availability_timeslots__render_zoom_control( $control_id, $selected_step = 15, $control_name = 'zoom' ) {
282
283 $zoom_steps = array( 60, 30, 15, 10, 5 );
284 $zoom_index = array_search( (int) $selected_step, $zoom_steps, true );
285 if ( false === $zoom_index ) {
286 $zoom_index = 2;
287 }
288 ?>
289 <div class="wpbc_ts_zoom">
290 <a href="javascript:void(0)" class="button button-secondary wpbc_ts_zoom_button" data-wpbc-ts-zoom="out" aria-label="<?php esc_attr_e( 'Zoom out', 'booking' ); ?>">-</a>
291 <input id="<?php echo esc_attr( $control_id ); ?>" data-wpbc-ts-control="<?php echo esc_attr( $control_name ); ?>" type="range" min="0" max="<?php echo esc_attr( count( $zoom_steps ) - 1 ); ?>" value="<?php echo esc_attr( $zoom_index ); ?>" />
292 <a href="javascript:void(0)" class="button button-secondary wpbc_ts_zoom_button" data-wpbc-ts-zoom="in" aria-label="<?php esc_attr_e( 'Zoom in', 'booking' ); ?>">+</a>
293 </div>
294 <?php
295 }
296
297 /**
298 * Render Time Slots Availability action buttons.
299 *
300 * @param string $extra_class Additional wrapper CSS class.
301 * @return void
302 */
303 function wpbc_availability_timeslots__render_action_buttons( $extra_class = '' ) {
304
305 $wrapper_class = trim( 'wpbc_ts_action_buttons ' . $extra_class );
306 ?>
307 <div class="<?php echo esc_attr( $wrapper_class ); ?>">
308 <a href="javascript:void(0)" class="button button-secondary wpbc_ts_button_danger wpbc_ts_action_button" data-wpbc-ts-command="block"><span class="wpbc_icn_do_not_disturb_on"></span> <?php esc_html_e( 'Block selected', 'booking' ); ?></a>
309 <a href="javascript:void(0)" class="button button-secondary wpbc_ts_action_button wpbc_ts_unblock" data-wpbc-ts-command="unblock"><span class="wpbc_icn_blur_off"></span> <?php esc_html_e( 'Unblock selected', 'booking' ); ?></a>
310 <a href="javascript:void(0)" class="button button-secondary wpbc_ts_clear_selection"><?php esc_html_e( 'Clear selection', 'booking' ); ?></a>
311 </div>
312 <?php
313 }
314
315 /**
316 * Render the reusable Time Slots Availability timeline component.
317 *
318 * @param array $args Component arguments.
319 *
320 * @return void
321 */
322 function wpbc_availability_timeslots__render_timeline_component( $args = array() ) {
323
324 $defaults = array(
325 'id_prefix' => 'wpbc_ts',
326 'wrap_class' => 'wrap wpbc_ts_page wpdevelop',
327 'resource_id' => wpbc_get_default_resource(),
328 'resources' => null,
329 'start_ts' => strtotime( wp_date( 'Y-m-d 00:00:00' ) ),
330 'days_count' => WPBC_AVAILABILITY_TIMESLOTS_DEFAULT_DAYS_COUNT,
331 'visible_start_minutes' => 360,
332 'visible_end_minutes' => 1320,
333 'slot_step' => 15,
334 'show_toolbar' => true,
335 'show_toolbar_actions' => true,
336 'show_hint' => true,
337 'show_legend' => true,
338 'auto_init' => true,
339 );
340 $args = wp_parse_args( $args, $defaults );
341
342 $id_prefix = sanitize_key( $args['id_prefix'] );
343 $resource_id = (int) $args['resource_id'];
344 $resources = is_array( $args['resources'] ) ? $args['resources'] : wpbc_availability_timeslots__get_resources();
345 $start_ts = (int) $args['start_ts'];
346 $days_count = max( 1, intval( $args['days_count'] ) );
347 $end_ts = strtotime( '+' . ( $days_count - 1 ) . ' days', $start_ts );
348 $rows = wpbc_availability_timeslots__get_initial_rows( $start_ts, $days_count );
349 $visible_start_minutes = (int) $args['visible_start_minutes'];
350 $visible_end_minutes = (int) $args['visible_end_minutes'];
351 $slot_step = (int) $args['slot_step'];
352
353 $ids = array(
354 'resource' => $id_prefix . '_resource',
355 'date_range' => $id_prefix . '_date_range',
356 'slot_step' => $id_prefix . '_slot_step',
357 'zoom' => $id_prefix . '_zoom',
358 'day_start' => $id_prefix . '_day_start',
359 'day_end' => $id_prefix . '_day_end',
360 'day_start_slider' => $id_prefix . '_day_start_slider',
361 'day_end_slider' => $id_prefix . '_day_end_slider',
362 );
363
364 ?>
365 <div class="<?php echo esc_attr( $args['wrap_class'] ); ?>" data-wpbc-ts-component="1" data-wpbc-ts-auto-init="<?php echo esc_attr( $args['auto_init'] ? '1' : '0' ); ?>" data-wpbc-ts-id-prefix="<?php echo esc_attr( $id_prefix ); ?>">
366 <?php if ( $args['show_toolbar'] ) : ?>
367 <div class="wpbc_ts_toolbar">
368 <div class="wpbc_ts_control wpbc_ts_control_resource">
369 <label for="<?php echo esc_attr( $ids['resource'] ); ?>"><?php esc_html_e( 'Booking resource', 'booking' ); ?></label>
370 <select id="<?php echo esc_attr( $ids['resource'] ); ?>" data-wpbc-ts-control="resource" class="wpbc_ui_control wpbc_ui_select">
371 <?php foreach ( $resources as $resource ) : ?>
372 <option value="<?php echo esc_attr( $resource['id'] ); ?>" <?php selected( (int) $resource['id'], (int) $resource_id ); ?>>
373 <?php echo esc_html( $resource['title'] ); ?>
374 </option>
375 <?php endforeach; ?>
376 </select>
377 </div>
378
379 <div class="wpbc_ts_control wpbc_ts_control_range">
380 <label for="<?php echo esc_attr( $ids['date_range'] ); ?>"><?php esc_html_e( 'Date range', 'booking' ); ?></label>
381 <div class="wpbc_ts_range_nav">
382 <a href="javascript:void(0)"
383 class="button tooltip_top button-secondary wpbc_button_no_background wpbc_ts_range_nav_button"
384 data-wpbc-ts-range-shift="prev"
385 aria-label="<?php esc_attr_e( 'Previous date range', 'booking' ); ?>"
386 data-original-title="<?php esc_attr_e( 'Previous date range', 'booking' ); ?>"><i class="menu_icon icon-1x wpbc_icn_keyboard_arrow_left"></i><span class="in-button-text"></span></a>
387 <div class="wpbc_ts_input_icon">
388 <span class="wpbc-bi-calendar3-range"></span>
389 <input id="<?php echo esc_attr( $ids['date_range'] ); ?>"
390 data-wpbc-ts-control="date_range"
391 class="wpbc_ui_control wpbc_ui_text wpdevbk-filters-section-calendar"
392 type="text"
393 readonly="readonly"
394 data-wpbc-ts-start="<?php echo esc_attr( wp_date( 'Y-m-d', $start_ts ) ); ?>"
395 data-wpbc-ts-end="<?php echo esc_attr( wp_date( 'Y-m-d', $end_ts ) ); ?>"
396 value="<?php echo esc_attr( wp_date( 'M j, Y', $start_ts ) . ' - ' . wp_date( 'M j, Y', $end_ts ) ); ?>" />
397 </div>
398 <a href="javascript:void(0)"
399 class="button tooltip_top button-secondary wpbc_button_no_background wpbc_ts_range_nav_button"
400 data-wpbc-ts-range-shift="next"
401 aria-label="<?php esc_attr_e( 'Next date range', 'booking' ); ?>"
402 data-original-title="<?php esc_attr_e( 'Next date range', 'booking' ); ?>"><i class="menu_icon icon-1x wpbc_icn_keyboard_arrow_right"></i><span class="in-button-text"></span></a>
403 </div>
404 </div>
405
406 <div class="wpbc_ts_control wpbc_ts_control_precision">
407 <label for="<?php echo esc_attr( $ids['slot_step'] ); ?>"><?php esc_html_e( 'Slot step', 'booking' ); ?></label>
408 <select id="<?php echo esc_attr( $ids['slot_step'] ); ?>" data-wpbc-ts-control="slot_step" class="wpbc_ui_control wpbc_ui_select">
409 <?php wpbc_availability_timeslots__render_slot_step_options( $slot_step ); ?>
410 </select>
411 <?php wpbc_availability_timeslots__render_zoom_control( $ids['zoom'], $slot_step ); ?>
412 </div>
413
414 <div class="wpbc_ts_control wpbc_ts_control_time_range">
415 <label><?php esc_html_e( 'Visible time', 'booking' ); ?></label>
416 <div class="wpbc_ts_time_inputs">
417 <select id="<?php echo esc_attr( $ids['day_start'] ); ?>" data-wpbc-ts-control="day_start" class="wpbc_ui_control wpbc_ui_select" aria-label="<?php esc_attr_e( 'Start time', 'booking' ); ?>">
418 <?php echo wpbc_availability_timeslots__get_time_options( $visible_start_minutes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
419 </select>
420 <select id="<?php echo esc_attr( $ids['day_end'] ); ?>" data-wpbc-ts-control="day_end" class="wpbc_ui_control wpbc_ui_select" aria-label="<?php esc_attr_e( 'End time', 'booking' ); ?>">
421 <?php echo wpbc_availability_timeslots__get_time_options( $visible_end_minutes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
422 </select>
423 </div>
424 <div class="wpbc_ts_dual_slider">
425 <input id="<?php echo esc_attr( $ids['day_start_slider'] ); ?>" data-wpbc-ts-control="day_start_slider" type="range" min="0" max="1440" step="60" value="<?php echo esc_attr( $visible_start_minutes ); ?>" aria-label="<?php esc_attr_e( 'Start time', 'booking' ); ?>" />
426 <input id="<?php echo esc_attr( $ids['day_end_slider'] ); ?>" data-wpbc-ts-control="day_end_slider" type="range" min="0" max="1440" step="60" value="<?php echo esc_attr( $visible_end_minutes ); ?>" aria-label="<?php esc_attr_e( 'End time', 'booking' ); ?>" />
427 </div>
428 </div>
429
430 <?php if ( $args['show_toolbar_actions'] ) : ?>
431 <div class="wpbc_ts_toolbar_actions">
432 <?php wpbc_availability_timeslots__render_action_buttons( 'wpbc_ts_action_buttons_inline' ); ?>
433 </div>
434 <?php endif; ?>
435 </div>
436 <?php endif; ?>
437
438 <?php if ( $args['show_hint'] ) : ?>
439 <div class="wpbc_ts_hint">
440 <span class="wpbc_icn_info_outline"></span>
441 <?php esc_html_e( 'Click and drag across the timeline to select slots. Drag selection ends to adjust the time range.', 'booking' ); ?>
442 </div>
443 <?php endif; ?>
444
445 <div class="wpbc_ts_timeline_card">
446 <div class="wpbc_ts_loading_overlay" aria-live="polite" aria-hidden="true">
447 <div class="wpbc_spins_loading_container wpbc_bfb_spins_loading_container">
448 <div class="wpbc_booking_form_spin_loader">
449 <div class="wpbc_spins_loader_wrapper">
450 <div class="wpbc_one_spin_loader_mini2"></div>
451 </div>
452 </div>
453 <span><?php esc_html_e( 'Loading', 'booking' ); ?>...</span>
454 </div>
455 </div>
456 <div class="wpbc_ts_grid"
457 data-wpbc-ts-start="<?php echo esc_attr( $visible_start_minutes ); ?>"
458 data-wpbc-ts-end="<?php echo esc_attr( $visible_end_minutes ); ?>"
459 data-wpbc-ts-step="<?php echo esc_attr( $slot_step ); ?>">
460 <div class="wpbc_ts_header">
461 <div class="wpbc_ts_axis_corner">
462 <div><?php esc_html_e( 'Time', 'booking' ); ?></div>
463 <div><?php esc_html_e( 'Date', 'booking' ); ?></div>
464 </div>
465 <div class="wpbc_ts_time_axis" aria-hidden="true"></div>
466 </div>
467
468 <div class="wpbc_ts_rows">
469 <?php foreach ( $rows as $row_index => $row ) : ?>
470 <div class="wpbc_ts_row" data-wpbc-ts-row="<?php echo esc_attr( $row_index ); ?>" data-wpbc-ts-date="<?php echo esc_attr( $row['date'] ); ?>">
471 <div class="wpbc_ts_row_label">
472 <span class="wpbc_ts_row_label_text"><?php echo esc_html( $row['label'] ); ?></span>
473 <?php // TODO: add later extended row actions menu! ?>
474 <!--a href="javascript:void(0)" class="wpbc_ts_row_menu" aria-label="<?php esc_attr_e( 'Row actions', 'booking' ); ?>">...</a-->
475 </div>
476 <div class="wpbc_ts_lane" tabindex="0">
477 <div class="wpbc_ts_available_rail"></div>
478 <div class="wpbc_ts_selection wpbc_ts_selection_template" hidden="hidden">
479 <span class="wpbc_ts_time_chip wpbc_ts_time_chip_start">00:00</span>
480 <span class="wpbc_ts_time_chip wpbc_ts_time_chip_end">00:00</span>
481 <span class="wpbc_ts_handle wpbc_ts_handle_start"></span>
482 <span class="wpbc_ts_handle wpbc_ts_handle_end"></span>
483 </div>
484 </div>
485 </div>
486 <?php endforeach; ?>
487 </div>
488 </div>
489
490 <?php if ( $args['show_legend'] ) : ?>
491 <div class="wpbc_ts_legend">
492 <span><i class="wpbc_ts_legend_available"></i><?php esc_html_e( 'Available', 'booking' ); ?></span>
493 <span><i class="wpbc_ts_legend_booked"><span class="wpbc_icn_lock"></span></i><?php esc_html_e( 'Booked', 'booking' ); ?></span>
494 <span><i class="wpbc_ts_legend_blocked"><span class="wpbc_icn_do_not_disturb_on"></span></i><?php esc_html_e( 'Blocked', 'booking' ); ?></span>
495 <span><i class="wpbc_ts_legend_unavailable_day"><span class="wpbc_icn_event_busy"></span></i><?php esc_html_e( 'Unavailable day', 'booking' ); ?></span>
496 <span><i class="wpbc_ts_legend_working_time"><span class="wpbc-bi-clock-history"></span></i><?php esc_html_e( 'Outside working time', 'booking' ); ?></span>
497 <span><i class="wpbc_ts_legend_selected"></i><?php esc_html_e( 'Selected pending changes', 'booking' ); ?></span>
498 <span class="wpbc_ts_legend_note"><span class="wpbc_icn_info_outline"></span><?php esc_html_e( 'Booked slots and availability rules cannot be changed here.', 'booking' ); ?></span>
499 </div>
500 <?php endif; ?>
501 </div>
502 </div>
503 <?php
504 }
505
506 /**
507 * Time Slots Availability tab.
508 */
509 class WPBC_Page_TimeSlots_Availability extends WPBC_Page_Structure {
510
511 /**
512 * Menu slug.
513 *
514 * @return string
515 */
516 public function in_page() {
517 return 'wpbc-availability';
518 }
519
520 /**
521 * Register tab.
522 *
523 * @return array
524 */
525 public function tabs() {
526
527 $tabs = array();
528 $tabs['time_slots_availability'] = array(
529 'is_show_top_path' => true,
530 'right_vertical_sidebar__is_show' => true,
531 'right_vertical_sidebar__default_view_mode' => '',
532 'right_vertical_sidebar_compact__is_show' => true,
533 'left_navigation__default_view_mode' => 'compact',
534 'top_path_title' => __( 'Time Slots Availability', 'booking' ),
535 'title' => __( 'Time Slots Availability', 'booking' ), // Title of TAB.
536 // . '<span class="wpbc_new_label" style="margin-left: auto;">' . esc_html__( 'New', 'booking' ) . '</span>',
537 'hint' => __( 'Flexible blocking time-slot ranges.', 'booking' ),
538 'page_title' => __( 'Time Slots Availability', 'booking' ),
539 'link' => '',
540 'position' => '',
541 'css_classes' => '',
542 'icon' => '',
543 'font_icon' => 'wpbc-bi-clock-history',
544 // 'font_icon_right' => 'wpbc-bi-question-circle', //.
545 'font_icon_right' => '',
546 'default' => false,
547 'disabled' => false,
548 'hided' => false,
549 'subtabs' => array(),
550 'folder_style' => 'order:92;',
551 'is_show_top_navigation' => true,
552 );
553
554 return $tabs;
555 }
556
557 /**
558 * Right compact sidebar tabs.
559 *
560 * @return void
561 */
562 public function right_sidebar_compact_content() {
563
564 WPBC_UI_Sidebar_Panels::render_rightbar_tabs(
565 array(
566 array(
567 'id' => 'wpbc_tab_ts_summary',
568 'panel_id' => 'wpbc_ts__inspector_summary',
569 'title' => __( 'Selection', 'booking' ),
570 'icon' => 'wpbc-bi-check2-circle',
571 'selected' => true,
572 ),
573 array(
574 'id' => 'wpbc_tab_ts_settings',
575 'panel_id' => 'wpbc_ts__inspector_settings',
576 'title' => __( 'Settings', 'booking' ),
577 'icon' => 'wpbc_icn_tune',
578 ),
579 ),
580 array(
581 'aria_label' => __( 'Time Slots Availability Panels', 'booking' ),
582 'context' => 'time_slots_availability',
583 'class' => 'wpbc_ts_rightbar_tabs',
584 )
585 );
586 }
587
588 /**
589 * Right sidebar panels.
590 *
591 * @return void
592 */
593 public function right_sidebar_content() {
594 ?>
595 <div class="wpbc_bfb__panel--library wpbc_rightbar_palette wpbc_ts_rightbar_panels">
596 <?php
597 WPBC_UI_Sidebar_Panels::render_panel(
598 array(
599 'id' => 'wpbc_ts__inspector_summary',
600 'labelledby' => 'wpbc_tab_ts_summary',
601 'class' => 'wpbc_ts__inspector_summary',
602 ),
603 array( $this, 'right_panel_summary_content' )
604 );
605
606 WPBC_UI_Sidebar_Panels::render_panel(
607 array(
608 'id' => 'wpbc_ts__inspector_settings',
609 'labelledby' => 'wpbc_tab_ts_settings',
610 'class' => 'wpbc_ts__inspector_settings',
611 'hidden' => true,
612 ),
613 array( $this, 'right_panel_settings_content' )
614 );
615 ?>
616 </div>
617 <?php
618 }
619
620 /**
621 * Summary panel content.
622 *
623 * @return void
624 */
625 public function right_panel_summary_content() {
626
627 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Selection', 'booking' ), __( 'Review selected time slots, then block or unblock them.', 'booking' ) );
628 ?>
629 <div class="wpbc_bfb__inspector__body wpbc_ts_inspector_body">
630 <?php
631 WPBC_UI_Sidebar_Panels::render_collapsible_group(
632 array(
633 'id' => 'wpbc_ts_action_group',
634 'group' => 'time-slots-actions',
635 'title' => __( 'Selected Time Slots', 'booking' ),
636 'open' => true,
637 ),
638 function () {
639 ?>
640 <?php wpbc_availability_timeslots__render_action_buttons(); ?>
641 <div class="wpbc_ts_inspector_row row__bordered">
642 <div class="wpbc_ts_inspector_label"><?php esc_html_e( 'Slots selected', 'booking' ); ?></div>
643 <div class="wpbc_ts_inspector_value"><strong data-wpbc-ts-detail="slots">0</strong></div>
644 <div class="wpbc_ts_inspector_row">
645 <div class="wpbc_ts_inspector_label"><?php esc_html_e( 'Dates', 'booking' ); ?></div>
646 <div class="wpbc_ts_inspector_value" data-wpbc-ts-detail="dates">-</div>
647 </div>
648 <div class="wpbc_ts_inspector_row">
649 <div class="wpbc_ts_inspector_label"><?php esc_html_e( 'Time', 'booking' ); ?></div>
650 <div class="wpbc_ts_inspector_value" data-wpbc-ts-detail="time">-</div>
651 </div>
652 </div>
653 <div class="wpbc_ts_selection_details" data-wpbc-ts-detail="selection_list">
654 <div class="wpbc_ts_selection_details_empty"><?php esc_html_e( 'No time slots selected.', 'booking' ); ?></div>
655 </div>
656 <?php
657 }
658 );
659 ?>
660 </div>
661 <?php
662 }
663
664 /**
665 * Settings panel content.
666 *
667 * @return void
668 */
669 public function right_panel_settings_content() {
670 $visible_start_minutes = 360;
671 $visible_end_minutes = 1320;
672
673 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Timeline Settings', 'booking' ), __( 'Control the visible time window and selection precision.', 'booking' ) );
674 ?>
675 <div class="wpbc_bfb__inspector__body wpbc_ts_inspector_body">
676 <?php
677 WPBC_UI_Sidebar_Panels::render_collapsible_group(
678 array(
679 'id' => 'wpbc_ts_date_range_group',
680 'group' => 'time-slots-date-range',
681 'title' => __( 'Date Range', 'booking' ),
682 'open' => true,
683 ),
684 function () {
685 ?>
686 <div class="wpbc_ts_inspector_row">
687 <div class="wpbc_ts_inspector_label"><?php esc_html_e( 'Scroll range', 'booking' ); ?></div>
688 <div class="wpbc_ts_inspector_value">
689 <div class="wpbc_ts_range_nav wpbc_ts_range_nav_sidebar">
690 <a href="javascript:void(0)"
691 class="button tooltip_top button-secondary wpbc_button_no_background wpbc_ts_range_nav_button"
692 data-wpbc-ts-range-shift="prev"
693 aria-label="<?php esc_attr_e( 'Previous date range', 'booking' ); ?>"
694 data-original-title="<?php esc_attr_e( 'Previous date range', 'booking' ); ?>"><i class="menu_icon icon-1x wpbc_icn_keyboard_arrow_left"></i><span class="in-button-text"></span></a>
695 <a href="javascript:void(0)"
696 class="button tooltip_top button-secondary wpbc_button_no_background wpbc_ts_range_nav_button"
697 data-wpbc-ts-range-shift="next"
698 aria-label="<?php esc_attr_e( 'Next date range', 'booking' ); ?>"
699 data-original-title="<?php esc_attr_e( 'Next date range', 'booking' ); ?>"><i class="menu_icon icon-1x wpbc_icn_keyboard_arrow_right"></i><span class="in-button-text"></span></a>
700 </div>
701 </div>
702 </div>
703 <?php
704 }
705 );
706
707 WPBC_UI_Sidebar_Panels::render_collapsible_group(
708 array(
709 'id' => 'wpbc_ts_slot_precision_group',
710 'group' => 'time-slots-precision',
711 'title' => __( 'Time Step & Zoom', 'booking' ),
712 'open' => true,
713 ),
714 function () {
715 ?>
716 <div class="wpbc_ts_inspector_row">
717 <label class="wpbc_ts_inspector_label" for="wpbc_ts_side_slot_step"><?php esc_html_e( 'Slot step', 'booking' ); ?></label>
718 <div class="wpbc_ts_inspector_value">
719 <select id="wpbc_ts_side_slot_step" class="wpbc_ts_inspector_select">
720 <?php wpbc_availability_timeslots__render_slot_step_options( 15 ); ?>
721 </select>
722 </div>
723 </div>
724 <div class="wpbc_ts_inspector_row">
725 <div class="wpbc_ts_inspector_label"><?php esc_html_e( 'Zoom', 'booking' ); ?></div>
726 <div class="wpbc_ts_inspector_value">
727 <?php wpbc_availability_timeslots__render_zoom_control( 'wpbc_ts_side_zoom', 15, 'side_zoom' ); ?>
728 </div>
729 </div>
730 <?php
731 }
732 );
733
734 WPBC_UI_Sidebar_Panels::render_collapsible_group(
735 array(
736 'id' => 'wpbc_ts_time_window_group',
737 'group' => 'time-slots-visible-window',
738 'title' => __( 'Visible Time Range', 'booking' ),
739 'open' => true,
740 ),
741 function () use ( $visible_start_minutes, $visible_end_minutes ) {
742 ?>
743 <div class="wpbc_ts_inspector_row">
744 <label class="wpbc_ts_inspector_label" for="wpbc_ts_side_start"><?php esc_html_e( 'Start time', 'booking' ); ?></label>
745 <div class="wpbc_ts_inspector_value">
746 <select id="wpbc_ts_side_start" class="wpbc_ts_inspector_select">
747 <?php echo wpbc_availability_timeslots__get_time_options( $visible_start_minutes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
748 </select>
749 </div>
750 </div>
751 <div class="wpbc_ts_inspector_row">
752 <label class="wpbc_ts_inspector_label" for="wpbc_ts_side_end"><?php esc_html_e( 'End time', 'booking' ); ?></label>
753 <div class="wpbc_ts_inspector_value">
754 <select id="wpbc_ts_side_end" class="wpbc_ts_inspector_select">
755 <?php echo wpbc_availability_timeslots__get_time_options( $visible_end_minutes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
756 </select>
757 </div>
758 </div>
759 <div class="wpbc_ts_inspector_row">
760 <div class="wpbc_ts_inspector_label"><?php esc_html_e( 'Visible range', 'booking' ); ?></div>
761 <div class="wpbc_ts_inspector_value">
762 <div class="wpbc_ts_dual_slider">
763 <input id="wpbc_ts_side_start_slider" type="range" min="0" max="1440" step="60" value="<?php echo esc_attr( $visible_start_minutes ); ?>" aria-label="<?php esc_attr_e( 'Start time', 'booking' ); ?>" />
764 <input id="wpbc_ts_side_end_slider" type="range" min="0" max="1440" step="60" value="<?php echo esc_attr( $visible_end_minutes ); ?>" aria-label="<?php esc_attr_e( 'End time', 'booking' ); ?>" />
765 </div>
766 </div>
767 </div>
768 <?php
769 }
770 );
771 // TODO: add later Advanced Options.
772 if ( 0 )
773 WPBC_UI_Sidebar_Panels::render_collapsible_group(
774 array(
775 'id' => 'wpbc_ts_future_group',
776 'group' => 'time-slots-future-settings',
777 'title' => __( 'Advanced Options', 'booking' ),
778 ),
779 function () {
780 ?>
781 <div class="wpbc_ts_inspector_row row__bordered">
782 <div class="wpbc_ts_inspector_label"><?php esc_html_e( 'Extension area', 'booking' ); ?></div>
783 <div class="wpbc_ts_inspector_value"><?php esc_html_e( 'Rules, copy tools, templates, and resource constraints can be added here later.', 'booking' ); ?></div>
784 </div>
785 <?php
786 }
787 );
788 ?>
789 </div>
790 <?php
791 }
792
793 /**
794 * Show page content.
795 *
796 * @return void|false
797 */
798 public function content() {
799
800 do_action( 'wpbc_hook_settings_page_header', 'page_booking_availability_timeslots' );
801
802 if ( ! wpbc_is_mu_user_can_be_here( 'activated_user' ) ) {
803 return false;
804 }
805
806 wpbc_availability_timeslots__render_timeline_component();
807
808 do_action( 'wpbc_hook_settings_page_footer', 'page_booking_availability_timeslots' );
809 }
810 }
811 add_action( 'wpbc_menu_created', array( new WPBC_Page_TimeSlots_Availability(), '__construct' ) );
812