AkurAI Build
Menu

popagent

public

Latest change fadf21d1cd584745f6f92eaa60509e0bef19d242 - fix task orchestration and compact overview cards by AkurAI Build

import { useEffect, useState } from "react";
import { Building2, Mail, Users } from "lucide-react";
import type { CompanyDepartment, CompanyRosterResponse } from "../api-types";
import { apiFetch } from "./api";

export function CompanyRosterPanel() {
  const [departments, setDepartments] = useState<CompanyDepartment[]>();
  const [error, setError] = useState("");

  useEffect(() => {
    let active = true;
    void apiFetch("/api/company")
      .then(async (response) => {
        if (!response.ok) throw new Error("Unable to load company roster");
        const result = (await response.json()) as CompanyRosterResponse;
        if (active) setDepartments(result.departments);
      })
      .catch((reason: unknown) => {
        if (active) setError(reason instanceof Error ? reason.message : "Unable to load company roster");
      });
    return () => { active = false; };
  }, []);

  return <div className="w-full">
    <div className="flex flex-wrap items-end justify-between gap-3">
      <div>
        <div className="mb-2 flex items-center gap-2 text-xs font-medium uppercase tracking-[0.16em] text-accent"><Building2 className="size-4" />AkurAI company</div>
        <h1 className="text-xl font-semibold">Departments and staff</h1>
        <p className="mt-1 max-w-3xl text-sm text-ink-dim">Organizational identities recovered from the Midget staff directory. These people form company squads; they do not create additional LLM execution loops.</p>
      </div>
      {departments ? <span className="rounded-full border border-line bg-panel px-3 py-1.5 text-xs text-ink-muted"><Users className="mr-1.5 inline size-3.5" />{departments.reduce((count, department) => count + department.members.length, 0)} staff · {departments.length} departments</span> : null}
    </div>
    {error ? <div role="alert" className="mt-6 rounded border border-red-500/30 bg-red-500/10 p-4 text-sm text-red-400">{error}</div> : departments ? <div className="mt-6 grid items-start gap-4 xl:grid-cols-2">
      {departments.map((department) => <section key={department.id} className="overflow-hidden rounded border border-line bg-panel">
        <header className="flex items-center justify-between border-b border-line bg-panel-2 px-4 py-3">
          <h2 className="font-medium">{department.name}</h2>
          <span className="text-xs tabular-nums text-ink-dim">{department.members.length}</span>
        </header>
        <ul className="divide-y divide-line">
          {department.members.map((member) => <li key={member.id} className="flex min-w-0 items-center gap-3 px-4 py-3">
            <img src={member.avatarUrl} alt="" className="size-12 shrink-0 rounded-full border border-line object-cover bg-bg" />
            <div className="min-w-0 flex-1">
              <div className="truncate text-sm font-medium text-ink">{member.name}</div>
              <div className="truncate text-xs text-ink-muted">{member.title}</div>
            </div>
            <a href={`mailto:${member.email}`} aria-label={`Email ${member.name}`} className="flex size-10 shrink-0 items-center justify-center rounded text-ink-dim hover:bg-accent-soft hover:text-ink"><Mail className="size-4" /></a>
          </li>)}
        </ul>
      </section>)}
    </div> : <div className="mt-6 text-sm text-ink-dim">Loading company roster…</div>}
  </div>;
}