);
}
diff --git a/apps/as/src/pages/instl-sncn/ui/instl-view-page.tsx b/apps/as/src/pages/instl-sncn/ui/instl-view-page.tsx
index 6e5bd3eca..6a4f5ad2b 100644
--- a/apps/as/src/pages/instl-sncn/ui/instl-view-page.tsx
+++ b/apps/as/src/pages/instl-sncn/ui/instl-view-page.tsx
@@ -3,10 +3,15 @@
import { useMemo, useRef } from "react";
import { useUserStore } from "@/shared/lib";
+import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui";
import { ElaprDocPrgrsStatus } from "@/entities/elapr";
import { useInstlSncnDetail } from "@/entities/instl-sncn";
import { useRvwMnpwMngLoginUserList } from "@/entities/rvw-mnpw";
-import { AttachmentsViewSection, ProgressStatusSection, SupplementDemandSection } from "@/widgets/pbadms-sprt";
+import {
+ AttachmentsViewSection,
+ ProgressStatusSection,
+ SupplementDemandSection,
+} from "@/widgets/pbadms-sprt";
import { Skeleton } from "@common/components";
import { needsRoleUser01AtrzResolve } from "../lib/button-config";
@@ -88,48 +93,53 @@ function InstlViewPage({ id }: InstlViewPageProps) {
);
return (
-
-
-
-
-
-
-
-
-
-
-
-
+
);
}
diff --git a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-view-page.tsx b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-view-page.tsx
index 63b61052b..3099c4c37 100644
--- a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-view-page.tsx
+++ b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-view-page.tsx
@@ -3,10 +3,15 @@
import { useMemo, useRef } from "react";
import { useUserStore } from "@/shared/lib";
+import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui";
import { ElaprDocPrgrsStatus } from "@/entities/elapr";
import { useRvwMnpwMngLoginUserList } from "@/entities/rvw-mnpw";
import { useSewerBscPlanDetails } from "@/entities/sewer-bsc-plan";
-import { AttachmentsViewSection, ProgressStatusSection, SupplementDemandSection } from "@/widgets/pbadms-sprt";
+import {
+ AttachmentsViewSection,
+ ProgressStatusSection,
+ SupplementDemandSection,
+} from "@/widgets/pbadms-sprt";
import { Skeleton } from "@common/components";
import { needsRoleUser01AtrzResolve } from "../lib/button-config";
@@ -95,48 +100,53 @@ function SewerBscPlanViewPage({ id, propChgCycl }: SewerBscPlanViewPageProps) {
);
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/apps/as/src/shared/ui/index.ts b/apps/as/src/shared/ui/index.ts
index 577618146..813bcafd5 100644
--- a/apps/as/src/shared/ui/index.ts
+++ b/apps/as/src/shared/ui/index.ts
@@ -1,5 +1,9 @@
export { NoData } from "./no-data";
export { PageLayout } from "./page-layout";
export { SectionCollapsible } from "./section-collapsible";
+export {
+ SectionCollapsibleGroup,
+ SectionCollapsibleToggle,
+} from "./section-collapsible-group";
export type { TextShimmerProps } from "./text-shimmer";
export { TEXT_SHIMMER_CLASS, TextShimmer } from "./text-shimmer";
diff --git a/apps/as/src/shared/ui/section-collapsible-group.tsx b/apps/as/src/shared/ui/section-collapsible-group.tsx
new file mode 100644
index 000000000..88828e335
--- /dev/null
+++ b/apps/as/src/shared/ui/section-collapsible-group.tsx
@@ -0,0 +1,89 @@
+"use client";
+
+import { createContext, type ReactNode, useCallback, useContext, useMemo, useState } from "react";
+
+import { ChevronsDownUp, ChevronsUpDown } from "lucide-react";
+
+import { Button } from "@common/components";
+
+interface SectionCollapsibleGroupValue {
+ batchOpen: boolean;
+ batchVersion: number;
+ expandAll: () => void;
+ collapseAll: () => void;
+}
+
+const SectionCollapsibleGroupContext = createContext
(null);
+
+function useSectionCollapsibleGroup() {
+ return useContext(SectionCollapsibleGroupContext);
+}
+
+interface SectionCollapsibleGroupProps {
+ children: ReactNode;
+}
+
+function SectionCollapsibleGroup({ children }: SectionCollapsibleGroupProps) {
+ const [batch, setBatch] = useState({ open: true, version: 0 });
+
+ const expandAll = useCallback(() => {
+ setBatch((prev) => ({ open: true, version: prev.version + 1 }));
+ }, []);
+
+ const collapseAll = useCallback(() => {
+ setBatch((prev) => ({ open: false, version: prev.version + 1 }));
+ }, []);
+
+ const value = useMemo(
+ () => ({
+ batchOpen: batch.open,
+ batchVersion: batch.version,
+ expandAll,
+ collapseAll,
+ }),
+ [batch.open, batch.version, expandAll, collapseAll],
+ );
+
+ return (
+
+ {children}
+
+ );
+}
+
+function SectionCollapsibleToggle() {
+ const group = useSectionCollapsibleGroup();
+
+ if (!group) return null;
+
+ const { batchOpen, expandAll, collapseAll } = group;
+
+ return (
+
+
+
+
+ );
+}
+
+export { SectionCollapsibleGroup, SectionCollapsibleToggle, useSectionCollapsibleGroup };
diff --git a/apps/as/src/shared/ui/section-collapsible.tsx b/apps/as/src/shared/ui/section-collapsible.tsx
index 2d9d6f27e..9b6fa050b 100644
--- a/apps/as/src/shared/ui/section-collapsible.tsx
+++ b/apps/as/src/shared/ui/section-collapsible.tsx
@@ -1,11 +1,13 @@
"use client";
-import type { ReactNode } from "react";
+import { type ReactNode, useState } from "react";
import { ChevronDown } from "lucide-react";
import { cn, Collapsible, CollapsibleContent, CollapsibleTrigger } from "@common/components";
+import { useSectionCollapsibleGroup } from "./section-collapsible-group";
+
interface SectionCollapsibleProps {
title: ReactNode;
defaultOpen?: boolean;
@@ -13,8 +15,19 @@ interface SectionCollapsibleProps {
}
function SectionCollapsible({ title, defaultOpen = true, children }: SectionCollapsibleProps) {
+ const group = useSectionCollapsibleGroup();
+ const [open, setOpen] = useState(group?.batchOpen ?? defaultOpen);
+ const [seenVersion, setSeenVersion] = useState(group?.batchVersion ?? 0);
+
+ if (group && group.batchVersion !== seenVersion) {
+ setSeenVersion(group.batchVersion);
+ setOpen(group.batchOpen);
+ }
+
+ const collapsibleProps = group ? { open, onOpenChange: setOpen } : { defaultOpen };
+
return (
-
+