| @@ -142,31 +142,27 @@ | ||
| 142 | 142 | ); |
| 143 | 143 | } |
| 144 | 144 | } |
| 145 | 145 | |
| 146 | - public function renderApp() | |
| 146 | + public function getMenuItems() | |
| 147 | 147 | { |
| 148 | - $app = App::getInstance(); | |
| 149 | - | |
| 150 | - $assets = $app['url.assets']; | |
| 151 | - | |
| 152 | 148 | $baseUrl = apply_filters('fluent_support/base_url', admin_url('admin.php?page=fluent-support#/')); |
| 153 | 149 | |
| 154 | 150 | $menuItems = [ |
| 155 | - [ | |
| 151 | + 'dashboard' => [ | |
| 156 | 152 | 'key' => 'dashboard', |
| 157 | 153 | 'label' => __('Dashboard', 'fluent-support'), |
| 158 | - 'permalink' => $baseUrl | |
| 154 | + 'permalink' => $baseUrl, | |
| 159 | 155 | ], |
| 160 | - [ | |
| 156 | + 'tickets' => [ | |
| 161 | 157 | 'key' => 'tickets', |
| 162 | 158 | 'label' => __('Tickets', 'fluent-support'), |
| 163 | 159 | 'permalink' => $baseUrl . 'tickets', |
| 164 | 160 | ], |
| 165 | - [ | |
| 161 | + 'reports' => [ | |
| 166 | 162 | 'key' => 'reports', |
| 167 | 163 | 'label' => __('Reports', 'fluent-support'), |
| 168 | - 'permalink' => $baseUrl . 'reports' | |
| 164 | + 'permalink' => $baseUrl . 'reports', | |
| 169 | 165 | ], |
| 170 | 166 | ]; |
| 171 | 167 | |
| 172 | 168 | $canManageSettings = PermissionManager::currentUserCan('fst_manage_settings'); |
| @@ -171,33 +167,31 @@ | ||
| 171 | 167 | |
| 172 | 168 | $canManageSettings = PermissionManager::currentUserCan('fst_manage_settings'); |
| 173 | 169 | |
| 174 | 170 | if ($canManageSettings) { |
| 175 | - $menuItems[] = [ | |
| 171 | + $menuItems['mailboxes'] = [ | |
| 176 | 172 | 'key' => 'mailboxes', |
| 177 | 173 | 'label' => __('Business Inboxes', 'fluent-support'), |
| 178 | - 'permalink' => $baseUrl . 'mailboxes' | |
| 174 | + 'permalink' => $baseUrl . 'mailboxes', | |
| 179 | 175 | ]; |
| 180 | 176 | } |
| 181 | 177 | |
| 182 | 178 | if (PermissionManager::currentUserCan('fst_view_activity_logs')) { |
| 183 | - $menuItems[] = [ | |
| 179 | + $menuItems['activity'] = [ | |
| 184 | 180 | 'key' => 'activity', |
| 185 | 181 | 'label' => __('Activities', 'fluent-support'), |
| 186 | - 'permalink' => $baseUrl . 'activity' | |
| 182 | + 'permalink' => $baseUrl . 'activity', | |
| 187 | 183 | ]; |
| 188 | 184 | } |
| 189 | 185 | |
| 190 | - $hasSensitiveAccess = PermissionManager::currentUserCan('fst_sensitive_data'); | |
| 191 | - if ($hasSensitiveAccess) { | |
| 192 | - $menuItems[] = [ | |
| 186 | + if (PermissionManager::currentUserCan('fst_sensitive_data')) { | |
| 187 | + $menuItems['customers'] = [ | |
| 193 | 188 | 'key' => 'customers', |
| 194 | 189 | 'label' => __('Customers', 'fluent-support'), |
| 195 | - 'permalink' => $baseUrl . 'customers' | |
| 190 | + 'permalink' => $baseUrl . 'customers', | |
| 196 | 191 | ]; |
| 197 | 192 | } |
| 198 | 193 | |
| 199 | - // Build the "More" dropdown children | |
| 200 | 194 | $moreChildren = []; |
| 201 | 195 | |
| 202 | 196 | if (PermissionManager::currentUserCan('fst_manage_saved_replies')) { |
| 203 | 197 | $moreChildren['saved_replies'] = [ |
| @@ -202,9 +196,9 @@ | ||
| 202 | 196 | if (PermissionManager::currentUserCan('fst_manage_saved_replies')) { |
| 203 | 197 | $moreChildren['saved_replies'] = [ |
| 204 | 198 | 'key' => 'saved_replies', |
| 205 | 199 | 'label' => __('Saved Replies', 'fluent-support'), |
| 206 | - 'permalink' => $baseUrl . 'saved-replies' | |
| 200 | + 'permalink' => $baseUrl . 'saved-replies', | |
| 207 | 201 | ]; |
| 208 | 202 | } |
| 209 | 203 | |
| 210 | 204 | if (PermissionManager::currentUserCan('fst_manage_workflows')) { |
| @@ -210,61 +204,65 @@ | ||
| 210 | 204 | if (PermissionManager::currentUserCan('fst_manage_workflows')) { |
| 211 | 205 | $moreChildren['workflows'] = [ |
| 212 | 206 | 'key' => 'workflows', |
| 213 | 207 | 'label' => __('Workflows', 'fluent-support'), |
| 214 | - 'permalink' => $baseUrl . 'workflows' | |
| 208 | + 'permalink' => $baseUrl . 'workflows', | |
| 215 | 209 | ]; |
| 216 | 210 | } |
| 217 | 211 | |
| 218 | - // Add the "More" dropdown if there are children | |
| 219 | 212 | if (!empty($moreChildren)) { |
| 220 | - $menuItems[] = [ | |
| 221 | - 'key' => 'more', | |
| 222 | - 'label' => __('More', 'fluent-support'), | |
| 213 | + $menuItems['more'] = [ | |
| 214 | + 'key' => 'more', | |
| 215 | + 'label' => __('More', 'fluent-support'), | |
| 223 | 216 | 'permalink' => '#', |
| 224 | - 'children' => $moreChildren | |
| 217 | + 'children' => $moreChildren, | |
| 225 | 218 | ]; |
| 226 | 219 | } |
| 227 | 220 | |
| 228 | - $secondaryItems = []; | |
| 229 | - | |
| 230 | 221 | if ($canManageSettings) { |
| 231 | - $secondaryItems[] = [ | |
| 222 | + $menuItems['settings'] = [ | |
| 232 | 223 | 'key' => 'settings', |
| 233 | 224 | 'label' => __('Global Settings', 'fluent-support'), |
| 234 | - 'permalink' => $baseUrl . 'settings' | |
| 225 | + 'permalink' => $baseUrl . 'settings', | |
| 235 | 226 | ]; |
| 236 | 227 | } |
| 237 | 228 | |
| 238 | - /* | |
| 239 | - * Filter Fluent Support dashboard top-left menu items | |
| 240 | - * | |
| 241 | - * @since v1.0.0 | |
| 242 | - * | |
| 243 | - * @param array $menuItems | |
| 244 | - */ | |
| 245 | - $menuItems = apply_filters('fluent_support/primary_menu_items', $menuItems); | |
| 229 | + return apply_filters('fluent_support/menu_items', $menuItems); | |
| 230 | + } | |
| 246 | 231 | |
| 247 | - /* | |
| 248 | - * Filter Fluent Support dashboard top-right menu items | |
| 249 | - * | |
| 250 | - * @since v1.0.0 | |
| 251 | - * | |
| 252 | - * @param array $secondaryItems | |
| 253 | - */ | |
| 254 | - $secondaryItems = apply_filters('fluent_support/secondary_menu_items', $secondaryItems); | |
| 232 | + public function renderApp() | |
| 233 | + { | |
| 234 | + $app = App::getInstance(); | |
| 255 | 235 | |
| 236 | + $assets = $app['url.assets']; | |
| 256 | 237 | |
| 238 | + $allItems = $this->getMenuItems(); | |
| 257 | 239 | |
| 240 | + $secondaryKeys = ['settings']; | |
| 241 | + $menuItems = []; | |
| 242 | + $secondaryItems = []; | |
| 243 | + | |
| 244 | + foreach ($allItems as $key => $item) { | |
| 245 | + if (in_array($key, $secondaryKeys, true)) { | |
| 246 | + $secondaryItems[] = $item; | |
| 247 | + } else { | |
| 248 | + $menuItems[] = $item; | |
| 249 | + } | |
| 250 | + } | |
| 251 | + | |
| 252 | + $menuItems = apply_filters('fluent_support/primary_menu_items', $menuItems); | |
| 253 | + $secondaryItems = apply_filters('fluent_support/secondary_menu_items', $secondaryItems); | |
| 254 | + | |
| 258 | 255 | if (!defined('FLUENT_SUPPORT_PRO_DIR_FILE')) { |
| 259 | 256 | $secondaryItems[] = [ |
| 260 | 257 | 'key' => 'upgrade_to_pro', |
| 261 | - 'label' => 'Upgrade to Pro', | |
| 262 | - 'permalink' => 'https://fluentsupport.com' | |
| 258 | + 'label' => __('Upgrade to Pro', 'fluent-support'), | |
| 259 | + 'permalink' => Helper::getUpgradeUrl('sidebar_cta') | |
| 263 | 260 | ]; |
| 264 | 261 | } |
| 265 | 262 | |
| 266 | - $app = App::getInstance(); | |
| 263 | + $baseUrl = apply_filters('fluent_support/base_url', admin_url('admin.php?page=fluent-support#/')); | |
| 264 | + | |
| 267 | 265 | $this->enqueueAssets(); |
| 268 | 266 | |
| 269 | 267 | do_action('fluent_support/admin_app_loaded', $app); |
| 270 | 268 | $app->view->render('admin.menu', [ |
| @@ -326,9 +324,9 @@ | ||
| 326 | 324 | add_action('admin_head', function () { |
| 327 | 325 | Vite::injectViteClient(); |
| 328 | 326 | }, 1); |
| 329 | 327 | |
| 330 | - wp_enqueue_script('dompurify', $assets . 'libs/purify/purify.min.js', [], '2.4.3'); | |
| 328 | + wp_enqueue_script('dompurify', $assets . 'libs/purify/purify.min.js', [], '3.4.16'); | |
| 331 | 329 | |
| 332 | 330 | if (is_rtl()) { |
| 333 | 331 | wp_enqueue_style('fluent_support_admin_app_rtl', $assets . 'admin/css/alpha-admin-rtl.css', [], FLUENT_SUPPORT_VERSION); |
| 334 | 332 | } else { |
| @@ -426,8 +424,10 @@ | ||
| 426 | 424 | }, $tags); |
| 427 | 425 | |
| 428 | 426 | $i18ns = TranslationStrings::getAdminStrings(); |
| 429 | 427 | $i18ns['allowed_files_and_size'] = Helper::getFileUploadMessage(); |
| 428 | + $i18ns['open'] = __('Open', 'fluent-support'); | |
| 429 | + $i18ns['all'] = __('All', 'fluent-support'); | |
| 430 | 430 | |
| 431 | 431 | /* |
| 432 | 432 | * Filter agent portal localize javascript data |
| 433 | 433 | * |
| @@ -444,22 +444,30 @@ | ||
| 444 | 444 | 'lastEntry' => '', |
| 445 | 445 | 'asset_url' => $assets, |
| 446 | 446 | 'support_agents' => $agents, |
| 447 | 447 | 'agent_groups' => $agentGroups, |
| 448 | - 'support_products' => Product::select(['id', 'title'])->get(), | |
| 448 | + 'support_products' => Product::select(['id', 'title'])->orderedByTitle()->get(), | |
| 449 | 449 | 'client_priorities' => Helper::customerTicketPriorities(), |
| 450 | 450 | 'ticket_statuses' => Helper::ticketStatuses(), |
| 451 | 451 | 'ticket_statuses_group' => Helper::ticketStatusGroups(), |
| 452 | 452 | 'changeable_ticket_statuses' => Helper::changeableTicketStatuses(), |
| 453 | 453 | 'admin_priorities' => Helper::adminTicketPriorities(), |
| 454 | - 'mailboxes' => MailBox::select(['id', 'name', 'settings'])->get(), | |
| 454 | + 'mailboxes' => MailBox::getAccessibleBoxes(), | |
| 455 | + // Whether the site has any inbox at all, regardless of what this agent may see. | |
| 456 | + // `mailboxes` is restriction-filtered and can legitimately be empty, so it cannot | |
| 457 | + // double as the "is Fluent Support set up yet?" signal the setup wizard keys off. | |
| 458 | + 'has_mailboxes' => MailBox::count() > 0, | |
| 455 | 459 | 'me' => $me, |
| 460 | + // Deleting a customer needs fst_sensitive_data plus administrator rights unless | |
| 461 | + // the site turns the administrator part off. | |
| 462 | + 'customer_delete_requires_admin' => (bool) apply_filters('fluent_support/customer_delete_requires_admin', true), | |
| 456 | 463 | 'pref' => [ |
| 457 | 464 | 'go_back_after_reply' => 'yes' |
| 458 | 465 | ], |
| 459 | 466 | 'notification_integrations' => $integrationDrivers, |
| 460 | 467 | 'internal_notification_settings' => (new NotificationSettings())->get(false), |
| 461 | - 'server_time' => gmdate('Y-m-d\TH:i:sP'), | |
| 468 | + // Site time, like every date the API sends; relative times compare the two. | |
| 469 | + 'server_time' => current_time('mysql'), | |
| 462 | 470 | 'has_email_parser' => defined('FLUENTSUPPORTPRO_PLUGIN_VERSION'), |
| 463 | 471 | 'ticket_tags' => $tags, |
| 464 | 472 | 'i18n' => $i18ns, |
| 465 | 473 | 'custom_fields' => apply_filters('fluent_support/ticket_custom_fields', []), |
| @@ -484,8 +492,11 @@ | ||
| 484 | 492 | $appVars['fluent_boards'] = true; |
| 485 | 493 | } |
| 486 | 494 | |
| 487 | 495 | $appVars['has_pro'] = defined('FLUENTSUPPORTPRO_PLUGIN_VERSION'); |
| 496 | + $appVars['version'] = FLUENT_SUPPORT_VERSION; | |
| 497 | + // Single source of truth for upgrade CTAs; the SPA only re-points utm_content on this. | |
| 498 | + $appVars['upgrade_url'] = Helper::getUpgradeUrl(); | |
| 488 | 499 | if ($appVars['has_pro']) { |
| 489 | 500 | $appVars['agent_feedback_rating'] = Helper::getBusinessSettings('agent_feedback_rating', 'no'); |
| 490 | 501 | $appVars['open_ai_integration'] = Helper::openAIIntegrationStatus(); |
| 491 | 502 | } |