Añadir componente PersonAvatarGroup para mostrar avatares de personas en la sección de departamentos

This commit is contained in:
David Arranz 2026-10-09 23:02:52 +02:00
parent d8fdad11e6
commit a622eacfe7
5 changed files with 25 additions and 12 deletions

View File

@ -11,6 +11,7 @@ import { useTranslation } from "react-i18next";
import type { CompanyDTO } from "../../../../common";
import { DepartmentEditorDialog } from "../../shared";
import { PersonAvatarGroup } from "../../../people";
export function DepartmentSection({
company,
@ -56,15 +57,13 @@ export function DepartmentSection({
company.assignments.filter(
(entry) => entry.departmentId === item.id && entry.endDate === null
).length,
render: (item) => (
<>
{
company.assignments.filter(
(entry) => entry.departmentId === item.id && entry.endDate === null
).length
}
</>
),
render: (item) => {
const people = company.assignments
.filter((entry) => entry.departmentId === item.id && entry.endDate === null)
.map((entry) => company.people.find((person) => person.id === entry.personId))
.filter((person): person is CompanyDTO["people"][number] => Boolean(person));
return <PersonAvatarGroup companyId={company.id} people={people} peopleLabel={t("people")} />;
},
},
{
id: "actions",

View File

@ -1,2 +1,2 @@
export { PeopleSection } from "./list";
export { PersonEditorDialog, PersonForm } from "./shared";
export { PersonEditorDialog, PersonForm, PersonAvatarGroup } from "./shared";

View File

@ -1 +1 @@
export { PersonEditorDialog, PersonForm, PersonAvatar } from "./ui";
export { PersonEditorDialog, PersonForm, PersonAvatar, PersonAvatarGroup } from "./ui";

View File

@ -1,4 +1,4 @@
export { PersonEditorDialog } from "./person-editor-dialog";
export { PersonForm } from "./person-form";
export { PersonAvatar } from "./person-avatar";
export { PersonAvatar, PersonAvatarGroup } from "./person-avatar";

View File

@ -4,3 +4,17 @@ export function PersonAvatar({ companyId, personId, photoVersion, name, classNam
const src = photoVersion ? `/api/companies/${companyId}/people/${personId}/photo?version=${photoVersion}` : undefined;
return <Avatar className={className}><AvatarImage src={src} alt="" /><AvatarFallback>{initials}</AvatarFallback></Avatar>;
}
export function PersonAvatarGroup({ companyId, people, max = 3, peopleLabel = "Personas" }: { companyId: string; people: readonly { id: string; name: string; photoVersion?: string | null | undefined }[]; max?: number; peopleLabel?: string }) {
const visible = people.slice(0, max);
const remaining = people.length - visible.length;
if (!people.length) return <span className="text-muted-foreground">—</span>;
return (
<div className="flex items-center" aria-label={`${people.length} ${peopleLabel}`}>
<div className="flex -space-x-2">
{visible.map((person) => <PersonAvatar key={person.id} companyId={companyId} personId={person.id} photoVersion={person.photoVersion} name={person.name} className="size-8 border-2 border-background" />)}
</div>
{remaining > 0 && <span className="ml-2 inline-flex size-8 items-center justify-center rounded-full bg-muted text-xs font-medium text-muted-foreground">+{remaining}</span>}
</div>
);
}