feat: dynamic my projects from active dispatches
This commit is contained in:
@@ -27,6 +27,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { useAuthStore } from '@/stores';
|
||||
import apiClient from '@/services/apiClient';
|
||||
import employeeService from '@/services/employeeService';
|
||||
import type { MenuPermission } from '@/types';
|
||||
|
||||
const Sidebar = ({ isCollapsed }: { isCollapsed?: boolean }) => {
|
||||
@@ -36,6 +37,7 @@ const Sidebar = ({ isCollapsed }: { isCollapsed?: boolean }) => {
|
||||
const [isAdminOpen, setIsAdminOpen] = useState(pathname.startsWith('/settings'));
|
||||
const [menuPerms, setMenuPerms] = useState<Record<string, MenuPermission>>({});
|
||||
const [permsLoaded, setPermsLoaded] = useState(false);
|
||||
const [activeDispatches, setActiveDispatches] = useState<{ projectName: string; projectId: number }[]>([]);
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const role = user?.roleCode;
|
||||
|
||||
@@ -49,6 +51,15 @@ const Sidebar = ({ isCollapsed }: { isCollapsed?: boolean }) => {
|
||||
}).catch(() => {}).finally(() => setPermsLoaded(true));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!user) return;
|
||||
employeeService.getActiveDispatches().then((res) => {
|
||||
if (res.success && res.data) {
|
||||
setActiveDispatches(res.data.map((d: any) => ({ projectName: d.projectName || 'Project', projectId: d.projectId })));
|
||||
}
|
||||
}).catch(() => {});
|
||||
}, [user]);
|
||||
|
||||
const canAccess = (menuKey: string): boolean => {
|
||||
if (!permsLoaded) return true; // show all until loaded
|
||||
const perm = menuPerms[menuKey];
|
||||
@@ -73,11 +84,14 @@ const Sidebar = ({ isCollapsed }: { isCollapsed?: boolean }) => {
|
||||
{ name: 'History', href: '/itam', icon: History },
|
||||
];
|
||||
|
||||
const projects = [
|
||||
{ name: 'Samsung Pay SI', dot: 'bg-dot-green' },
|
||||
{ name: 'LG CNS SM', dot: 'bg-dot-orange' },
|
||||
{ name: 'Kakao Maintenance', dot: 'bg-dot-blue' },
|
||||
];
|
||||
const projectDotColors = ['bg-dot-green', 'bg-dot-orange', 'bg-dot-blue', 'bg-dot-pink', 'bg-dot-purple', 'bg-dot-gray'];
|
||||
const getProjectDot = (name: string) => {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
||||
return projectDotColors[Math.abs(hash) % projectDotColors.length];
|
||||
};
|
||||
|
||||
const projectsList = activeDispatches.map((p) => ({ name: p.projectName, dot: getProjectDot(p.projectName), projectId: p.projectId }));
|
||||
|
||||
return (
|
||||
<aside
|
||||
@@ -326,19 +340,23 @@ const Sidebar = ({ isCollapsed }: { isCollapsed?: boolean }) => {
|
||||
)}
|
||||
</div>
|
||||
<nav className="space-y-1">
|
||||
{projects.map((project) => (
|
||||
{projectsList.length > 0 ? projectsList.map((project) => (
|
||||
<Link
|
||||
key={project.name}
|
||||
href="/dispatch"
|
||||
href={`/dispatch?projectId=${project.projectId}`}
|
||||
title={isCollapsed ? project.name : ''}
|
||||
className={`flex items-center hover:bg-gray-50 rounded-xl text-xs font-bold text-text-muted transition-colors ${
|
||||
isCollapsed ? 'justify-center py-2' : 'px-3 py-2'
|
||||
}`}
|
||||
>
|
||||
<span className={`w-2 h-2 rounded-full flex-shrink-0 ${project.dot} ${isCollapsed ? '' : 'mr-3'}`}></span>
|
||||
{!isCollapsed && <span className="whitespace-nowrap">{project.name}</span>}
|
||||
{!isCollapsed && <span className="whitespace-nowrap truncate max-w-[160px]">{project.name}</span>}
|
||||
</Link>
|
||||
))}
|
||||
)) : (
|
||||
!isCollapsed && (
|
||||
<p className="text-[10px] text-text-muted px-2">No active projects</p>
|
||||
)
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user