New alert service
This commit is contained in:
@@ -8,6 +8,7 @@ import { useHasAccess } from '../../../hooks/useAccessControl';
|
||||
import { getNavigationRoutes, canAccessRoute, ROUTES } from '../../../router/routes.config';
|
||||
import { useSubscriptionAwareRoutes } from '../../../hooks/useSubscriptionAwareRoutes';
|
||||
import { useSubscriptionEvents } from '../../../contexts/SubscriptionEventsContext';
|
||||
import { useSubscription } from '../../../api/hooks/subscription';
|
||||
import { Button } from '../../ui';
|
||||
import { Badge } from '../../ui';
|
||||
import { Tooltip } from '../../ui';
|
||||
@@ -136,6 +137,7 @@ const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
|
||||
insights: Lightbulb,
|
||||
events: Activity,
|
||||
list: List,
|
||||
distribution: Truck,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -162,7 +164,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
showCollapseButton = true,
|
||||
showFooter = true,
|
||||
}, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const { t } = useTranslation(['common']);
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const user = useAuthUser();
|
||||
@@ -170,7 +172,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
const hasAccess = useHasAccess(); // For UI visibility
|
||||
const currentTenantAccess = useCurrentTenantAccess();
|
||||
const { logout } = useAuthActions();
|
||||
|
||||
|
||||
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
||||
const [hoveredItem, setHoveredItem] = useState<string | null>(null);
|
||||
const [isProfileMenuOpen, setIsProfileMenuOpen] = useState(false);
|
||||
@@ -179,6 +181,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
const searchInputRef = React.useRef<HTMLInputElement>(null);
|
||||
const sidebarRef = React.useRef<HTMLDivElement>(null);
|
||||
const { subscriptionVersion } = useSubscriptionEvents();
|
||||
const { subscriptionInfo } = useSubscription();
|
||||
|
||||
// Get subscription-aware navigation routes
|
||||
const baseNavigationRoutes = useMemo(() => getNavigationRoutes(), []);
|
||||
@@ -186,6 +189,11 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
|
||||
// Map route paths to translation keys
|
||||
const getTranslationKey = (routePath: string): string => {
|
||||
// Special case for Enterprise tier: Rename "Mi Panadería" to "Central Baker"
|
||||
if (routePath === '/app/database' && subscriptionInfo.plan === 'enterprise') {
|
||||
return 'navigation.central_baker';
|
||||
}
|
||||
|
||||
const pathMappings: Record<string, string> = {
|
||||
'/app/dashboard': 'navigation.dashboard',
|
||||
'/app/operations': 'navigation.operations',
|
||||
@@ -193,6 +201,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
'/app/operations/production': 'navigation.production',
|
||||
'/app/operations/maquinaria': 'navigation.equipment',
|
||||
'/app/operations/pos': 'navigation.pos',
|
||||
'/app/operations/distribution': 'navigation.distribution',
|
||||
'/app/bakery': 'navigation.bakery',
|
||||
'/app/bakery/recipes': 'navigation.recipes',
|
||||
'/app/database': 'navigation.data',
|
||||
@@ -436,11 +445,11 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
const findParentPaths = useCallback((items: NavigationItem[], targetPath: string, parents: string[] = []): string[] => {
|
||||
for (const item of items) {
|
||||
const currentPath = [...parents, item.id];
|
||||
|
||||
|
||||
if (item.path === targetPath) {
|
||||
return parents;
|
||||
}
|
||||
|
||||
|
||||
if (item.children) {
|
||||
const found = findParentPaths(item.children, targetPath, currentPath);
|
||||
if (found.length > 0) {
|
||||
@@ -479,7 +488,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
|
||||
let touchStartX = 0;
|
||||
let touchStartY = 0;
|
||||
|
||||
|
||||
const handleTouchStart = (e: TouchEvent) => {
|
||||
if (isOpen) {
|
||||
touchStartX = e.touches[0].clientX;
|
||||
@@ -489,12 +498,12 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
|
||||
const handleTouchMove = (e: TouchEvent) => {
|
||||
if (!isOpen || !onClose) return;
|
||||
|
||||
|
||||
const touchCurrentX = e.touches[0].clientX;
|
||||
const touchCurrentY = e.touches[0].clientY;
|
||||
const deltaX = touchStartX - touchCurrentX;
|
||||
const deltaY = Math.abs(touchStartY - touchCurrentY);
|
||||
|
||||
|
||||
// Only trigger swipe left to close if it's more horizontal than vertical
|
||||
// and the swipe distance is significant
|
||||
if (deltaX > 50 && deltaX > deltaY * 2) {
|
||||
@@ -536,7 +545,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
e.preventDefault();
|
||||
focusSearch();
|
||||
}
|
||||
|
||||
|
||||
// Escape to close menus
|
||||
if (e.key === 'Escape') {
|
||||
setIsProfileMenuOpen(false);
|
||||
@@ -651,18 +660,18 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
{/* Submenu indicator for collapsed sidebar */}
|
||||
{isCollapsed && hasChildren && level === 0 && item.children && item.children.length > 0 && (
|
||||
<div className="absolute -bottom-1 -right-1 w-2 h-2 bg-[var(--color-primary)] rounded-full opacity-75" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
{!ItemIcon && level > 0 && (
|
||||
<Dot className={clsx(
|
||||
'flex-shrink-0 w-4 h-4 mr-3 transition-colors duration-200',
|
||||
isActive
|
||||
? 'text-[var(--color-primary)]'
|
||||
isActive
|
||||
? 'text-[var(--color-primary)]'
|
||||
: 'text-[var(--text-tertiary)]'
|
||||
)} />
|
||||
)}
|
||||
@@ -671,8 +680,8 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
<>
|
||||
<span className={clsx(
|
||||
'flex-1 truncate transition-colors duration-200 text-sm font-medium',
|
||||
isActive
|
||||
? 'text-[var(--color-primary)]'
|
||||
isActive
|
||||
? 'text-[var(--color-primary)]'
|
||||
: 'text-[var(--text-primary)] group-hover:text-[var(--text-primary)]'
|
||||
)}>
|
||||
{item.label}
|
||||
@@ -692,8 +701,8 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
<ChevronDown className={clsx(
|
||||
'flex-shrink-0 w-4 h-4 ml-2 transition-transform duration-200',
|
||||
isExpanded && 'transform rotate-180',
|
||||
isActive
|
||||
? 'text-[var(--color-primary)]'
|
||||
isActive
|
||||
? 'text-[var(--color-primary)]'
|
||||
: 'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
|
||||
)} />
|
||||
)}
|
||||
@@ -733,7 +742,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
>
|
||||
{itemContent}
|
||||
</button>
|
||||
|
||||
|
||||
{/* Submenu overlay for collapsed sidebar */}
|
||||
{isCollapsed && hasChildren && level === 0 && isHovered && item.children && item.children.length > 0 && (
|
||||
<div
|
||||
@@ -788,7 +797,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
{/* Search */}
|
||||
{!isCollapsed && (
|
||||
<div className="px-4 pt-4" data-search>
|
||||
<form
|
||||
<form
|
||||
onSubmit={handleSearchSubmit}
|
||||
className="relative"
|
||||
>
|
||||
@@ -989,7 +998,7 @@ export const Sidebar = forwardRef<SidebarRef, SidebarProps>(({
|
||||
|
||||
{/* Mobile search - always visible in mobile view */}
|
||||
<div className="p-4 border-b border-[var(--border-primary)]">
|
||||
<form
|
||||
<form
|
||||
onSubmit={handleSearchSubmit}
|
||||
className="relative"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user