Restructure navigation: move setup items to Settings with accordion menu
Move rarely-used setup items from main sidebar to Settings to keep daily-use features prominent: - Services → Settings > Business section - Locations → Settings > Business section - Site Builder → Settings > Branding section Settings sidebar changes: - Convert static sections to accordion (one open at a time) - Auto-expand section based on current URL - Preserve all permission checks for moved items Add redirects from old URLs to new locations for backwards compatibility. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -879,15 +879,10 @@ const AppContent: React.FC = () => {
|
||||
)
|
||||
}
|
||||
/>
|
||||
{/* Redirect old services path to new settings location */}
|
||||
<Route
|
||||
path="/dashboard/services"
|
||||
element={
|
||||
canAccess('can_access_services') ? (
|
||||
<Services />
|
||||
) : (
|
||||
<Navigate to="/dashboard" />
|
||||
)
|
||||
}
|
||||
element={<Navigate to="/dashboard/settings/services" replace />}
|
||||
/>
|
||||
<Route
|
||||
path="/dashboard/resources"
|
||||
@@ -919,15 +914,10 @@ const AppContent: React.FC = () => {
|
||||
)
|
||||
}
|
||||
/>
|
||||
{/* Redirect old locations path to new settings location */}
|
||||
<Route
|
||||
path="/dashboard/locations"
|
||||
element={
|
||||
canAccess('can_access_locations') ? (
|
||||
<Locations />
|
||||
) : (
|
||||
<Navigate to="/dashboard" />
|
||||
)
|
||||
}
|
||||
element={<Navigate to="/dashboard/settings/locations" replace />}
|
||||
/>
|
||||
<Route
|
||||
path="/dashboard/my-availability"
|
||||
@@ -975,15 +965,10 @@ const AppContent: React.FC = () => {
|
||||
)
|
||||
}
|
||||
/>
|
||||
{/* Redirect old site-editor path to new settings location */}
|
||||
<Route
|
||||
path="/dashboard/site-editor"
|
||||
element={
|
||||
canAccess('can_access_site_editor') ? (
|
||||
<PageEditor />
|
||||
) : (
|
||||
<Navigate to="/dashboard" />
|
||||
)
|
||||
}
|
||||
element={<Navigate to="/dashboard/settings/site-builder" replace />}
|
||||
/>
|
||||
<Route
|
||||
path="/dashboard/email-template-editor/:emailType"
|
||||
@@ -1025,6 +1010,10 @@ const AppContent: React.FC = () => {
|
||||
<Route path="sms-calling" element={<CommunicationSettings />} />
|
||||
<Route path="billing" element={<BillingSettings />} />
|
||||
<Route path="quota" element={<QuotaSettings />} />
|
||||
{/* Moved from main sidebar */}
|
||||
<Route path="services" element={<Services />} />
|
||||
<Route path="locations" element={<Locations />} />
|
||||
<Route path="site-builder" element={<PageEditor />} />
|
||||
</Route>
|
||||
) : (
|
||||
<Route path="/dashboard/settings/*" element={<Navigate to="/dashboard" />} />
|
||||
|
||||
@@ -10,15 +10,12 @@ import {
|
||||
MessageSquare,
|
||||
LogOut,
|
||||
ClipboardList,
|
||||
Briefcase,
|
||||
Ticket,
|
||||
HelpCircle,
|
||||
Clock,
|
||||
Plug,
|
||||
FileSignature,
|
||||
CalendarOff,
|
||||
LayoutTemplate,
|
||||
MapPin,
|
||||
Image,
|
||||
} from 'lucide-react';
|
||||
import { Business, User } from '../types';
|
||||
@@ -159,25 +156,14 @@ const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCo
|
||||
|
||||
{/* Manage Section - Show if user has any manage-related permission */}
|
||||
{(canViewManagementPages ||
|
||||
hasPermission('can_access_site_builder') ||
|
||||
hasPermission('can_access_gallery') ||
|
||||
hasPermission('can_access_customers') ||
|
||||
hasPermission('can_access_services') ||
|
||||
hasPermission('can_access_resources') ||
|
||||
hasPermission('can_access_staff') ||
|
||||
hasPermission('can_access_contracts') ||
|
||||
hasPermission('can_access_time_blocks') ||
|
||||
hasPermission('can_access_locations')
|
||||
hasPermission('can_access_time_blocks')
|
||||
) && (
|
||||
<SidebarSection title={t('nav.sections.manage', 'Manage')} isCollapsed={isCollapsed}>
|
||||
{hasPermission('can_access_site_builder') && (
|
||||
<SidebarItem
|
||||
to="/dashboard/site-editor"
|
||||
icon={LayoutTemplate}
|
||||
label={t('nav.siteBuilder', 'Site Builder')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
)}
|
||||
{hasPermission('can_access_gallery') && (
|
||||
<SidebarItem
|
||||
to="/dashboard/gallery"
|
||||
@@ -194,14 +180,6 @@ const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCo
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
)}
|
||||
{hasPermission('can_access_services') && (
|
||||
<SidebarItem
|
||||
to="/dashboard/services"
|
||||
icon={Briefcase}
|
||||
label={t('nav.services', 'Services')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
)}
|
||||
{hasPermission('can_access_resources') && (
|
||||
<SidebarItem
|
||||
to="/dashboard/resources"
|
||||
@@ -235,15 +213,6 @@ const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCo
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
)}
|
||||
{hasPermission('can_access_locations') && (
|
||||
<SidebarItem
|
||||
to="/dashboard/locations"
|
||||
icon={MapPin}
|
||||
label={t('nav.locations', 'Locations')}
|
||||
isCollapsed={isCollapsed}
|
||||
locked={!canUse('multi_location')}
|
||||
/>
|
||||
)}
|
||||
</SidebarSection>
|
||||
)}
|
||||
|
||||
|
||||
@@ -256,6 +256,55 @@ export const SettingsSidebarSection: React.FC<SettingsSidebarSectionProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
interface SettingsAccordionSectionProps {
|
||||
title: string;
|
||||
sectionKey: string;
|
||||
isOpen: boolean;
|
||||
onToggle: (sectionKey: string) => void;
|
||||
children: React.ReactNode;
|
||||
hasVisibleItems?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapsible accordion section for settings sidebar
|
||||
* Only one section can be open at a time (controlled by parent)
|
||||
*/
|
||||
export const SettingsAccordionSection: React.FC<SettingsAccordionSectionProps> = ({
|
||||
title,
|
||||
sectionKey,
|
||||
isOpen,
|
||||
onToggle,
|
||||
children,
|
||||
hasVisibleItems = true,
|
||||
}) => {
|
||||
// Don't render if no visible items
|
||||
if (!hasVisibleItems) return null;
|
||||
|
||||
return (
|
||||
<div className="space-y-0.5">
|
||||
<button
|
||||
onClick={() => onToggle(sectionKey)}
|
||||
className="flex items-center justify-between w-full px-4 py-2 text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 rounded-lg transition-colors"
|
||||
>
|
||||
<span>{title}</span>
|
||||
<ChevronDown
|
||||
size={14}
|
||||
className={`transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`}
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
className={`overflow-hidden transition-all duration-200 ease-in-out ${
|
||||
isOpen ? 'max-h-[500px] opacity-100' : 'max-h-0 opacity-0'
|
||||
}`}
|
||||
>
|
||||
<div className="space-y-0.5 pt-1">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface SettingsSidebarItemProps {
|
||||
to: string;
|
||||
icon: LucideIcon;
|
||||
|
||||
@@ -2042,6 +2042,14 @@
|
||||
"title": "Business Hours",
|
||||
"description": "Operating hours"
|
||||
},
|
||||
"services": {
|
||||
"title": "Services",
|
||||
"description": "Manage your services"
|
||||
},
|
||||
"locations": {
|
||||
"title": "Locations",
|
||||
"description": "Business locations"
|
||||
},
|
||||
"appearance": {
|
||||
"title": "Appearance",
|
||||
"description": "Logo, colors, theme"
|
||||
@@ -2082,6 +2090,10 @@
|
||||
"step2": "Copy the embed code and paste it into your website's HTML where you want the booking widget to appear.",
|
||||
"step3": "For platforms like WordPress, Squarespace, or Wix, look for an \"HTML\" or \"Embed\" block and paste the code there."
|
||||
},
|
||||
"siteBuilder": {
|
||||
"title": "Site Builder",
|
||||
"description": "Build your booking site"
|
||||
},
|
||||
"api": {
|
||||
"title": "API & Webhooks",
|
||||
"description": "API tokens, webhooks"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Used as a wrapper for all /settings/* routes.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Outlet, Link, useLocation, useNavigate, useOutletContext } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
@@ -24,9 +24,12 @@ import {
|
||||
Clock,
|
||||
Users,
|
||||
Code2,
|
||||
Briefcase,
|
||||
MapPin,
|
||||
LayoutTemplate,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
SettingsSidebarSection,
|
||||
SettingsAccordionSection,
|
||||
SettingsSidebarItem,
|
||||
} from '../components/navigation/SidebarComponents';
|
||||
import UnfinishedBadge from '../components/ui/UnfinishedBadge';
|
||||
@@ -46,6 +49,44 @@ const SETTINGS_PAGE_FEATURES: Record<string, FeatureKey> = {
|
||||
'/dashboard/settings/api': 'api_access',
|
||||
'/dashboard/settings/authentication': 'custom_oauth',
|
||||
'/dashboard/settings/sms-calling': 'sms_reminders',
|
||||
'/dashboard/settings/locations': 'multi_location',
|
||||
};
|
||||
|
||||
// Map URL paths to section keys for auto-expand
|
||||
const URL_TO_SECTION: Record<string, string> = {
|
||||
'/dashboard/settings/general': 'business',
|
||||
'/dashboard/settings/resource-types': 'business',
|
||||
'/dashboard/settings/booking': 'business',
|
||||
'/dashboard/settings/business-hours': 'business',
|
||||
'/dashboard/settings/services': 'business',
|
||||
'/dashboard/settings/locations': 'business',
|
||||
'/dashboard/settings/branding': 'branding',
|
||||
'/dashboard/settings/email-templates': 'branding',
|
||||
'/dashboard/settings/custom-domains': 'branding',
|
||||
'/dashboard/settings/embed-widget': 'branding',
|
||||
'/dashboard/settings/site-builder': 'branding',
|
||||
'/dashboard/settings/api': 'integrations',
|
||||
'/dashboard/settings/staff-roles': 'access',
|
||||
'/dashboard/settings/authentication': 'access',
|
||||
'/dashboard/settings/email': 'communication',
|
||||
'/dashboard/settings/sms-calling': 'communication',
|
||||
'/dashboard/settings/billing': 'billing',
|
||||
'/dashboard/settings/quota': 'billing',
|
||||
};
|
||||
|
||||
// Helper to get section from URL
|
||||
const getSectionFromUrl = (pathname: string): string => {
|
||||
// Check for exact match first
|
||||
if (URL_TO_SECTION[pathname]) {
|
||||
return URL_TO_SECTION[pathname];
|
||||
}
|
||||
// Check for prefix match (for nested routes)
|
||||
for (const [path, section] of Object.entries(URL_TO_SECTION)) {
|
||||
if (pathname.startsWith(path)) {
|
||||
return section;
|
||||
}
|
||||
}
|
||||
return 'business'; // Default to business section
|
||||
};
|
||||
|
||||
const SettingsLayout: React.FC = () => {
|
||||
@@ -59,6 +100,20 @@ const SettingsLayout: React.FC = () => {
|
||||
const { user } = parentContext || {};
|
||||
const isOwner = user?.role === 'owner';
|
||||
|
||||
// Accordion state - track which section is open
|
||||
const [openSection, setOpenSection] = useState<string>(() => getSectionFromUrl(location.pathname));
|
||||
|
||||
// Update open section when URL changes
|
||||
useEffect(() => {
|
||||
const section = getSectionFromUrl(location.pathname);
|
||||
setOpenSection(section);
|
||||
}, [location.pathname]);
|
||||
|
||||
// Handle section toggle (only one open at a time)
|
||||
const handleSectionToggle = (sectionKey: string) => {
|
||||
setOpenSection(prev => prev === sectionKey ? '' : sectionKey);
|
||||
};
|
||||
|
||||
// Check if staff has access to a specific settings page
|
||||
const hasSettingsPermission = (permissionKey: string): boolean => {
|
||||
// Owners always have all permissions
|
||||
@@ -100,169 +155,229 @@ const SettingsLayout: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<nav className="flex-1 px-2 pb-4 space-y-3 overflow-y-auto">
|
||||
<nav className="flex-1 px-2 pb-4 space-y-1 overflow-y-auto">
|
||||
{/* Business Section */}
|
||||
{(hasSettingsPermission('can_access_settings_general') ||
|
||||
hasSettingsPermission('can_access_settings_resource_types') ||
|
||||
hasSettingsPermission('can_access_settings_booking') ||
|
||||
hasSettingsPermission('can_access_settings_business_hours')) && (
|
||||
<SettingsSidebarSection title={t('settings.sections.business', 'Business')}>
|
||||
{hasSettingsPermission('can_access_settings_general') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/general"
|
||||
icon={Building2}
|
||||
label={t('settings.general.title', 'General')}
|
||||
description={t('settings.general.description', 'Name, timezone, contact')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_resource_types') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/resource-types"
|
||||
icon={Layers}
|
||||
label={t('settings.resourceTypes.title', 'Resource Types')}
|
||||
description={t('settings.resourceTypes.description', 'Staff, rooms, equipment')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_booking') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/booking"
|
||||
icon={Calendar}
|
||||
label={t('settings.booking.title', 'Booking')}
|
||||
description={t('settings.booking.description', 'Booking URL, redirects')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_business_hours') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/business-hours"
|
||||
icon={Clock}
|
||||
label={t('settings.businessHours.title', 'Business Hours')}
|
||||
description={t('settings.businessHours.description', 'Operating hours')}
|
||||
/>
|
||||
)}
|
||||
</SettingsSidebarSection>
|
||||
)}
|
||||
<SettingsAccordionSection
|
||||
title={t('settings.sections.business', 'Business')}
|
||||
sectionKey="business"
|
||||
isOpen={openSection === 'business'}
|
||||
onToggle={handleSectionToggle}
|
||||
hasVisibleItems={
|
||||
hasSettingsPermission('can_access_settings_general') ||
|
||||
hasSettingsPermission('can_access_settings_resource_types') ||
|
||||
hasSettingsPermission('can_access_settings_booking') ||
|
||||
hasSettingsPermission('can_access_settings_business_hours') ||
|
||||
hasSettingsPermission('can_access_services') ||
|
||||
hasSettingsPermission('can_access_locations')
|
||||
}
|
||||
>
|
||||
{hasSettingsPermission('can_access_settings_general') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/general"
|
||||
icon={Building2}
|
||||
label={t('settings.general.title', 'General')}
|
||||
description={t('settings.general.description', 'Name, timezone, contact')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_resource_types') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/resource-types"
|
||||
icon={Layers}
|
||||
label={t('settings.resourceTypes.title', 'Resource Types')}
|
||||
description={t('settings.resourceTypes.description', 'Staff, rooms, equipment')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_booking') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/booking"
|
||||
icon={Calendar}
|
||||
label={t('settings.booking.title', 'Booking')}
|
||||
description={t('settings.booking.description', 'Booking URL, redirects')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_business_hours') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/business-hours"
|
||||
icon={Clock}
|
||||
label={t('settings.businessHours.title', 'Business Hours')}
|
||||
description={t('settings.businessHours.description', 'Operating hours')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_services') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/services"
|
||||
icon={Briefcase}
|
||||
label={t('settings.services.title', 'Services')}
|
||||
description={t('settings.services.description', 'Manage your services')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_locations') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/locations"
|
||||
icon={MapPin}
|
||||
label={t('settings.locations.title', 'Locations')}
|
||||
description={t('settings.locations.description', 'Business locations')}
|
||||
locked={isLocked('multi_location')}
|
||||
/>
|
||||
)}
|
||||
</SettingsAccordionSection>
|
||||
|
||||
{/* Branding Section */}
|
||||
{(hasSettingsPermission('can_access_settings_branding') ||
|
||||
hasSettingsPermission('can_access_settings_email_templates') ||
|
||||
hasSettingsPermission('can_access_settings_custom_domains') ||
|
||||
hasSettingsPermission('can_access_settings_embed_widget')) && (
|
||||
<SettingsSidebarSection title={t('settings.sections.branding', 'Branding')}>
|
||||
{hasSettingsPermission('can_access_settings_branding') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/branding"
|
||||
icon={Palette}
|
||||
label={t('settings.appearance.title', 'Appearance')}
|
||||
description={t('settings.appearance.description', 'Logo, colors, theme')}
|
||||
locked={isLocked('custom_branding')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_email_templates') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/email-templates"
|
||||
icon={Mail}
|
||||
label={t('settings.emailTemplates.title', 'Email Templates')}
|
||||
description={t('settings.emailTemplates.description', 'Customize automated emails')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_custom_domains') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/custom-domains"
|
||||
icon={Globe}
|
||||
label={t('settings.customDomains.title', 'Custom Domains')}
|
||||
description={t('settings.customDomains.description', 'Use your own domain')}
|
||||
locked={isLocked('custom_domain')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_embed_widget') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/embed-widget"
|
||||
icon={Code2}
|
||||
label={t('settings.embedWidget.title', 'Embed Widget')}
|
||||
description={t('settings.embedWidget.sidebarDescription', 'Add booking to your site')}
|
||||
/>
|
||||
)}
|
||||
</SettingsSidebarSection>
|
||||
)}
|
||||
<SettingsAccordionSection
|
||||
title={t('settings.sections.branding', 'Branding')}
|
||||
sectionKey="branding"
|
||||
isOpen={openSection === 'branding'}
|
||||
onToggle={handleSectionToggle}
|
||||
hasVisibleItems={
|
||||
hasSettingsPermission('can_access_settings_branding') ||
|
||||
hasSettingsPermission('can_access_settings_email_templates') ||
|
||||
hasSettingsPermission('can_access_settings_custom_domains') ||
|
||||
hasSettingsPermission('can_access_settings_embed_widget') ||
|
||||
hasSettingsPermission('can_access_site_builder')
|
||||
}
|
||||
>
|
||||
{hasSettingsPermission('can_access_settings_branding') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/branding"
|
||||
icon={Palette}
|
||||
label={t('settings.appearance.title', 'Appearance')}
|
||||
description={t('settings.appearance.description', 'Logo, colors, theme')}
|
||||
locked={isLocked('custom_branding')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_email_templates') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/email-templates"
|
||||
icon={Mail}
|
||||
label={t('settings.emailTemplates.title', 'Email Templates')}
|
||||
description={t('settings.emailTemplates.description', 'Customize automated emails')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_custom_domains') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/custom-domains"
|
||||
icon={Globe}
|
||||
label={t('settings.customDomains.title', 'Custom Domains')}
|
||||
description={t('settings.customDomains.description', 'Use your own domain')}
|
||||
locked={isLocked('custom_domain')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_embed_widget') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/embed-widget"
|
||||
icon={Code2}
|
||||
label={t('settings.embedWidget.title', 'Embed Widget')}
|
||||
description={t('settings.embedWidget.sidebarDescription', 'Add booking to your site')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_site_builder') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/site-builder"
|
||||
icon={LayoutTemplate}
|
||||
label={t('settings.siteBuilder.title', 'Site Builder')}
|
||||
description={t('settings.siteBuilder.description', 'Build your booking site')}
|
||||
/>
|
||||
)}
|
||||
</SettingsAccordionSection>
|
||||
|
||||
{/* Integrations Section */}
|
||||
{hasSettingsPermission('can_access_settings_api') && (
|
||||
<SettingsSidebarSection title={t('settings.sections.integrations', 'Integrations')}>
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/api"
|
||||
icon={Key}
|
||||
label={t('settings.api.title', 'API & Webhooks')}
|
||||
description={t('settings.api.description', 'API tokens, webhooks')}
|
||||
locked={isLocked('api_access')}
|
||||
/>
|
||||
</SettingsSidebarSection>
|
||||
)}
|
||||
<SettingsAccordionSection
|
||||
title={t('settings.sections.integrations', 'Integrations')}
|
||||
sectionKey="integrations"
|
||||
isOpen={openSection === 'integrations'}
|
||||
onToggle={handleSectionToggle}
|
||||
hasVisibleItems={hasSettingsPermission('can_access_settings_api')}
|
||||
>
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/api"
|
||||
icon={Key}
|
||||
label={t('settings.api.title', 'API & Webhooks')}
|
||||
description={t('settings.api.description', 'API tokens, webhooks')}
|
||||
locked={isLocked('api_access')}
|
||||
/>
|
||||
</SettingsAccordionSection>
|
||||
|
||||
{/* Access Section */}
|
||||
{(hasSettingsPermission('can_access_settings_staff_roles') ||
|
||||
hasSettingsPermission('can_access_settings_authentication')) && (
|
||||
<SettingsSidebarSection title={t('settings.sections.access', 'Access')}>
|
||||
{hasSettingsPermission('can_access_settings_staff_roles') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/staff-roles"
|
||||
icon={Users}
|
||||
label={t('settings.staffRoles.title', 'Staff Roles')}
|
||||
description={t('settings.staffRoles.description', 'Role permissions')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_authentication') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/authentication"
|
||||
icon={Lock}
|
||||
label={t('settings.authentication.title', 'Authentication')}
|
||||
description={t('settings.authentication.description', 'OAuth, social login')}
|
||||
locked={isLocked('custom_oauth')}
|
||||
/>
|
||||
)}
|
||||
</SettingsSidebarSection>
|
||||
)}
|
||||
<SettingsAccordionSection
|
||||
title={t('settings.sections.access', 'Access')}
|
||||
sectionKey="access"
|
||||
isOpen={openSection === 'access'}
|
||||
onToggle={handleSectionToggle}
|
||||
hasVisibleItems={
|
||||
hasSettingsPermission('can_access_settings_staff_roles') ||
|
||||
hasSettingsPermission('can_access_settings_authentication')
|
||||
}
|
||||
>
|
||||
{hasSettingsPermission('can_access_settings_staff_roles') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/staff-roles"
|
||||
icon={Users}
|
||||
label={t('settings.staffRoles.title', 'Staff Roles')}
|
||||
description={t('settings.staffRoles.description', 'Role permissions')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_authentication') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/authentication"
|
||||
icon={Lock}
|
||||
label={t('settings.authentication.title', 'Authentication')}
|
||||
description={t('settings.authentication.description', 'OAuth, social login')}
|
||||
locked={isLocked('custom_oauth')}
|
||||
/>
|
||||
)}
|
||||
</SettingsAccordionSection>
|
||||
|
||||
{/* Communication Section */}
|
||||
{(hasSettingsPermission('can_access_settings_email') ||
|
||||
hasSettingsPermission('can_access_settings_sms_calling')) && (
|
||||
<SettingsSidebarSection title={t('settings.sections.communication', 'Communication')}>
|
||||
{hasSettingsPermission('can_access_settings_email') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/email"
|
||||
icon={Mail}
|
||||
label={t('settings.email.title', 'Email Setup')}
|
||||
description={t('settings.email.description', 'Email addresses for tickets')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_sms_calling') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/sms-calling"
|
||||
icon={Phone}
|
||||
label={t('settings.smsCalling.title', 'SMS & Calling')}
|
||||
description={t('settings.smsCalling.description', 'Credits, phone numbers')}
|
||||
locked={isLocked('sms_reminders')}
|
||||
/>
|
||||
)}
|
||||
</SettingsSidebarSection>
|
||||
)}
|
||||
<SettingsAccordionSection
|
||||
title={t('settings.sections.communication', 'Communication')}
|
||||
sectionKey="communication"
|
||||
isOpen={openSection === 'communication'}
|
||||
onToggle={handleSectionToggle}
|
||||
hasVisibleItems={
|
||||
hasSettingsPermission('can_access_settings_email') ||
|
||||
hasSettingsPermission('can_access_settings_sms_calling')
|
||||
}
|
||||
>
|
||||
{hasSettingsPermission('can_access_settings_email') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/email"
|
||||
icon={Mail}
|
||||
label={t('settings.email.title', 'Email Setup')}
|
||||
description={t('settings.email.description', 'Email addresses for tickets')}
|
||||
/>
|
||||
)}
|
||||
{hasSettingsPermission('can_access_settings_sms_calling') && (
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/sms-calling"
|
||||
icon={Phone}
|
||||
label={t('settings.smsCalling.title', 'SMS & Calling')}
|
||||
description={t('settings.smsCalling.description', 'Credits, phone numbers')}
|
||||
locked={isLocked('sms_reminders')}
|
||||
/>
|
||||
)}
|
||||
</SettingsAccordionSection>
|
||||
|
||||
{/* Billing Section - Owner only */}
|
||||
{isOwner && (
|
||||
<SettingsSidebarSection title={t('settings.sections.billing', 'Billing')}>
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/billing"
|
||||
icon={CreditCard}
|
||||
label={t('settings.billing.title', 'Plan & Billing')}
|
||||
description={t('settings.billing.description', 'Subscription, invoices')}
|
||||
/>
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/quota"
|
||||
icon={AlertTriangle}
|
||||
label={t('settings.quota.title', 'Quota Management')}
|
||||
description={t('settings.quota.description', 'Usage limits, archiving')}
|
||||
/>
|
||||
</SettingsSidebarSection>
|
||||
)}
|
||||
<SettingsAccordionSection
|
||||
title={t('settings.sections.billing', 'Billing')}
|
||||
sectionKey="billing"
|
||||
isOpen={openSection === 'billing'}
|
||||
onToggle={handleSectionToggle}
|
||||
hasVisibleItems={isOwner}
|
||||
>
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/billing"
|
||||
icon={CreditCard}
|
||||
label={t('settings.billing.title', 'Plan & Billing')}
|
||||
description={t('settings.billing.description', 'Subscription, invoices')}
|
||||
/>
|
||||
<SettingsSidebarItem
|
||||
to="/dashboard/settings/quota"
|
||||
icon={AlertTriangle}
|
||||
label={t('settings.quota.title', 'Quota Management')}
|
||||
description={t('settings.quota.description', 'Usage limits, archiving')}
|
||||
/>
|
||||
</SettingsAccordionSection>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user