"use client"; import { ChevronDown, ChevronRight } from "lucide-react"; import Link from "next/link"; import { useState, type ReactNode } from "react"; import type { OpenPositionResolved } from "@/lib/positions"; import type { OrgDepartment, OrgDivision, OrgEmployee, OrgTeam } from "./types"; function TreeRow({ depth, expandable, expandedNow, onToggle, children, }: { depth: number; expandable: boolean; expandedNow: boolean; onToggle: () => void; children: ReactNode; }) { return (
{expandable ? ( ) : ( )} {children}
); } type PositionTreeProps = { employees: OrgEmployee[]; divisions: OrgDivision[]; departments: OrgDepartment[]; teams: OrgTeam[]; openPositions: OpenPositionResolved[]; }; export function PositionTree({ employees, divisions, departments, teams, openPositions }: PositionTreeProps) { const [expanded, setExpanded] = useState>(new Set(["root"])); function toggle(id: string) { setExpanded((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); } const ceo = employees.find((e) => e.org_level === 0) ?? null; const divisionHeadByDivision = new Map(); const teamLeadByTeam = new Map(); const icsByTeamAndTitle = new Map>(); for (const e of employees) { if (e.org_level === 1 && e.division_id) divisionHeadByDivision.set(e.division_id, e); if (e.is_lead && e.team_id) teamLeadByTeam.set(e.team_id, e); if (!e.is_lead && e.org_level === 3 && e.team_id) { if (!icsByTeamAndTitle.has(e.team_id)) icsByTeamAndTitle.set(e.team_id, new Map()); const byTitle = icsByTeamAndTitle.get(e.team_id)!; if (!byTitle.has(e.job_title)) byTitle.set(e.job_title, []); byTitle.get(e.job_title)!.push(e); } } const openByTeam = new Map(); for (const p of openPositions) { if (!openByTeam.has(p.team_id)) openByTeam.set(p.team_id, []); openByTeam.get(p.team_id)!.push(p); } return (
{ceo && ( toggle("root")}> Geschäftsführung besetzt: {ceo.first_name} {ceo.last_name} )} {expanded.has("root") && divisions.map((div) => { const head = divisionHeadByDivision.get(div.id); const divKey = `div-${div.id}`; return (
toggle(divKey)}> Bereichsleitung {div.name} {head ? `besetzt: ${head.first_name} ${head.last_name}` : "vakant"} {expanded.has(divKey) && departments .filter((d) => d.division_id === div.id) .map((dept) => { const deptKey = `dept-${dept.id}`; return (
toggle(deptKey)}> {dept.org_number} · {dept.name} {expanded.has(deptKey) && teams .filter((t) => t.department_id === dept.id) .map((team) => { const teamKey = `team-${team.id}`; const lead = teamLeadByTeam.get(team.id); const icsByTitle = icsByTeamAndTitle.get(team.id) ?? new Map(); const openForTeam = openByTeam.get(team.id) ?? []; return (
toggle(teamKey)}> Teamleitung {team.name} {lead ? `besetzt: ${lead.first_name} ${lead.last_name}` : "vakant"} {expanded.has(teamKey) && ( <> {Array.from(icsByTitle.entries()).map(([title, people]) => { const groupKey = `${teamKey}-${title}`; return (
0} expandedNow={expanded.has(groupKey)} onToggle={() => toggle(groupKey)} > {title} {people.length}x besetzt {expanded.has(groupKey) && people.map((p) => (
{p.first_name} {p.last_name}
))}
); })} {openForTeam.map((p) => ( + {p.position_number} · {p.title} ))} )}
); })}
); })}
); })}
); }