feat: Email templates, bulk delete, communication credits, plan features
- Add email template presets for Browse Templates tab (12 templates) - Add bulk selection and deletion for My Templates tab - Add communication credits system with Twilio integration - Add payment views for credit purchases and auto-reload - Add SMS reminder and masked calling plan permissions - Fix appointment status mapping (frontend/backend mismatch) - Clear masquerade stack on login/logout for session hygiene - Update platform settings with credit configuration - Add new migrations for Twilio and Stripe payment fields 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
@@ -13,21 +13,19 @@ import {
|
||||
Briefcase,
|
||||
Ticket,
|
||||
HelpCircle,
|
||||
Code,
|
||||
ChevronDown,
|
||||
BookOpen,
|
||||
FileQuestion,
|
||||
LifeBuoy,
|
||||
Zap,
|
||||
Plug,
|
||||
Package,
|
||||
Clock,
|
||||
Store,
|
||||
Mail
|
||||
Mail,
|
||||
Plug,
|
||||
BookOpen,
|
||||
} from 'lucide-react';
|
||||
import { Business, User } from '../types';
|
||||
import { useLogout } from '../hooks/useAuth';
|
||||
import SmoothScheduleLogo from './SmoothScheduleLogo';
|
||||
import {
|
||||
SidebarSection,
|
||||
SidebarItem,
|
||||
SidebarDivider,
|
||||
} from './navigation/SidebarComponents';
|
||||
|
||||
interface SidebarProps {
|
||||
business: Business;
|
||||
@@ -38,41 +36,14 @@ interface SidebarProps {
|
||||
|
||||
const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCollapse }) => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const { role } = user;
|
||||
const logoutMutation = useLogout();
|
||||
const [isHelpOpen, setIsHelpOpen] = useState(location.pathname.startsWith('/help') || location.pathname === '/support');
|
||||
const [isPluginsOpen, setIsPluginsOpen] = useState(location.pathname.startsWith('/plugins') || location.pathname === '/plugins/marketplace');
|
||||
|
||||
const getNavClass = (path: string, exact: boolean = false, disabled: boolean = false) => {
|
||||
const isActive = exact
|
||||
? location.pathname === path
|
||||
: location.pathname.startsWith(path);
|
||||
|
||||
const baseClasses = `flex items-center gap-3 py-3 text-base font-medium rounded-lg transition-colors`;
|
||||
const collapsedClasses = isCollapsed ? 'px-3 justify-center' : 'px-4';
|
||||
const activeClasses = 'bg-white/10 text-white';
|
||||
const inactiveClasses = 'text-white/70 hover:text-white hover:bg-white/5';
|
||||
const disabledClasses = 'text-white/30 cursor-not-allowed';
|
||||
|
||||
if (disabled) {
|
||||
return `${baseClasses} ${collapsedClasses} ${disabledClasses}`;
|
||||
}
|
||||
|
||||
return `${baseClasses} ${collapsedClasses} ${isActive ? activeClasses : inactiveClasses}`;
|
||||
};
|
||||
|
||||
const canViewAdminPages = role === 'owner' || role === 'manager';
|
||||
const canViewManagementPages = role === 'owner' || role === 'manager' || role === 'staff';
|
||||
const canViewSettings = role === 'owner';
|
||||
// Tickets: owners/managers always, staff only with permission
|
||||
const canViewTickets = role === 'owner' || role === 'manager' || (role === 'staff' && user.can_access_tickets);
|
||||
|
||||
const getDashboardLink = () => {
|
||||
if (role === 'resource') return '/';
|
||||
return '/';
|
||||
};
|
||||
|
||||
const handleSignOut = () => {
|
||||
logoutMutation.mutate();
|
||||
};
|
||||
@@ -84,23 +55,22 @@ const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCo
|
||||
background: `linear-gradient(to bottom right, ${business.primaryColor}, ${business.secondaryColor || business.primaryColor})`
|
||||
}}
|
||||
>
|
||||
{/* Header / Logo */}
|
||||
<button
|
||||
onClick={toggleCollapse}
|
||||
className={`flex items-center gap-3 w-full text-left px-6 py-8 ${isCollapsed ? 'justify-center' : ''} hover:bg-white/5 transition-colors focus:outline-none`}
|
||||
className={`flex items-center gap-3 w-full text-left px-6 py-6 ${isCollapsed ? 'justify-center' : ''} hover:bg-white/5 transition-colors focus:outline-none`}
|
||||
aria-label={isCollapsed ? "Expand sidebar" : "Collapse sidebar"}
|
||||
>
|
||||
{/* Logo-only mode: full width */}
|
||||
{business.logoDisplayMode === 'logo-only' && business.logoUrl ? (
|
||||
<div className="flex items-center justify-center w-full">
|
||||
<img
|
||||
src={business.logoUrl}
|
||||
alt={business.name}
|
||||
className="max-w-full max-h-16 object-contain"
|
||||
className="max-w-full max-h-12 object-contain"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* Logo/Icon display */}
|
||||
{business.logoUrl && business.logoDisplayMode !== 'text-only' ? (
|
||||
<div className="flex items-center justify-center w-10 h-10 shrink-0">
|
||||
<img
|
||||
@@ -110,12 +80,13 @@ const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCo
|
||||
/>
|
||||
</div>
|
||||
) : business.logoDisplayMode !== 'logo-only' && (
|
||||
<div className="flex items-center justify-center w-10 h-10 bg-white rounded-lg text-brand-600 font-bold text-xl shrink-0" style={{ color: business.primaryColor }}>
|
||||
<div
|
||||
className="flex items-center justify-center w-10 h-10 bg-white rounded-lg font-bold text-xl shrink-0"
|
||||
style={{ color: business.primaryColor }}
|
||||
>
|
||||
{business.name.substring(0, 2).toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Text display */}
|
||||
{!isCollapsed && business.logoDisplayMode !== 'logo-only' && (
|
||||
<div className="overflow-hidden">
|
||||
<h1 className="font-bold leading-tight truncate">{business.name}</h1>
|
||||
@@ -126,219 +97,156 @@ const Sidebar: React.FC<SidebarProps> = ({ business, user, isCollapsed, toggleCo
|
||||
)}
|
||||
</button>
|
||||
|
||||
<nav className="flex-1 px-4 space-y-1 overflow-y-auto">
|
||||
<Link to={getDashboardLink()} className={getNavClass('/', true)} title={t('nav.dashboard')}>
|
||||
<LayoutDashboard size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.dashboard')}</span>}
|
||||
</Link>
|
||||
|
||||
<Link to="/scheduler" className={getNavClass('/scheduler')} title={t('nav.scheduler')}>
|
||||
<CalendarDays size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.scheduler')}</span>}
|
||||
</Link>
|
||||
|
||||
<Link to="/tasks" className={getNavClass('/tasks')} title={t('nav.tasks', 'Tasks')}>
|
||||
<Clock size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.tasks', 'Tasks')}</span>}
|
||||
</Link>
|
||||
{/* Navigation */}
|
||||
<nav className="flex-1 px-3 space-y-6 overflow-y-auto pb-4">
|
||||
{/* Core Features - Always visible */}
|
||||
<SidebarSection isCollapsed={isCollapsed}>
|
||||
<SidebarItem
|
||||
to="/"
|
||||
icon={LayoutDashboard}
|
||||
label={t('nav.dashboard')}
|
||||
isCollapsed={isCollapsed}
|
||||
exact
|
||||
/>
|
||||
<SidebarItem
|
||||
to="/scheduler"
|
||||
icon={CalendarDays}
|
||||
label={t('nav.scheduler')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
<SidebarItem
|
||||
to="/tasks"
|
||||
icon={Clock}
|
||||
label={t('nav.tasks', 'Tasks')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
</SidebarSection>
|
||||
|
||||
{/* Manage Section - Staff+ */}
|
||||
{canViewManagementPages && (
|
||||
<>
|
||||
<Link to="/customers" className={getNavClass('/customers')} title={t('nav.customers')}>
|
||||
<Users size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.customers')}</span>}
|
||||
</Link>
|
||||
<Link to="/services" className={getNavClass('/services')} title={t('nav.services', 'Services')}>
|
||||
<Briefcase size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.services', 'Services')}</span>}
|
||||
</Link>
|
||||
<Link to="/resources" className={getNavClass('/resources')} title={t('nav.resources')}>
|
||||
<ClipboardList size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.resources')}</span>}
|
||||
</Link>
|
||||
</>
|
||||
<SidebarSection title={t('nav.sections.manage', 'Manage')} isCollapsed={isCollapsed}>
|
||||
<SidebarItem
|
||||
to="/customers"
|
||||
icon={Users}
|
||||
label={t('nav.customers')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
<SidebarItem
|
||||
to="/services"
|
||||
icon={Briefcase}
|
||||
label={t('nav.services', 'Services')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
<SidebarItem
|
||||
to="/resources"
|
||||
icon={ClipboardList}
|
||||
label={t('nav.resources')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
{canViewAdminPages && (
|
||||
<SidebarItem
|
||||
to="/staff"
|
||||
icon={Users}
|
||||
label={t('nav.staff')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
)}
|
||||
</SidebarSection>
|
||||
)}
|
||||
|
||||
{canViewTickets && (
|
||||
<Link to="/tickets" className={getNavClass('/tickets')} title={t('nav.tickets')}>
|
||||
<Ticket size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.tickets')}</span>}
|
||||
</Link>
|
||||
{/* Communicate Section - Tickets + Messages */}
|
||||
{(canViewTickets || canViewAdminPages) && (
|
||||
<SidebarSection title={t('nav.sections.communicate', 'Communicate')} isCollapsed={isCollapsed}>
|
||||
{canViewAdminPages && (
|
||||
<SidebarItem
|
||||
to="/messages"
|
||||
icon={MessageSquare}
|
||||
label={t('nav.messages')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
)}
|
||||
{canViewTickets && (
|
||||
<SidebarItem
|
||||
to="/tickets"
|
||||
icon={Ticket}
|
||||
label={t('nav.tickets')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
)}
|
||||
</SidebarSection>
|
||||
)}
|
||||
|
||||
{/* Money Section - Payments */}
|
||||
{canViewAdminPages && (
|
||||
<>
|
||||
{/* Payments link: always visible for owners, only visible for others if enabled */}
|
||||
{(role === 'owner' || business.paymentsEnabled) && (
|
||||
business.paymentsEnabled ? (
|
||||
<Link to="/payments" className={getNavClass('/payments')} title={t('nav.payments')}>
|
||||
<CreditCard size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.payments')}</span>}
|
||||
</Link>
|
||||
) : (
|
||||
<div
|
||||
className={getNavClass('/payments', false, true)}
|
||||
title={t('nav.paymentsDisabledTooltip')}
|
||||
>
|
||||
<CreditCard size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.payments')}</span>}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
<Link to="/messages" className={getNavClass('/messages')} title={t('nav.messages')}>
|
||||
<MessageSquare size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.messages')}</span>}
|
||||
</Link>
|
||||
<Link to="/staff" className={getNavClass('/staff')} title={t('nav.staff')}>
|
||||
<Users size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.staff')}</span>}
|
||||
</Link>
|
||||
|
||||
{/* Plugins Dropdown */}
|
||||
<div>
|
||||
<button
|
||||
onClick={() => setIsPluginsOpen(!isPluginsOpen)}
|
||||
className={`flex items-center gap-3 py-3 text-base font-medium rounded-lg transition-colors w-full ${isCollapsed ? 'px-3 justify-center' : 'px-4'} ${location.pathname.startsWith('/plugins') ? 'bg-white/10 text-white' : 'text-white/70 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.plugins', 'Plugins')}
|
||||
>
|
||||
<Plug size={20} className="shrink-0" />
|
||||
{!isCollapsed && (
|
||||
<>
|
||||
<span className="flex-1 text-left">{t('nav.plugins', 'Plugins')}</span>
|
||||
<ChevronDown size={16} className={`shrink-0 transition-transform ${isPluginsOpen ? 'rotate-180' : ''}`} />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
{isPluginsOpen && !isCollapsed && (
|
||||
<div className="ml-4 mt-1 space-y-1 border-l border-white/20 pl-4">
|
||||
<Link
|
||||
to="/plugins/marketplace"
|
||||
className={`flex items-center gap-3 py-2 text-sm font-medium rounded-lg transition-colors px-3 ${location.pathname === '/plugins/marketplace' ? 'bg-white/10 text-white' : 'text-white/60 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.marketplace', 'Marketplace')}
|
||||
>
|
||||
<Store size={16} className="shrink-0" />
|
||||
<span>{t('nav.marketplace', 'Marketplace')}</span>
|
||||
</Link>
|
||||
<Link
|
||||
to="/plugins/my-plugins"
|
||||
className={`flex items-center gap-3 py-2 text-sm font-medium rounded-lg transition-colors px-3 ${location.pathname === '/plugins/my-plugins' ? 'bg-white/10 text-white' : 'text-white/60 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.myPlugins', 'My Plugins')}
|
||||
>
|
||||
<Package size={16} className="shrink-0" />
|
||||
<span>{t('nav.myPlugins', 'My Plugins')}</span>
|
||||
</Link>
|
||||
<Link
|
||||
to="/email-templates"
|
||||
className={`flex items-center gap-3 py-2 text-sm font-medium rounded-lg transition-colors px-3 ${location.pathname === '/email-templates' ? 'bg-white/10 text-white' : 'text-white/60 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.emailTemplates', 'Email Templates')}
|
||||
>
|
||||
<Mail size={16} className="shrink-0" />
|
||||
<span>{t('nav.emailTemplates', 'Email Templates')}</span>
|
||||
</Link>
|
||||
<Link
|
||||
to="/help/plugins"
|
||||
className={`flex items-center gap-3 py-2 text-sm font-medium rounded-lg transition-colors px-3 ${location.pathname === '/help/plugins' ? 'bg-white/10 text-white' : 'text-white/60 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.pluginDocs', 'Plugin Documentation')}
|
||||
>
|
||||
<Zap size={16} className="shrink-0" />
|
||||
<span>{t('nav.pluginDocs', 'Plugin Docs')}</span>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Help Dropdown */}
|
||||
<div>
|
||||
<button
|
||||
onClick={() => setIsHelpOpen(!isHelpOpen)}
|
||||
className={`flex items-center gap-3 py-3 text-base font-medium rounded-lg transition-colors w-full ${isCollapsed ? 'px-3 justify-center' : 'px-4'} ${location.pathname.startsWith('/help') || location.pathname === '/support' ? 'bg-white/10 text-white' : 'text-white/70 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.help', 'Help')}
|
||||
>
|
||||
<HelpCircle size={20} className="shrink-0" />
|
||||
{!isCollapsed && (
|
||||
<>
|
||||
<span className="flex-1 text-left">{t('nav.help', 'Help')}</span>
|
||||
<ChevronDown size={16} className={`shrink-0 transition-transform ${isHelpOpen ? 'rotate-180' : ''}`} />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
{isHelpOpen && !isCollapsed && (
|
||||
<div className="ml-4 mt-1 space-y-1 border-l border-white/20 pl-4">
|
||||
<Link
|
||||
to="/help/guide"
|
||||
className={`flex items-center gap-3 py-2 text-sm font-medium rounded-lg transition-colors px-3 ${location.pathname === '/help/guide' ? 'bg-white/10 text-white' : 'text-white/60 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.platformGuide', 'Platform Guide')}
|
||||
>
|
||||
<BookOpen size={16} className="shrink-0" />
|
||||
<span>{t('nav.platformGuide', 'Platform Guide')}</span>
|
||||
</Link>
|
||||
<Link
|
||||
to="/help/ticketing"
|
||||
className={`flex items-center gap-3 py-2 text-sm font-medium rounded-lg transition-colors px-3 ${location.pathname === '/help/ticketing' ? 'bg-white/10 text-white' : 'text-white/60 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.ticketingHelp', 'Ticketing System')}
|
||||
>
|
||||
<FileQuestion size={16} className="shrink-0" />
|
||||
<span>{t('nav.ticketingHelp', 'Ticketing System')}</span>
|
||||
</Link>
|
||||
{role === 'owner' && (
|
||||
<Link
|
||||
to="/help/api"
|
||||
className={`flex items-center gap-3 py-2 text-sm font-medium rounded-lg transition-colors px-3 ${location.pathname === '/help/api' ? 'bg-white/10 text-white' : 'text-white/60 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.apiDocs', 'API Documentation')}
|
||||
>
|
||||
<Code size={16} className="shrink-0" />
|
||||
<span>{t('nav.apiDocs', 'API Docs')}</span>
|
||||
</Link>
|
||||
)}
|
||||
<div className="pt-2 mt-2 border-t border-white/10">
|
||||
<Link
|
||||
to="/support"
|
||||
className={`flex items-center gap-3 py-2 text-sm font-medium rounded-lg transition-colors px-3 ${location.pathname === '/support' ? 'bg-white/10 text-white' : 'text-white/60 hover:text-white hover:bg-white/5'}`}
|
||||
title={t('nav.support', 'Support')}
|
||||
>
|
||||
<MessageSquare size={16} className="shrink-0" />
|
||||
<span>{t('nav.support', 'Support')}</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
<SidebarSection title={t('nav.sections.money', 'Money')} isCollapsed={isCollapsed}>
|
||||
<SidebarItem
|
||||
to="/payments"
|
||||
icon={CreditCard}
|
||||
label={t('nav.payments')}
|
||||
isCollapsed={isCollapsed}
|
||||
disabled={!business.paymentsEnabled && role !== 'owner'}
|
||||
/>
|
||||
</SidebarSection>
|
||||
)}
|
||||
|
||||
{canViewSettings && (
|
||||
<div className="pt-8 mt-8 border-t border-white/10">
|
||||
{canViewSettings && (
|
||||
<Link to="/settings" className={getNavClass('/settings', true)} title={t('nav.businessSettings')}>
|
||||
<Settings size={20} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('nav.businessSettings')}</span>}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
{/* Extend Section - Plugins & Templates */}
|
||||
{canViewAdminPages && (
|
||||
<SidebarSection title={t('nav.sections.extend', 'Extend')} isCollapsed={isCollapsed}>
|
||||
<SidebarItem
|
||||
to="/plugins"
|
||||
icon={Plug}
|
||||
label={t('nav.plugins', 'Plugins')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
<SidebarItem
|
||||
to="/email-templates"
|
||||
icon={Mail}
|
||||
label={t('nav.emailTemplates', 'Email Templates')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
</SidebarSection>
|
||||
)}
|
||||
|
||||
{/* Footer Section - Settings & Help */}
|
||||
<SidebarDivider isCollapsed={isCollapsed} />
|
||||
|
||||
<SidebarSection isCollapsed={isCollapsed}>
|
||||
{canViewSettings && (
|
||||
<SidebarItem
|
||||
to="/settings"
|
||||
icon={Settings}
|
||||
label={t('nav.businessSettings')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
)}
|
||||
<SidebarItem
|
||||
to="/help"
|
||||
icon={HelpCircle}
|
||||
label={t('nav.helpDocs', 'Help & Docs')}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
</SidebarSection>
|
||||
</nav>
|
||||
|
||||
{/* User Section */}
|
||||
<div className="p-4 border-t border-white/10">
|
||||
<a
|
||||
href={`${window.location.protocol}//${window.location.host.split('.').slice(-2).join('.')}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={`flex items-center gap-2 text-xs text-white/60 mb-4 hover:text-white/80 transition-colors ${isCollapsed ? 'justify-center' : ''}`}
|
||||
className={`flex items-center gap-2 text-xs text-white/60 mb-3 hover:text-white/80 transition-colors ${isCollapsed ? 'justify-center' : ''}`}
|
||||
>
|
||||
<SmoothScheduleLogo className="w-6 h-6 text-white" />
|
||||
<SmoothScheduleLogo className="w-5 h-5 text-white" />
|
||||
{!isCollapsed && (
|
||||
<div>
|
||||
<span className="block">{t('common.poweredBy')}</span>
|
||||
<span className="font-semibold text-white/80">Smooth Schedule</span>
|
||||
</div>
|
||||
<span className="text-white/60">Smooth Schedule</span>
|
||||
)}
|
||||
</a>
|
||||
<button
|
||||
onClick={handleSignOut}
|
||||
disabled={logoutMutation.isPending}
|
||||
className={`flex items-center gap-3 px-4 py-2 text-sm font-medium text-white/70 hover:text-white w-full transition-colors rounded-lg ${isCollapsed ? 'justify-center' : ''} disabled:opacity-50`}
|
||||
className={`flex items-center gap-3 px-3 py-2 text-sm font-medium text-white/70 hover:text-white hover:bg-white/5 w-full transition-colors rounded-lg ${isCollapsed ? 'justify-center' : ''} disabled:opacity-50`}
|
||||
>
|
||||
<LogOut size={20} className="shrink-0" />
|
||||
<LogOut size={18} className="shrink-0" />
|
||||
{!isCollapsed && <span>{t('auth.signOut')}</span>}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user