Initial commit
This commit is contained in:
127
frontend/src/contexts/SidebarContext.tsx
Normal file
127
frontend/src/contexts/SidebarContext.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import { createContext, useContext, useState, useEffect, useCallback } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export type SidebarMode = 'collapsed' | 'expanded' | 'toggle' | 'dynamic';
|
||||
|
||||
interface SidebarContextType {
|
||||
isCollapsed: boolean;
|
||||
isMobileOpen: boolean;
|
||||
sidebarMode: SidebarMode;
|
||||
canToggle: boolean;
|
||||
toggleCollapse: () => void;
|
||||
toggleMobileMenu: () => void;
|
||||
closeMobileMenu: () => void;
|
||||
setSidebarMode: (mode: SidebarMode) => Promise<void>;
|
||||
isHovered: boolean;
|
||||
setIsHovered: (isHovered: boolean) => void;
|
||||
showLogo: boolean;
|
||||
setShowLogo: (show: boolean) => void;
|
||||
}
|
||||
|
||||
const SidebarContext = createContext<SidebarContextType | undefined>(undefined);
|
||||
|
||||
export function SidebarProvider({ children }: { children: ReactNode }) {
|
||||
const [userCollapsed, setUserCollapsed] = useState(true);
|
||||
const [isMobileOpen, setIsMobileOpen] = useState(false);
|
||||
const [sidebarMode, setSidebarModeState] = useState<SidebarMode>('toggle');
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const [showLogo, setShowLogo] = useState(false);
|
||||
|
||||
// Load sidebar mode from backend
|
||||
useEffect(() => {
|
||||
const loadSidebarMode = async () => {
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) return;
|
||||
|
||||
const response = await fetch('/api/v1/settings', {
|
||||
headers: { 'Authorization': `Bearer ${token} ` }
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if (data.sidebar_mode && ['collapsed', 'expanded', 'toggle', 'dynamic'].includes(data.sidebar_mode)) {
|
||||
setSidebarModeState(data.sidebar_mode as SidebarMode);
|
||||
}
|
||||
if (data.show_logo !== undefined) {
|
||||
setShowLogo(data.show_logo === true);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load sidebar mode:', error);
|
||||
}
|
||||
};
|
||||
loadSidebarMode();
|
||||
}, []);
|
||||
|
||||
// Compute isCollapsed based on mode
|
||||
const isCollapsed = sidebarMode === 'collapsed' ? true :
|
||||
sidebarMode === 'dynamic' ? true :
|
||||
sidebarMode === 'expanded' ? false :
|
||||
userCollapsed;
|
||||
|
||||
// Can only toggle if mode is 'toggle'
|
||||
const canToggle = sidebarMode === 'toggle';
|
||||
|
||||
const toggleCollapse = () => {
|
||||
if (canToggle) {
|
||||
setUserCollapsed((prev) => !prev);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleMobileMenu = () => {
|
||||
setIsMobileOpen((prev) => !prev);
|
||||
};
|
||||
|
||||
const closeMobileMenu = () => {
|
||||
setIsMobileOpen(false);
|
||||
};
|
||||
|
||||
const setSidebarMode = useCallback(async (mode: SidebarMode) => {
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
const response = await fetch('/api/v1/settings/sidebar_mode', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token} `,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ value: mode }),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setSidebarModeState(mode);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to save sidebar mode:', error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SidebarContext.Provider
|
||||
value={{
|
||||
isCollapsed,
|
||||
isMobileOpen,
|
||||
sidebarMode,
|
||||
canToggle,
|
||||
toggleCollapse,
|
||||
toggleMobileMenu,
|
||||
closeMobileMenu,
|
||||
setSidebarMode,
|
||||
isHovered,
|
||||
setIsHovered: (value: boolean) => setIsHovered(value),
|
||||
showLogo,
|
||||
setShowLogo,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SidebarContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useSidebar() {
|
||||
const context = useContext(SidebarContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useSidebar must be used within a SidebarProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
Reference in New Issue
Block a user