Skip to content

Commit

Permalink
Redesign: Departments page root view (#10411)
Browse files Browse the repository at this point in the history
Co-authored-by: Jacob John Jeevan <mail@jacobjeevan.me>
  • Loading branch information
DonXavierdev and Jacobjeevan authored Feb 26, 2025
1 parent a51d39c commit 6ffedec
Show file tree
Hide file tree
Showing 2 changed files with 277 additions and 37 deletions.
6 changes: 6 additions & 0 deletions public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -590,8 +590,12 @@
"clear_search": "Clear search",
"clear_selection": "Clear selection",
"clear_skill": "Clear Skill",
"click_add_department_team": "Click <strong>Add Department/Team</strong> to create a new department/team.",
"click_manage_create_users": "Click <strong>See Details</strong><CareIcon /> to create or manage users and departments/teams within the corresponding dept/team.",
"click_manage_create_users_mobile": "Click <CareIcon /> to create or manage users and departments/teams within the corresponding dept/team.",
"close": "Close",
"close_scanner": "Close Scanner",
"collapse_all": "Collapse All",
"collapse_sidebar": "Collapse Sidebar",
"combine_files_pdf": "Combine Files To PDF",
"comment_added_successfully": "Comment added successfully",
Expand Down Expand Up @@ -1057,6 +1061,7 @@
"exception_created": "Exception created successfully",
"exception_deleted": "Exception deleted",
"exceptions": "Exceptions",
"expand_all": "Expand All",
"expand_sidebar": "Expand Sidebar",
"expected_burn_rate": "Expected Burn Rate",
"expiration_date": "Expiration Date",
Expand Down Expand Up @@ -1143,6 +1148,7 @@
"filter_by": "Filter By",
"filter_by_category": "Filter by category",
"filter_by_date": "Filter by Date",
"filter_by_department_or_team_name": "Filter by department or team name",
"filters": "Filters",
"first_name": "First Name",
"food": "Food",
Expand Down
308 changes: 271 additions & 37 deletions src/pages/Facility/settings/organizations/FacilityOrganizationIndex.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { TooltipContent, TooltipTrigger } from "@radix-ui/react-tooltip";
import { TooltipProvider } from "@radix-ui/react-tooltip";
import { Tooltip } from "@radix-ui/react-tooltip";
import { useQuery } from "@tanstack/react-query";
import { Link } from "raviger";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Trans } from "react-i18next";

import CareIcon from "@/CAREUI/icons/CareIcon";

Expand All @@ -9,38 +14,45 @@ import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";

import Page from "@/components/Common/Page";
import { CardGridSkeleton } from "@/components/Common/SkeletonLoading";

import useBreakpoints from "@/hooks/useBreakpoints";

import routes from "@/Utils/request/api";
import query from "@/Utils/request/query";
import { FacilityOrganization } from "@/types/facilityOrganization/facilityOrganization";

import CreateFacilityOrganizationSheet from "./components/CreateFacilityOrganizationSheet";
import CreateFacilityOrganizationSheet from "@/pages/Facility/settings/organizations/components/CreateFacilityOrganizationSheet";

export default function FacilityOrganizationIndex({
facilityId,
}: {
facilityId: string;
}) {
const [expandedRows, setExpandedRows] = useState<Record<string, boolean>>({});
const { t } = useTranslation();
const { data, isLoading } = useQuery({
queryKey: ["facilityOrganization", "list", facilityId],
queryFn: query(routes.facilityOrganization.list, {
queryFn: query.paginated(routes.facilityOrganization.list, {
pathParams: { facilityId },
queryParams: {
parent: "",
},
}),
enabled: !!facilityId,
});

const tableData = data?.results || [];
const isMobile = useBreakpoints({ default: true, sm: false });
if (isLoading) {
return (
<div className="px-6 py-6 space-y-6">
Expand All @@ -53,7 +65,7 @@ export default function FacilityOrganizationIndex({
);
}

if (!data?.results?.length) {
if (!tableData?.length) {
return (
<Page title={t("organizations")} hideTitleOnPage={true}>
<div className="flex justify-center md:justify-end mt-2 mb-4">
Expand All @@ -80,38 +92,260 @@ export default function FacilityOrganizationIndex({
</Page>
);
}
const toggleRow = (id: string) => {
const newExpandedRows = { ...expandedRows };
newExpandedRows[id] = !newExpandedRows[id];
const children = getChildren(id);
children.forEach((child) => {
if (!child.has_children) {
newExpandedRows[child.id] = !newExpandedRows[child.id];
}
});
setExpandedRows(newExpandedRows);
};
const getChildren = (parentId: string) => {
return tableData.filter((org) => org.parent?.id === parentId);
};
const OrganizationRow = ({
org,
expandedRows,
toggleRow,
getChildren,
indent,
}: {
org: {
id: string;
name: string;
parent?: { id: string };
org_type: string;
};
expandedRows: Record<string, boolean>;
toggleRow: (id: string) => void;
getChildren: (parentId: string) => {
id: string;
name: string;
parent?: { id: string };
org_type: string;
}[];
indent: number;
}) => {
const children = getChildren(org.id);
const isTopLevel = !org.parent || Object.keys(org.parent).length === 0;

const toggleAllChildren = () => {
setExpandedRows((prevExpandedRows) => {
const newExpandedRows = { ...prevExpandedRows };
const toggleChildren = (parentId: string, expand: boolean) => {
getChildren(parentId).forEach((child) => {
newExpandedRows[child.id] = expand;
toggleChildren(child.id, expand);
});
};
const shouldExpand = !children.every(
(child) => prevExpandedRows[child.id],
);
newExpandedRows[org.id] = shouldExpand;
toggleChildren(org.id, shouldExpand);
return newExpandedRows;
});
};
const allExpanded = children.every((child) => expandedRows[child.id]);
return (
<>
<TableRow
key={org.id}
style={{ "--indent": `${indent}rem` } as React.CSSProperties}
>
<TableCell
className={`${
isTopLevel
? "bg-white font-bold text-gray-900"
: "bg-white font-medium text-gray-900"
} flex justify-between lg:flex-row flex-col pl-[var(--indent)] flex-wrap gap-2`}
>
<div className="flex items-center">
{isTopLevel || children.length > 0 ? (
<Button
size={"icon"}
variant={"link"}
onClick={() => toggleRow(org.id)}
disabled={children.length === 0}
>
{expandedRows[org.id] ? (
<CareIcon icon="l-angle-down" className="h-5 w-5" />
) : (
<CareIcon icon="l-angle-right" className="h-5 w-5" />
)}
</Button>
) : (
<CareIcon
icon="l-corner-down-right-alt"
className="h-4 w-4 text-gray-400 ml-4 mr-2"
/>
)}
<CareIcon
icon={isTopLevel ? "l-building" : "l-users-alt"}
className="mr-2"
/>
{org.name}
</div>

<div className="flex justify-between gap-5">
{isTopLevel && children.length > 0 && (
<div>
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<Button
variant="white"
size={isMobile ? "xs" : "sm"}
onClick={toggleAllChildren}
>
<CareIcon
icon={allExpanded ? "l-minus" : "l-plus"}
className="h-4 w-4 sm:h-2 sm:w-2"
/>
<span className="hidden sm:inline">
{t(allExpanded ? "collapse_all" : "expand_all")}
</span>
</Button>
</TooltipTrigger>
<TooltipContent>
{t(allExpanded ? "collapse_all" : "expand_all")}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
)}
<div className="ml-auto">
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<Button
variant="white"
size={isMobile ? "xs" : "sm"}
asChild
>
<Link
href={`/departments/${org.id}`}
className="text-gray-900 flex items-center"
>
<CareIcon
icon="l-arrow-up-right"
className="h-4 w-4"
/>
<span className="hidden sm:inline">
{t("see_details")}
</span>
</Link>
</Button>
</TooltipTrigger>
<TooltipContent>{t("see_details")}</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</div>
</TableCell>
{!isMobile && (
<TableCell className="border-l bg-white font-semibold text-gray-900">
{t(`facility_organization_type__${org.org_type}`)}
</TableCell>
)}
</TableRow>
{expandedRows[org.id] &&
children.map((child) => (
<OrganizationRow
key={child.id}
org={child}
expandedRows={expandedRows}
toggleRow={toggleRow}
getChildren={getChildren}
indent={indent + 1}
/>
))}
</>
);
};
return (
<Page title={t("departments")} hideTitleOnPage={true}>
<div className="flex justify-center md:justify-end mt-2 mb-4">
<CreateFacilityOrganizationSheet facilityId={facilityId} />
<h3 className="mb-4 text-black">{t("departments")}</h3>
<div className="flex justify-between items-center mb-4 gap-5 lg:flex-row flex-col-reverse ">
<div className="lg:w-3/4 w-full">
<Input
className="px-2 placeholder:text-xs placeholder:text-gray-500"
placeholder={t("filter_by_department_or_team_name")}
></Input>
</div>
<div className="flex lg:justify-end w-full">
<CreateFacilityOrganizationSheet facilityId={facilityId} />
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pb-4">
{data.results.map((org: FacilityOrganization) => (
<Card key={org.id} className="relative group">
<CardHeader>
<div className="flex items-start justify-between">
<CardTitle className="flex items-center gap-2">
{org.name}
</CardTitle>
<CardDescription>{org.org_type}</CardDescription>
</div>
</CardHeader>

<CardFooter>
<Button variant="outline" asChild className="w-full">
<Link
href={`/departments/${org.id}`}
className="flex items-center justify-center gap-2"
>
{t("view_details")}
<CareIcon icon="l-arrow-right" className="h-4 w-4" />
</Link>
</Button>
</CardFooter>
</Card>
))}
<div className="items-center flex gap-3 text-blue-800 text-xs sm:text-sm border-2 rounded-lg border-blue-200 bg-blue-50 p-4 mb-4">
<div className="sm:p-2 p-1 bg-blue-100 rounded-sm">
<CareIcon icon="l-info-circle" className="h-6 w-6 text-blue-900" />
</div>
<div className="flex-1 space-y-2 text-xs md:text-sm text-blue-800">
<div className="flex flex-wrap items-center">
<Trans
i18nKey="click_add_department_team"
components={{
strong: <strong className="font-semibold mx-0.5" />,
}}
/>
</div>
<div className="hidden lg:flex flex-wrap items-center">
<Trans
i18nKey="click_manage_create_users"
components={{
strong: <strong className="font-semibold ml-1" />,
CareIcon: (
<CareIcon icon="l-arrow-up-right" className="h-4 w-4 mr-1" />
),
}}
/>
</div>
<div className="flex flex-wrap lg:hidden items-center">
<Trans
i18nKey="click_manage_create_users_mobile"
components={{
CareIcon: (
<CareIcon icon="l-arrow-up-right" className="h-4 w-4" />
),
}}
/>
</div>
</div>
</div>
<Table className="border rounded-lg w-full overflow-hidden">
<TableHeader>
<TableRow>
<TableHead className="w-[80%] border text-gray-700 bg-gray-200">
{t("name")}
</TableHead>
{!isMobile && (
<TableHead className="bg-gray-200 text-gray-700">
{t("category")}
</TableHead>
)}
</TableRow>
</TableHeader>
<TableBody>
{tableData
.filter(
(org) => !org.parent || Object.keys(org.parent).length === 0,
) // Parent rows only
.map((parent) => (
<OrganizationRow
key={parent.id}
org={parent}
expandedRows={expandedRows}
toggleRow={toggleRow}
getChildren={getChildren}
indent={1}
/>
))}
</TableBody>
</Table>
</Page>
);
}

0 comments on commit 6ffedec

Please sign in to comment.