diff --git a/frontend/package.json b/frontend/package.json
index 4355a31c..87033ec7 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -8,6 +8,7 @@
"build": "next build",
"start": "next start",
"lint": "eslint",
+ "test": "node --experimental-strip-types --test src/**/*.test.ts",
"postinstall": "cp node_modules/pdfjs-dist/build/pdf.worker.min.mjs public/pdf.worker.min.mjs || true"
},
"dependencies": {
diff --git a/frontend/src/app/departments/[id]/page.tsx b/frontend/src/app/departments/[id]/page.tsx
index 3c5cbfab..0cdffc88 100644
--- a/frontend/src/app/departments/[id]/page.tsx
+++ b/frontend/src/app/departments/[id]/page.tsx
@@ -18,6 +18,10 @@ import {
} from "lucide-react";
import { AppShell } from "@/components/AppShell";
+import {
+ DEPARTMENT_MEMBERS_EMPTY_STATE_CLASSNAME,
+ getDepartmentMembersListClassName,
+} from "@/components/departments/layout";
import { RequestAvatar } from "@/components/requests/RequestAvatar";
import { SearchableSelectSingle } from "@/components/shared/SearchableSelect";
import { Modal } from "@/components/ui/Modal";
@@ -367,6 +371,20 @@ function DepartmentEditorModal({
);
}
+function DepartmentMembersEmptyState() {
+ return (
+
+
+
+ Участники не найдены
+
+
+ Измени поисковый запрос.
+
+
+ );
+}
+
function AddMemberModal({
isOpen,
items,
@@ -707,13 +725,7 @@ export default function DepartmentDetailPage() {
) : null}
-
+
{h.filteredMembers.length ? (
h.filteredMembers.map((member) => (
))
) : (
-
-
-
- Участники не найдены
-
-
- Измени поисковый запрос.
-
-
+
)}
diff --git a/frontend/src/components/departments/layout.test.ts b/frontend/src/components/departments/layout.test.ts
new file mode 100644
index 00000000..3bc3e84f
--- /dev/null
+++ b/frontend/src/components/departments/layout.test.ts
@@ -0,0 +1,22 @@
+import test from "node:test";
+import assert from "node:assert/strict";
+
+import {
+ DEPARTMENT_MEMBERS_EMPTY_STATE_CLASSNAME,
+ getDepartmentMembersListClassName,
+} from "./layout.ts";
+
+test("showcase members layout keeps bubble flow", () => {
+ assert.equal(
+ getDepartmentMembersListClassName(false),
+ "flex flex-wrap items-center gap-2",
+ );
+});
+
+test("management members layout keeps stacked editing rows", () => {
+ assert.equal(getDepartmentMembersListClassName(true), "space-y-3");
+});
+
+test("department empty state spans full section width", () => {
+ assert.match(DEPARTMENT_MEMBERS_EMPTY_STATE_CLASSNAME, /\bw-full\b/);
+});
diff --git a/frontend/src/components/departments/layout.ts b/frontend/src/components/departments/layout.ts
new file mode 100644
index 00000000..20751e0b
--- /dev/null
+++ b/frontend/src/components/departments/layout.ts
@@ -0,0 +1,8 @@
+export function getDepartmentMembersListClassName(isManagementMode: boolean) {
+ return isManagementMode
+ ? "space-y-3"
+ : "flex flex-wrap items-center gap-2";
+}
+
+export const DEPARTMENT_MEMBERS_EMPTY_STATE_CLASSNAME =
+ "app-surface-muted w-full rounded-xl p-8 text-center";