"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}
))}
>
)}
);
})}
);
})}
);
})}
);
}