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