PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.5.0
2.5.0 2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 All 34 releases
fluent-booking / app / Hooks / Handlers / AdminMenuHandler.php

AdminMenuHandler.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 2.5.0, at app/Hooks/Handlers/AdminMenuHandler.php

981 lines 50.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\App\Hooks\Handlers;
4
5 use FluentBooking\App\App;
6 use FluentBooking\App\Vite;
7 use FluentBooking\App\Models\Booking;
8 use FluentBooking\App\Models\Calendar;
9 use FluentBooking\App\Services\DateTimeHelper;
10 use FluentBooking\App\Services\Helper;
11 use FluentBooking\App\Services\PermissionManager;
12 use FluentBooking\App\Services\TransStrings;
13 use FluentBooking\Framework\Support\Arr;
14
15 class AdminMenuHandler
16 {
17 public function register()
18 {
19 add_action('admin_menu', [$this, 'add']);
20
21 add_action('admin_enqueue_scripts', function ($hookSuffix) {
22 if ($hookSuffix !== 'toplevel_page_fluent-booking') {
23 return;
24 }
25
26 $this->enqueueAssets();
27
28 add_action('admin_head', function () {
29 $this->printThemeClass();
30 }, 1);
31
32 }, 100);
33 }
34
35 /**
36 * Put the dark class on the document before the page paints.
37 *
38 * The theme is chosen in the browser, so the server cannot know it - which means
39 * without this the first frame is always light, and somebody on dark gets a white flash
40 * on every page load. This runs in <head>, before wp-admin's own markup, and is the
41 * only reason it is inline rather than in global_admin.js: a file in the footer is too
42 * late to matter, and one in the header is still a request the paint would wait on.
43 *
44 * `fluent_theme_mode` is the key every Fluent plugin shares (see global_admin.js), and it
45 * holds a bare `light`, `dark` or `system`, so `system` is resolved here against the
46 * machine's own preference. <body> does not exist yet, so only <html> is marked;
47 * global_admin.js puts the same classes on <body> and #wpbody-content once it runs.
48 *
49 * @return void
50 */
51 public function printThemeClass()
52 {
53 $script = <<<'JS'
54 (function(){try{var s=localStorage.getItem('fluent_theme_mode')||'';
55 if(!s){s=localStorage.getItem('fcal_color_mode')==='dark'?'dark':'light';}
56 if(s==='system'){s='system:'+(window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light');}
57 if(s==='dark'||s==='system:dark'){var e=document.documentElement;e.classList.add('fluent_theme_dark');e.classList.add('dark');}}catch(e){}})();
58 JS;
59
60 echo '<script id="fluent-booking-theme-class">' . $script . '</script>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
61 }
62
63 public function add()
64 {
65 $capability = PermissionManager::getMenuPermission();
66 $menuPriority = 26;
67
68 if (defined('FLUENTCRM')) {
69 $menuPriority = 4;
70 }
71
72 add_menu_page(
73 __('Fluent Booking', 'fluent-booking'),
74 __('Fluent Booking', 'fluent-booking'),
75 $capability,
76 'fluent-booking',
77 [$this, 'render'],
78 $this->getMenuIcon(),
79 $menuPriority
80 );
81
82 add_submenu_page(
83 'fluent-booking',
84 __('Dashboard', 'fluent-booking'),
85 __('Dashboard', 'fluent-booking'),
86 $capability,
87 'fluent-booking',
88 [$this, 'render']
89 );
90
91 add_submenu_page(
92 'fluent-booking',
93 __('Calendars', 'fluent-booking'),
94 __('Calendars', 'fluent-booking'),
95 $capability,
96 'fluent-booking#/calendars',
97 [$this, 'render']
98 );
99
100 add_submenu_page(
101 'fluent-booking',
102 __('Bookings', 'fluent-booking'),
103 __('Bookings', 'fluent-booking'),
104 $capability,
105 'fluent-booking#/scheduled-events',
106 [$this, 'render']
107 );
108
109 add_submenu_page(
110 'fluent-booking',
111 __('Availability', 'fluent-booking'),
112 __('Availability', 'fluent-booking'),
113 $capability,
114 'fluent-booking#/availability',
115 [$this, 'render']
116 );
117
118 add_submenu_page(
119 'fluent-booking',
120 __('Settings', 'fluent-booking'),
121 __('Settings', 'fluent-booking'),
122 $capability,
123 'fluent-booking#/settings/general-settings',
124 [$this, 'render']
125 );
126
127 if ($this->shouldShowUpgrade()) {
128 add_submenu_page(
129 'fluent-booking',
130 __('Upgrade to Pro', 'fluent-booking'),
131 '<span class="fcal_upgrade_pro_menu">' . esc_html__('Upgrade to Pro', 'fluent-booking') . '</span>',
132 'manage_options',
133 Helper::getUpgradeUrl('admin_sidebar_menu')
134 );
135
136 add_action('admin_head', [$this, 'printUpgradeMenuStyle']);
137 add_action('admin_footer', [$this, 'printUpgradeMenuScript']);
138 }
139 }
140
141 /**
142 * The upsell is for whoever can buy the license, so it stays hidden once Pro is loaded
143 * and from hosts who only reach the app through their own calendars.
144 *
145 * @return bool
146 */
147 public function shouldShowUpgrade()
148 {
149 return !defined('FLUENT_BOOKING_PRO_DIR_FILE') && current_user_can('manage_options');
150 }
151
152 /**
153 * Onboarding asks on its final step. The dashboard card waits until the site has a completed
154 * booking, when FluentBooking has proven useful, and counts one the way the Bookings page's
155 * "Completed" tab does.
156 *
157 * @return array
158 */
159 private function getOptinVars()
160 {
161 $showPrompt = $this->showOptinPrompt();
162
163 return [
164 'share_stats' => Arr::get((array) Helper::getMeta('option', 0, 'optin'), 'share_stats', ''),
165 'can_manage' => PermissionManager::userCan('manage_all_data'),
166 'show_prompt' => $showPrompt,
167 'show_card' => $showPrompt && Booking::applyComputedStatus('completed')->exists(),
168 ];
169 }
170
171 /**
172 * The email opt-in prompt (dashboard card and onboarding) is for free sites that have not
173 * subscribed yet. Closing it hides it for 30 days.
174 *
175 * @return bool
176 */
177 private function showOptinPrompt()
178 {
179 if (defined('FLUENT_BOOKING_PRO_DIR_FILE') || !PermissionManager::userCan('manage_all_data')) {
180 return false;
181 }
182
183 $optin = (array) Helper::getMeta('option', 0, 'optin');
184
185 if (!empty($optin['email'])) {
186 return false;
187 }
188
189 return empty($optin['dismissed_at']) || (time() - (int) $optin['dismissed_at']) > 30 * DAY_IN_SECONDS;
190 }
191
192 public function printUpgradeMenuStyle()
193 {
194 echo '<style id="fluent-booking-upgrade-menu">#adminmenu .fcal_upgrade_pro_menu{color:#72aee6;font-weight:500;}</style>';
195 }
196
197 /**
198 * The submenu points off-site, and WordPress gives submenu links no target, so it would
199 * otherwise take the admin away from the dashboard.
200 *
201 * @return void
202 */
203 public function printUpgradeMenuScript()
204 {
205 echo '<script id="fluent-booking-upgrade-menu-js">(function(){var s=document.querySelector("#adminmenu .fcal_upgrade_pro_menu");if(s&&s.parentNode){s.parentNode.setAttribute("target","_blank");s.parentNode.setAttribute("rel","noopener");}})();</script>';
206 }
207
208 public function render()
209 {
210 if (!as_has_scheduled_action('fluent_booking_five_minutes_tasks')) {
211 as_schedule_recurring_action(time(), (60 * 5), 'fluent_booking_five_minutes_tasks', [], 'fluent-booking', true);
212 }
213
214 // The daily task carries the summary report and the MCP record purge.
215 // A site that never got it — a secondary blog on a network activation,
216 // or one that lost it — would grow fcal_mcp_g_* rows forever.
217 if (!as_has_scheduled_action('fluent_booking/daily_tasks')) {
218 as_schedule_recurring_action(time(), (60 * 60 * 24), 'fluent_booking/daily_tasks', [], 'fluent-booking', true);
219 }
220
221 $this->changeFooter();
222
223 $app = App::getInstance();
224
225 $config = $app->config;
226
227 $name = $config->get('app.name');
228
229 $slug = $config->get('app.slug');
230
231 $baseUrl = Helper::getAppBaseUrl();
232
233 if (is_admin()) {
234 $baseUrl = admin_url('admin.php?page=fluent-booking#/');
235 }
236
237 $isNew = $this->isNew();
238
239 $menuItems = [
240 [
241 'key' => 'dashboard',
242 'label' => $isNew ? __('Getting Started', 'fluent-booking') : __('Dashboard', 'fluent-booking'),
243 'permalink' => $baseUrl
244 ],
245 [
246 'key' => 'calendars',
247 'label' => __('Calendars', 'fluent-booking'),
248 'permalink' => $baseUrl . 'calendars'
249 ],
250 [
251 'key' => 'scheduled-events',
252 'label' => __('Bookings', 'fluent-booking'),
253 'permalink' => $baseUrl . 'scheduled-events',
254 ],
255 [
256 'key' => 'availability',
257 'label' => __('Availability', 'fluent-booking'),
258 'permalink' => $baseUrl . 'availability'
259 ]
260 ];
261
262 $settingItems = [];
263 if (PermissionManager::userCan('manage_all_data')) {
264 $settingItems = [
265 'key' => 'settings',
266 'label' => __('Settings', 'fluent-booking'),
267 'permalink' => $baseUrl . 'settings/general-settings'
268 ];
269 }
270
271 $menuItems = apply_filters('fluent_booking/admin_menu_items', $menuItems);
272
273 $assets = $app['url.assets'];
274
275 $portalVars = apply_filters('fluent_booking/admin_portal_vars', [
276 'name' => $name,
277 'slug' => $slug,
278 'menuItems' => $menuItems,
279 'settings' => $settingItems,
280 'baseUrl' => $baseUrl,
281 'logo' => $assets . 'images/logo.svg',
282 'dark_logo' => $assets . 'images/logo_dark.svg',
283 'upgradeUrl' => $this->shouldShowUpgrade() ? Helper::getUpgradeUrl('top_bar') : '',
284 ]);
285
286 do_action('fluent_booking/admin_app_rendering');
287
288 $app->view->render('admin.menu', $portalVars);
289 }
290
291 public function changeFooter()
292 {
293 add_filter('admin_footer_text', function ($content) {
294 $url = 'https://fluentbooking.com/';
295 /* translators: %s: URL of the FluentBooking website */
296 return sprintf(wp_kses(__('Thank you for using <a href="%s">FluentBooking</a>.', 'fluent-booking'), array('a' => array('href' => array()))), esc_url($url)) . '<span title="based on your WP timezone settings" style="margin-left: 10px;" data-timestamp="' . current_time('timestamp') . '" id="fcal_server_timestamp"></span>';
297 });
298
299 add_filter('update_footer', function ($text) {
300 return FLUENT_BOOKING_VERSION;
301 });
302 }
303
304 public function enqueueAssets($withApp = true)
305 {
306 $app = App::getInstance();
307
308 $isRtl = Helper::fluentbooking_is_rtl();
309
310 $slug = $app->config->get('app.slug');
311
312 $assetsVersion = Vite::isDev() ? time() : FLUENT_BOOKING_ASSETS_VERSION;
313
314 if ($isRtl) {
315 Vite::enqueueStyle('fluentbooking_admin_rtl', 'admin_rtl_css', [], $assetsVersion);
316 }
317
318 add_action('wp_print_scripts', function () {
319
320 $isSkip = apply_filters('fluent_booking/skip_no_conflict', false, 'scripts');
321
322 if ($isSkip) {
323 return;
324 }
325
326 global $wp_scripts;
327 if (!$wp_scripts) {
328 return;
329 }
330
331 $approvedSlugs = apply_filters('fluent_booking/asset_listed_slugs', [
332 '\/fluent-crm\/'
333 ]);
334
335 $approvedSlugs[] = '\/fluent-booking\/';
336 $approvedSlugs[] = '\/fluent-booking-pro\/';
337
338 $approvedSlugs = array_unique($approvedSlugs);
339
340 $approvedSlugs = implode('|', $approvedSlugs);
341
342 $pluginUrl = plugins_url();
343
344 $pluginUrl = str_replace(['http:', 'https:'], '', $pluginUrl);
345
346 foreach ($wp_scripts->queue as $script) {
347 if (empty($wp_scripts->registered[$script]) || empty($wp_scripts->registered[$script]->src)) {
348 continue;
349 }
350
351 $src = $wp_scripts->registered[$script]->src;
352 $isMatched = (strpos($src, $pluginUrl) !== false) && !preg_match('/' . $approvedSlugs . '/', $src);
353 if (!$isMatched) {
354 continue;
355 }
356 wp_dequeue_script($wp_scripts->registered[$script]->handle);
357 }
358 });
359
360 add_action('wp_print_styles', function () {
361 $isSkip = apply_filters('fluent_booking/skip_no_conflict', false, 'styles');
362
363 if ($isSkip) {
364 return;
365 }
366
367 global $wp_styles;
368 if (!$wp_styles) {
369 return;
370 }
371
372 $approvedSlugs = apply_filters('fluent_booking/asset_listed_slugs', [
373 '\/fluent-crm\/'
374 ]);
375
376 $approvedSlugs[] = '\/fluent-booking\/';
377 $approvedSlugs[] = '\/fluent-booking-pro\/';
378
379 $approvedSlugs = array_unique($approvedSlugs);
380
381 $approvedSlugs = implode('|', $approvedSlugs);
382
383 $pluginUrl = plugins_url();
384
385 $themeUrl = get_theme_root_uri();
386
387 $pluginUrl = str_replace(['http:', 'https:'], '', $pluginUrl);
388 $themeUrl = str_replace(['http:', 'https:'], '', $themeUrl);
389
390 foreach ($wp_styles->queue as $script) {
391
392 if (empty($wp_styles->registered[$script]) || empty($wp_styles->registered[$script]->src)) {
393 continue;
394 }
395
396 $src = $wp_styles->registered[$script]->src;
397 $pluginMatched = (strpos($src, $pluginUrl) !== false) && !preg_match('/' . $approvedSlugs . '/', $src);
398 $themeMatched = (strpos($src, $themeUrl) !== false) && !preg_match('/' . $approvedSlugs . '/', $src);
399
400 if (!$pluginMatched && !$themeMatched) {
401 continue;
402 }
403
404 wp_dequeue_style($wp_styles->registered[$script]->handle);
405 }
406 }, 999999);
407
408 Vite::enqueueStyle('fluent_booing_admin_app', 'admin_css', [], $assetsVersion, 'all');
409
410 // The dashboard payload is per-user and includes every host's email address,
411 // so the app bundle is only ever emitted for an authenticated, permitted viewer.
412 if (!$withApp || !get_current_user_id()) {
413 return;
414 }
415
416 do_action($slug . '_loading_app'); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
417
418 Vite::enqueueScript($slug . '_admin_app', 'admin_app', array('jquery'), $assetsVersion);
419
420 Vite::enqueueScript($slug . '_global_admin', 'global_admin', array(), $assetsVersion);
421
422 if (function_exists('wp_enqueue_editor')) {
423 add_filter('user_can_richedit', '__return_true');
424 wp_enqueue_editor();
425 wp_enqueue_media();
426 }
427
428 wp_localize_script($slug . '_admin_app', 'fluentFrameworkAdmin', $this->getDashboardVars($app));
429 }
430
431 public function getDashboardVars($app)
432 {
433 $assets = $app['url.assets'];
434 $currentUser = get_user_by('ID', get_current_user_id());
435
436 $currentUsername = trim($currentUser->first_name . ' ' . $currentUser->last_name);
437 if (!$currentUsername) {
438 $currentUsername = $currentUser->display_name;
439 }
440
441 $isNew = $this->isNew();
442
443 $requireSlug = false;
444
445 if ($isNew) {
446 $result = $this->maybeAutoCreateCalendar($currentUser);
447 if (!$result) {
448 $requireSlug = true;
449 }
450 }
451
452 $calendarId = null;
453
454 $firstCalendar = Calendar::where('user_id', $currentUser->ID)->where('type', 'simple')->first();
455
456 if ($firstCalendar) {
457 $calendarId = $firstCalendar->id;
458 }
459
460 $hasAllAccess = false;
461 if (PermissionManager::hasAllCalendarAccess()) {
462 $hasAllAccess = true;
463 }
464
465 $eventColors = Helper::getEventColors();
466 $meetingDurations = Helper::getMeetingDurations();
467 $multiDurations = Helper::getMeetingMultiDurations();
468 $durationLookup = Helper::getDurationLookup();
469 $multiDurationLookup = Helper::getDurationLookup(true);
470 $scheduleSchema = Helper::getWeeklyScheduleSchema();
471 $bufferTimes = Helper::getBufferTimes();
472 $slotIntervals = Helper::getSlotIntervals();
473 $customFieldTypes = Helper::getCustomFieldTypes();
474 $weekSelectTimes = Helper::getWeekSelectTimes();
475 $overrideSelectTimes = Helper::getOverrideSelectTimes();
476 $statusChangingTimes = Helper::getBookingStatusChangingTimes();
477 $defaultTermsAndConditions = Helper::getDefaultTermsAndConditions();
478
479 return apply_filters('fluent_booking/admin_vars', [
480 'slug' => $slug = $app->config->get('app.slug'),
481 'nonce' => wp_create_nonce($slug),
482 'rest' => $this->getRestInfo($app),
483 'brand_logo' => $this->getMenuIcon(),
484 'asset_url' => $assets,
485 'event_colors' => $eventColors,
486 'meeting_durations' => $meetingDurations,
487 'multi_durations' => $multiDurations,
488 'buffer_times' => $bufferTimes,
489 'slot_intervals' => $slotIntervals,
490 'schedule_schema' => $scheduleSchema,
491 'custom_field_types' => $customFieldTypes,
492 'week_select_times' => $weekSelectTimes,
493 'duration_lookup' => $durationLookup,
494 'multi_duration_lookup' => $multiDurationLookup,
495 'override_select_times' => $overrideSelectTimes,
496 'status_changing_times' => $statusChangingTimes,
497 'default_terms' => $defaultTermsAndConditions,
498 'me' => [
499 'id' => $currentUser->ID,
500 'calendar_id' => $calendarId,
501 'full_name' => $currentUsername,
502 'avatar' => get_avatar_url($currentUser->ID, ['size' => 96]),
503 'email' => $currentUser->user_email,
504 'is_admin' => $hasAllAccess,
505 'permissions' => PermissionManager::getUserPermissions($currentUser, false),
506 ],
507 'all_hosts' => Calendar::getAllHosts(),
508 'is_new' => $isNew,
509 'require_slug' => $requireSlug,
510 'site_url' => site_url('/'),
511 'site_title' => get_bloginfo('name'),
512 'upgrade_url' => Helper::getUpgradeUrl(),
513 'timezones' => DateTimeHelper::getTimeZones(true),
514 'features' => Helper::getFeatures(),
515 'supported_features' => apply_filters('fluent_booking/supported_featured', [
516 'multi_users' => true
517 ]),
518 'i18' => [
519 'date_time_config' => DateTimeHelper::getI18nDateTimeConfig(),
520 ],
521 'has_pro' => defined('FLUENT_BOOKING_PRO_DIR_FILE'),
522 'require_upgrade' => defined('FLUENT_BOOKING_PRO_DIR_FILE') && !defined('FLUENT_BOOKING_LITE'),
523 'dashboard_notices' => apply_filters('fluent_booking/dashboard_notices', []),
524 'optin' => $this->getOptinVars(),
525 'payment_methods' => apply_filters('fluent_booking/payment/get_all_methods', []),
526 'trans' => TransStrings::getStrings(),
527 'date_format' => DateTimeHelper::getDateFormatter(true),
528 'time_format' => DateTimeHelper::getTimeFormatter(true),
529 'date_time_formatter' => DateTimeHelper::getDateFormatter(true) . ', ' . DateTimeHelper::getTimeFormatter(true),
530 'available_date_formats' => DateTimeHelper::getAvailableDateFormats(),
531 'default_booking_filters' => Helper::getDefaultBookingFilters(),
532 'default_paginations' => Helper::getDefaultPaginations(),
533 'pref_settings' => Helper::getPrefSettings(),
534 'settings_menu_items' => static::settingsMenuItems(),
535 'admin_url' => admin_url(),
536 'is_rtl' => Helper::fluentbooking_is_rtl(),
537 'iframe_html' => Helper::getIframeHtml()
538 ]);
539 }
540
541 protected function getRestInfo($app)
542 {
543 $ns = $app->config->get('app.rest_namespace');
544 $ver = $app->config->get('app.rest_version');
545
546 return [
547 'base_url' => esc_url_raw(rest_url()),
548 'url' => rest_url($ns . '/' . $ver),
549 'nonce' => wp_create_nonce('wp_rest'),
550 'namespace' => $ns,
551 'version' => $ver
552 ];
553 }
554
555 protected function getMenuIcon()
556 {
557 return 'data:image/svg+xml;base64,' . base64_encode('<svg width="96" height="101" viewBox="0 0 96 101" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="25.5746" width="6.39365" height="15.9841" rx="3.19683" fill="white"/><rect x="63.9365" width="6.39365" height="15.9841" rx="3.19683" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M54.878 53.0655C54.544 55.6678 53.4646 58.035 51.8535 59.9427C50.1623 61.9572 47.886 63.4614 45.2863 64.1988L45.1741 64.2309L44.9203 64.2976L44.8989 64.303L24.7671 69.7V65.019C24.7671 64.9148 24.7671 64.8106 24.7778 64.7064C24.8953 62.748 26.127 61.0862 27.8476 60.3514C28.0427 60.2659 28.2431 60.1938 28.4515 60.1377L28.6412 60.0869L54.8753 53.0575V53.0655H54.878Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M71.1411 35.8059C70.4571 41.1467 66.6178 45.5017 61.5494 46.9391L61.4372 46.9712L61.1861 47.038H61.1834L61.162 47.0433L24.7671 56.7953V52.1144C24.7671 50.0197 26.0362 48.2216 27.8476 47.4468L28.4515 47.233L28.6385 47.1823L71.1384 35.7952V35.8059H71.1411Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M19.9802 11.1889H75.9246C83.4282 11.1889 89.5111 17.2718 89.5111 24.7754V70H95.9048V24.7754C95.9048 13.7406 86.9593 4.79523 75.9246 4.79523H19.9802C8.94542 4.79523 0 13.7406 0 24.7754V80.7198C0 91.7546 8.94542 100.7 19.9802 100.7L64.9524 100.7V94.3063H19.9802C12.4765 94.3063 6.39365 88.2234 6.39365 80.7198V24.7754C6.39365 17.2718 12.4765 11.1889 19.9802 11.1889Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M95.9524 70.7477V69.7H64.9524V100.7H66.0001L95.9524 70.7477Z" fill="white"/></svg>');
558 }
559
560 protected function isNew()
561 {
562 return apply_filters('fluent_booking/is_new', !Calendar::first());
563 }
564
565 /**
566 * @param $user \WP_User
567 * @return bool | Calendar
568 */
569 protected function maybeAutoCreateCalendar($user)
570 {
571 if (!apply_filters('fluent_booking/auto_create_calendar', false, $user)) {
572 return false;
573 }
574
575 $userName = $user->user_login;
576
577 if (is_email($userName)) {
578 $userName = explode('@', $userName);
579 $userName = $userName[0];
580 }
581
582 if (!Helper::isCalendarSlugAvailable($userName, true)) {
583 return false;
584 }
585
586 $personName = trim($user->first_name . ' ' . $user->last_name);
587
588 if (!$personName) {
589 $personName = $user->display_name;
590 }
591
592 $data = [
593 'user_id' => $user->ID,
594 'title' => $personName,
595 'slug' => $userName
596 ];
597
598 return Calendar::create($data);
599 }
600
601 public static function settingsMenuItems()
602 {
603 $app = App::getInstance();
604 $urlAssets = $app['url.assets'];
605
606 return apply_filters('fluent_booking/settings_menu_items', [
607 'general_settings' => [
608 'title' => __('General', 'fluent-booking'),
609 'disable' => false,
610 'el_icon' => 'Operation',
611 'component_type' => 'StandAloneComponent',
612 'class' => 'general_settings',
613 'route' => [
614 'name' => 'general_settings'
615 ]
616 ],
617 'team_members' => [
618 'title' => __('Team', 'fluent-booking'),
619 'disable' => true,
620 'el_icon' => 'TeamIcon',
621 'component_type' => 'StandAloneComponent',
622 'class' => 'team_members',
623 'route' => [
624 'name' => 'team_members'
625 ]
626 ],
627 'payment_settings' => [
628 'title' => __('Payment', 'fluent-booking'),
629 'disable' => true,
630 'el_icon' => 'Money',
631 'component_type' => 'PaymentSettingsComponent',
632 'class' => 'payment_settings',
633 'route' => [
634 'name' => 'global_payment_settings',
635 ],
636 'children' => [
637 'payment_settings' => [
638 'title' => __('Settings', 'fluent-booking'),
639 'disable' => true,
640 'route' => [
641 'name' => 'global_payment_settings'
642 ]
643 ],
644 'payment_methods' => [
645 'title' => __('Payment Methods', 'fluent-booking'),
646 'disable' => true,
647 'route' => [
648 'name' => 'payment_methods',
649 'params' => [
650 'settings_key' => 'stripe'
651 ]
652 ]
653 ],
654 'payment_coupons' => [
655 'title' => __('Coupons', 'fluent-booking'),
656 'disable' => true,
657 'route' => [
658 'name' => 'payment_coupons'
659 ]
660 ]
661 ],
662 ],
663 'google' => [
664 'title' => __('Google Calendar / Meet', 'fluent-booking'),
665 'disable' => true,
666 'icon_url' => $urlAssets . 'images/gg-calendar.svg',
667 'component_type' => 'StandAloneComponent',
668 'class' => 'configure_google_calendar',
669 'route' => [
670 'name' => 'configure-google'
671 ]
672 ],
673 'outlook' => [
674 'title' => __('Outlook Calendar / MS Teams', 'fluent-booking'),
675 'disable' => true,
676 'icon_url' => $urlAssets . 'images/ol-icon-color.svg',
677 'component_type' => 'GlobalSettingsComponent',
678 'class' => 'configure_outlook_calendar',
679 'route' => [
680 'name' => 'configure-integrations',
681 'params' => [
682 'settings_key' => 'outlook'
683 ]
684 ]
685 ],
686 'apple_calendar' => [
687 'title' => __('Apple Calendar', 'fluent-booking'),
688 'disable' => true,
689 'icon_url' => $urlAssets . 'images/a-cal.svg',
690 'component_type' => 'GlobalSettingsComponent',
691 'class' => 'configure_apple_calendar',
692 'route' => [
693 'name' => 'configure-integrations',
694 'params' => [
695 'settings_key' => 'apple_calendar'
696 ]
697 ]
698 ],
699 'next_cloud_calendar' => [
700 'title' => __('Nextcloud Calendar', 'fluent-booking'),
701 'disable' => true,
702 'svg_icon' => '<svg xmlns="http://www.w3.org/2000/svg" height="800" width="1200" viewBox="-17.0838 -18.65685 148.0596 111.9411"><path d="M57.0328 0C45.2275 0 35.2216 8.0032 32.1204 18.8466c-2.6952-5.7515-8.5359-9.781-15.2633-9.781C7.6053 9.0657 0 16.671 0 25.9228c0 9.2519 7.6052 16.8606 16.857 16.8606 6.7275 0 12.5682-4.0319 15.2635-9.7844 3.1011 10.8442 13.107 18.85 24.9123 18.85 11.718 0 21.6729-7.885 24.8533-18.607 2.745 5.622 8.5135 9.5414 15.1454 9.5414 9.2518 0 16.8605-7.6087 16.8605-16.8606 0-9.2518-7.6087-16.857-16.8605-16.857-6.632 0-12.4003 3.917-15.1454 9.5378C78.7057 7.8825 68.7507 0 57.0328 0zm0 9.8955c8.9116 0 16.0307 7.1156 16.0307 16.0272s-7.119 16.0308-16.0307 16.0308c-8.9116 0-16.0272-7.1192-16.0272-16.0308S48.1212 9.8955 57.0328 9.8955zm-40.1757 9.0657c3.9044 0 6.965 3.0571 6.965 6.9615s-3.0606 6.965-6.965 6.965-6.9616-3.0606-6.9616-6.965 3.0572-6.9615 6.9616-6.9615zm80.1744 0c3.9044 0 6.965 3.0571 6.965 6.9615s-3.0606 6.965-6.965 6.965-6.9616-3.0606-6.9616-6.965 3.0572-6.9615 6.9616-6.9615z" color="currentColor" font-weight="400" font-family="sans-serif" overflow="visible" fill="currentColor"></path><path d="M29.1085 63.7615c2.7752 0 4.3275 1.9756 4.3275 4.939 0 .2822-.2352.5174-.5174.5174h-7.4792c.047 2.6342 1.8816 4.1394 3.9983 4.1394 1.3171 0 2.2579-.5644 2.7283-.9408.2822-.1881.5174-.141.6585.1412l.1411.2352c.1411.2351.094.4703-.1411.6585-.5645.4233-1.7875 1.129-3.4338 1.129-3.0575 0-5.4094-2.2109-5.4094-5.4095.047-3.3868 2.3048-5.4094 5.1272-5.4094zm2.8693 4.4216c-.094-2.1638-1.4112-3.2457-2.9164-3.2457-1.7404 0-3.2456 1.129-3.575 3.2457zm15.584-2.9164v-3.622c0-.3292.1882-.5174.5174-.5174h.3764c.3292 0 .4703.1882.4703.5174v2.446h2.1168c.3292 0 .5174.1882.5174.5174v.1412c0 .3292-.1882.4703-.5174.4703h-2.1168v5.1743c0 2.399 1.4582 2.6812 2.2579 2.7282.4233.047.5644.1411.5644.5174v.2823c0 .3292-.141.4704-.5644.4704-2.2579 0-3.622-1.3642-3.622-3.8102zm10.7718-1.5052c1.7875 0 2.9164.7526 3.4339 1.176.2351.188.2822.4233.047.7055l-.1411.2352c-.1882.2822-.4234.2822-.7056.094-.4704-.3292-1.3641-.9407-2.5871-.9407-2.2579 0-4.0453 1.6934-4.0453 4.1864 0 2.446 1.7874 4.1394 4.0453 4.1394 1.4582 0 2.446-.6585 2.9164-1.0819.2822-.1881.4704-.141.6585.1411l.1411.1882c.1411.2822.0941.4704-.141.7056-.5175.4233-1.7876 1.317-3.6691 1.317-3.0575 0-5.4094-2.2108-5.4094-5.4094.047-3.1986 2.399-5.4564 5.4564-5.4564zm6.2562-3.3398c0-.3292-.1882-.5174.141-.5174h.3764c.3293 0 .8467.1882.8467.5174V71.664c0 1.3171.6115 1.4582 1.0819 1.5053.2352 0 .4233.141.4233.4703v.3293c0 .3293-.1411.5174-.5174.5174-.8467 0-2.352-.2822-2.352-2.54zm9.6429 3.3398c3.0104 0 5.4564 2.3048 5.4564 5.3623 0 3.1046-2.446 5.4565-5.4564 5.4565-3.0105 0-5.4565-2.352-5.4565-5.4565 0-3.0575 2.446-5.3623 5.4565-5.3623zm0 9.5958c2.2108 0 3.9982-1.7875 3.9982-4.2335 0-2.3519-1.7874-4.0923-3.9982-4.0923s-4.0454 1.7875-4.0454 4.0923c.047 2.399 1.8346 4.2335 4.0454 4.2335zm23.4722-9.5958c2.493 0 3.3868 2.0697 3.3868 2.0697h.047s-.047-.3293-.047-.7997v-4.6568c0-.3293-.1412-.5174.1881-.5174h.3763c.3293 0 .8467.1881.8467.5174v13.406c0 .3292-.1411.5174-.4704.5174h-.3292c-.3293 0-.5175-.1411-.5175-.4704v-.7997c0-.3763.0941-.6585.0941-.6585h-.047s-.8938 2.1638-3.575 2.1638c-2.7752 0-4.5157-2.2108-4.5157-5.4095-.094-3.1986 1.8345-5.3623 4.5628-5.3623zm.047 9.5958c1.7404 0 3.3398-1.223 3.3398-4.1864 0-2.1167-1.082-4.1394-3.2927-4.1394-1.8345 0-3.3398 1.5052-3.3398 4.1394.047 2.54 1.3641 4.1864 3.2927 4.1864zm-85.8923.9878h.3763c.3293 0 .5174-.1881.5174-.5174V63.7274c0-1.5993 1.7404-2.7412 3.716-2.7412 1.9757 0 3.7161 1.142 3.7161 2.7412v10.1003c0 .3293.1882.5174.5174.5174h.3763c.3293 0 .4704-.1881.4704-.5174V63.6674c0-2.6812-2.6812-3.9983-5.1272-3.9983-2.3519 0-5.0331 1.317-5.0331 3.9983v10.1603c0 .3293.1411.5174.4704.5174zm78.5073-10.3485h-.3763c-.3293 0-.5175.1882-.5175.5175v5.6916c0 1.5993-1.0348 3.0575-3.0575 3.0575-1.9756 0-3.0575-1.4582-3.0575-3.0575v-5.6916c0-.3293-.1881-.5175-.5174-.5175h-.3763c-.3293 0-.4704.1882-.4704.5175v6.068c0 2.6811 1.9756 3.9982 4.4216 3.9982 2.446 0 4.4217-1.317 4.4217-3.9983v-6.068c.047-.3292-.1412-.5174-.4704-.5174zm-46.5643-.0771c-.1152.0184-.2258.0953-.3317.2214L41.5673 66.41l-1.4249 1.6978-2.1571-2.5715-1.1705-1.3955c-.1058-.1261-.2257-.195-.35-.2058-.1244-.0107-.2533.0366-.3795.1424l-.2884.2416c-.2523.2117-.2392.446-.0276.6982l1.9045 2.2693 1.5793 1.8815-2.3124 2.7553c-.0018.002-.0029.0043-.0046.0064l-1.1668 1.39c-.2117.2523-.188.5178.0643.7295l.2885.2407c.2522.2116.481.1585.6927-.0937l1.9036-2.2693 1.425-1.6977 2.157 2.5715c.0015.0016.0032.0029.0047.0046l1.1668 1.391c.2116.2521.4763.275.7285.0633l.2885-.2416c.2522-.2117.2392-.446.0275-.6983l-1.9045-2.2692-1.5792-1.8815 2.3124-2.7553c.0017-.002.0028-.0044.0046-.0064l1.1668-1.39c.2116-.2523.1879-.5179-.0643-.7295l-.2885-.2416c-.1261-.1058-.2459-.1452-.361-.1268z" fill="currentColor"></path></svg>',
703 'component_type' => 'GlobalSettingsComponent',
704 'class' => 'configure_nextcloud_calendar',
705 'route' => [
706 'name' => 'configure-integrations',
707 'params' => [
708 'settings_key' => 'next_cloud_calendar'
709 ]
710 ]
711 ],
712 'zoom_meeting' => [
713 'title' => __('Zoom', 'fluent-booking'),
714 'disable' => true,
715 'icon_url' => $urlAssets . 'images/zoom.svg',
716 'component_type' => 'StandAloneComponent',
717 'class' => 'zoom_integrations',
718 'route' => [
719 'name' => 'zoom_integrations'
720 ]
721 ],
722 'twilio' => [
723 'title' => __('SMS by Twilio', 'fluent-booking'),
724 'disable' => true,
725 'svg_icon' => '<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" viewBox="0 0 24 24" id="twilio"><path d="M0,12c0,6.64,5.359,12,12,12s12-5.36,12-12c0-6.641-5.36-12-12-12C5.381-0.008,0.008,5.352,0,11.971V12z M3.199,12c-0.014-4.846,3.904-8.786,8.75-8.801H12c4.847-0.014,8.786,3.904,8.801,8.75V12c0.015,4.847-3.904,8.786-8.75,8.801H12c-4.846,0.015-8.786-3.904-8.801-8.75V12z"></path><path d="M14.959 17.44c1.361 0 2.481-1.12 2.481-2.48 0-1.359-1.12-2.48-2.481-2.479-1.359 0-2.479 1.12-2.479 2.479C12.486 16.326 13.592 17.432 14.959 17.44zM14.959 11.52c1.361 0 2.481-1.12 2.481-2.479 0-1.361-1.12-2.481-2.481-2.481-1.359 0-2.479 1.12-2.479 2.481C12.487 10.407 13.593 11.513 14.959 11.52zM9.042 17.44c1.359 0 2.479-1.12 2.479-2.48 0-1.359-1.121-2.48-2.479-2.479-1.361 0-2.481 1.12-2.481 2.479C6.567 16.327 7.674 17.433 9.042 17.44zM9.042 11.52c1.359 0 2.479-1.12 2.479-2.479 0-1.361-1.121-2.481-2.479-2.481-1.361 0-2.481 1.12-2.481 2.481C6.567 10.408 7.675 11.513 9.042 11.52z"></path></svg>',
726 'component_type' => 'GlobalSettingsComponent',
727 'class' => 'configure_twilio',
728 'route' => [
729 'name' => 'configure-integrations',
730 'params' => [
731 'settings_key' => 'twilio'
732 ]
733 ]
734 ],
735 'license' => [
736 'title' => __('License', 'fluent-booking'),
737 'disable' => true,
738 'el_icon' => 'Lock',
739 'component_type' => 'StandAloneComponent',
740 'class' => 'configure_license',
741 'route' => [
742 'name' => 'license'
743 ]
744 ]
745 ]);
746 }
747
748 public static function getEventSettingsMenuItems($event)
749 {
750 return apply_filters('fluent_booking/calendar_event_setting_menu_items', [
751 'event_details' => [
752 'type' => 'route',
753 'visible' => true,
754 'disable' => false,
755 'route' => [
756 'name' => 'event_details',
757 'params' => [
758 'calendar_id' => $event->calendar_id,
759 'event_id' => $event->id
760 ]
761 ],
762 'label' => __('Event Details', 'fluent-booking'),
763 'svgIcon' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M8 2V5" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M16 2V5" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M7 13H15" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M7 17H12" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M16 3.5C19.33 3.68 21 4.95 21 9.65V15.83C21 19.95 20 22.01 15 22.01H9C4 22.01 3 19.95 3 15.83V9.65C3 4.95 4.67 3.69 8 3.5H16Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/></svg>'
764 ],
765 'assignment' => [
766 'type' => 'route',
767 'visible' => false,
768 'disable' => true,
769 'route' => [
770 'name' => 'assignment',
771 'params' => [
772 'calendar_id' => $event->calendar_id,
773 'event_id' => $event->id
774 ]
775 ],
776 'label' => __('Assignment', 'fluent-booking'),
777 'svgIcon' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2 h-[16px] w-[16px] stroke-[2px] ltr:mr-2 rtl:ml-2 md:mt-px" data-testid="icon-component"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M22 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>'
778 ],
779 'availability_settings' => [
780 'type' => 'route',
781 'visible' => true,
782 'disable' => false,
783 'route' => [
784 'name' => 'availability_settings',
785 'params' => [
786 'calendar_id' => $event->calendar_id,
787 'event_id' => $event->id
788 ]
789 ],
790 'label' => __('Availability', 'fluent-booking'),
791 'svgIcon' => '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M6.66666 1.66699V4.16699" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M13.3333 1.66699V4.16699" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M2.91666 7.5752H17.0833" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M17.5 7.08366V14.167C17.5 16.667 16.25 18.3337 13.3333 18.3337H6.66667C3.75 18.3337 2.5 16.667 2.5 14.167V7.08366C2.5 4.58366 3.75 2.91699 6.66667 2.91699H13.3333C16.25 2.91699 17.5 4.58366 17.5 7.08366Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M13.0789 11.4167H13.0864" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M13.0789 13.9167H13.0864" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M9.99623 11.4167H10.0037" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M9.99623 13.9167H10.0037" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M6.91194 11.4167H6.91942" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M6.91194 13.9167H6.91942" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
792 ],
793 'limit_settings' => [
794 'type' => 'route',
795 'visible' => true,
796 'disable' => false,
797 'route' => [
798 'name' => 'limit_settings',
799 'params' => [
800 'calendar_id' => $event->calendar_id,
801 'event_id' => $event->id
802 ]
803 ],
804 'label' => __('Limits', 'fluent-booking'),
805 'elIcon' => 'Clock'
806 ],
807 'question_settings' => [
808 'type' => 'route',
809 'visible' => true,
810 'disable' => false,
811 'route' => [
812 'name' => 'question_settings',
813 'params' => [
814 'calendar_id' => $event->calendar_id,
815 'event_id' => $event->id
816 ]
817 ],
818 'label' => __('Question Settings', 'fluent-booking'),
819 'svgIcon' => '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 2V5" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M16 2V5" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M12 13.8714V13.6441C12 12.908 12.5061 12.5182 13.0121 12.2043C13.5061 11.9012 14 11.5115 14 10.797C14 9.8011 13.1085 9 12 9C10.8915 9 10 9.8011 10 10.797" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M11.9945 16.4587H12.0053" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M16 3.5C19.33 3.67504 21 4.91005 21 9.48055V15.4903C21 19.4968 20 21.5 15 21.5H9C4 21.5 3 19.4968 3 15.4903V9.48055C3 4.91005 4.67 3.68476 8 3.5H16Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/></svg>'
820 ],
821 'email_notification' => [
822 'type' => 'route',
823 'visible' => true,
824 'disable' => false,
825 'route' => [
826 'name' => 'email_notification',
827 'params' => [
828 'calendar_id' => $event->calendar_id,
829 'event_id' => $event->id
830 ]
831 ],
832 'label' => __('Email Notification', 'fluent-booking'),
833 'elIcon' => 'Message'
834 ],
835 'sms_notification' => [
836 'type' => 'route',
837 'visible' => true,
838 'disable' => true,
839 'route' => [
840 'name' => 'sms_notification',
841 'params' => [
842 'calendar_id' => $event->calendar_id,
843 'event_id' => $event->id
844 ]
845 ],
846 'label' => __('SMS Notification', 'fluent-booking'),
847 'elIcon' => 'Notification'
848 ],
849 'recurring_settings' => [
850 'type' => 'route',
851 'visible' => ($event->isOneToOne() || $event->isGroup()) ? true : false,
852 'disable' => true,
853 'route' => [
854 'name' => 'recurring_settings',
855 'params' => [
856 'calendar_id' => $event->calendar_id,
857 'event_id' => $event->id
858 ]
859 ],
860 'label' => __('Recurring Settings', 'fluent-booking'),
861 'svgIcon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M6 4H21C21.5523 4 22 4.44772 22 5V12H20V6H6V9L1 5L6 1V4ZM18 20H3C2.44772 20 2 19.5523 2 19V12H4V18H18V15L23 19L18 23V20Z"></path></svg>'
862 ],
863 'advanced_settings' => [
864 'type' => 'route',
865 'visible' => true,
866 'disable' => true,
867 'route' => [
868 'name' => 'advanced_settings',
869 'params' => [
870 'calendar_id' => $event->calendar_id,
871 'event_id' => $event->id
872 ]
873 ],
874 'label' => __('Advanced Settings', 'fluent-booking'),
875 'elIcon' => 'Operation'
876 ],
877 'payment_settings' => [
878 'type' => 'route',
879 'visible' => true,
880 'disable' => true,
881 'route' => [
882 'name' => 'payment_settings',
883 'params' => [
884 'calendar_id' => $event->calendar_id,
885 'event_id' => $event->id
886 ]
887 ],
888 'label' => __('Payment Settings', 'fluent-booking'),
889 'elIcon' => 'Money'
890 ],
891 'webhook_settings' => [
892 'type' => 'route',
893 'visible' => true,
894 'disable' => true,
895 'route' => [
896 'name' => 'webhook_settings',
897 'params' => [
898 'calendar_id' => $event->calendar_id,
899 'event_id' => $event->id
900 ]
901 ],
902 'label' => __('Webhooks Feeds', 'fluent-booking'),
903 'elIcon' => 'Link'
904 ],
905 'integrations' => [
906 'type' => 'route',
907 'visible' => true,
908 'disable' => false,
909 'route' => [
910 'name' => 'integrations',
911 'params' => [
912 'calendar_id' => $event->calendar_id,
913 'event_id' => $event->id
914 ]
915 ],
916 'label' => __('Integrations', 'fluent-booking'),
917 'elIcon' => 'Connection'
918 ]
919 ], $event);
920 }
921
922 public static function getCalendarSettingsMenuItems($calendar)
923 {
924 return apply_filters('fluent_booking/calendar_setting_menu_items', [
925 'calendar_settings' => [
926 'type' => 'route',
927 'visible' => true,
928 'disable' => false,
929 'route' => [
930 'name' => 'calendar_settings',
931 'params' => [
932 'calendar_id' => $calendar->id
933 ]
934 ],
935 'label' => __('Calendar Settings', 'fluent-booking'),
936 'svgIcon' => '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 12.8799V11.1199C2 10.0799 2.85 9.21994 3.9 9.21994C5.71 9.21994 6.45 7.93994 5.54 6.36994C5.02 5.46994 5.33 4.29994 6.24 3.77994L7.97 2.78994C8.76 2.31994 9.78 2.59994 10.25 3.38994L10.36 3.57994C11.26 5.14994 12.74 5.14994 13.65 3.57994L13.76 3.38994C14.23 2.59994 15.25 2.31994 16.04 2.78994L17.77 3.77994C18.68 4.29994 18.99 5.46994 18.47 6.36994C17.56 7.93994 18.3 9.21994 20.11 9.21994C21.15 9.21994 22.01 10.0699 22.01 11.1199V12.8799C22.01 13.9199 21.16 14.7799 20.11 14.7799C18.3 14.7799 17.56 16.0599 18.47 17.6299C18.99 18.5399 18.68 19.6999 17.77 20.2199L16.04 21.2099C15.25 21.6799 14.23 21.3999 13.76 20.6099L13.65 20.4199C12.75 18.8499 11.27 18.8499 10.36 20.4199L10.25 20.6099C9.78 21.3999 8.76 21.6799 7.97 21.2099L6.24 20.2199C5.33 19.6999 5.02 18.5299 5.54 17.6299C6.45 16.0599 5.71 14.7799 3.9 14.7799C2.85 14.7799 2 13.9199 2 12.8799Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/></svg>'
937 ],
938 'calendar_events' => [
939 'type' => 'route',
940 'visible' => true,
941 'disable' => false,
942 'route' => [
943 'name' => 'calendar_events',
944 'params' => [
945 'calendar_id' => $calendar->id
946 ]
947 ],
948 'label' => __('Event Types', 'fluent-booking'),
949 'svgIcon' => '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 6H21" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M8 12H21" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M8 18H21" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M3 6H3.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M3 12H3.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M3 18H3.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'
950 ],
951 'remote_calendars' => [
952 'type' => 'route',
953 'visible' => true,
954 'disable' => true,
955 'route' => [
956 'name' => 'remote_calendars',
957 'params' => [
958 'calendar_id' => $calendar->id
959 ]
960 ],
961 'label' => __('Remote Calendars', 'fluent-booking'),
962 'svgIcon' => '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2 h-[16px] w-[16px] stroke-[2px] ltr:mr-2 rtl:ml-2 md:mt-0" data-testid="icon-component"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"></rect><line x1="16" x2="16" y1="2" y2="6"></line><line x1="8" x2="8" y1="2" y2="6"></line><line x1="3" x2="21" y1="10" y2="10"></line></svg>'
963 ],
964 'zoom_meeting' => [
965 'type' => 'route',
966 'visible' => true,
967 'disable' => true,
968 'route' => [
969 'name' => 'user_zoom_integration',
970 'params' => [
971 'calendar_id' => $calendar->id
972 ]
973 ],
974 'label' => __('Zoom Integration', 'fluent-booking'),
975 'svgIcon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><circle cx="24" cy="24" r="20" fill="#2196f3"/><path fill="#fff" d="M29,31H14c-1.657,0-3-1.343-3-3V17h15c1.657,0,3,1.343,3,3V31z"/><polygon fill="#fff" points="37,31 31,27 31,21 37,17"/></svg>'
976 ]
977 ], $calendar);
978 }
979 }
980
981