Skip to content

Commit

Permalink
Fix: Redesign the Open view of Department/Teams (#10558)
Browse files Browse the repository at this point in the history
  • Loading branch information
abhimanyurajeesh authored Feb 13, 2025
1 parent 6c5cefc commit 2c7e95f
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 95 deletions.
7 changes: 7 additions & 0 deletions public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,7 @@
"department": "Department",
"departments": "Departments",
"departments_and_teams": "Departments and Teams",
"departments_or_teams": "Departments/Teams",
"describe_why_the_asset_is_not_working": "Describe why the asset is not working",
"description": "Description",
"details_about_the_equipment": "Details about the equipment",
Expand Down Expand Up @@ -999,6 +1000,10 @@
"facility_linked_success": "Facility linked successfully",
"facility_name": "Facility Name",
"facility_not_found": "Facility Not Found",
"facility_organization_type__dept": "Department",
"facility_organization_type__other": "Other",
"facility_organization_type__root": "Root",
"facility_organization_type__team": "Team",
"facility_organizations": "Facility Organizations",
"facility_preference": "Facility preference",
"facility_search_placeholder_text": "Search by Facility name",
Expand Down Expand Up @@ -1898,6 +1903,7 @@
"scribe_error": "Could not autofill fields",
"search": "Search",
"search_by": "Search by",
"search_by_department_team_name": "Search by department/team name",
"search_by_emergency_contact_phone_number": "Search by Emergency Contact Phone Number",
"search_by_emergency_phone_number": "Search by Emergency Phone Number",
"search_by_name": "Search by Name",
Expand Down Expand Up @@ -1926,6 +1932,7 @@
"search_user_description": "Search for a user and assign a role to add them to the patient.",
"searching": "Searching...",
"see_attachments": "See Attachments",
"see_details": "See Details",
"see_note": "See Note",
"select": "Select",
"select_additional_instructions": "Select additional instructions",
Expand Down
130 changes: 70 additions & 60 deletions src/pages/Facility/settings/organizations/FacilityOrganizationView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";

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

import useFilters from "@/hooks/useFilters";

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

import CreateFacilityOrganizationSheet from "./components/CreateFacilityOrganizationSheet";
import FacilityOrganizationLayout from "./components/FacilityOrganizationLayout";
Expand All @@ -24,50 +26,89 @@ interface Props {
facilityId: string;
}

export default function FacilityOrganizationView({ id, facilityId }: Props) {
function OrganizationCard({
org,
}: {
org: FacilityOrganization;
facilityId: string;
}) {
const { t } = useTranslation();

const [page, setPage] = useState(1);
return (
<Card key={org.id}>
<CardContent className="p-4">
<div className="space-y-4">
<div className="flex items-center justify-between flex-wrap">
<div className="space-y-1 mb-2">
<h3 className="text-lg font-semibold">{org.name}</h3>
<div className="flex items-center gap-2 capitalize">
<Badge
variant="primary"
className=" border border-transparent text-indigo-800 bg-indigo-100 px-2 py-1"
>
{org.org_type}
</Badge>
</div>
</div>
<Button variant="white" size="sm" className="font-semibold" asChild>
<Link href={`/departments/${org.id}`}>{t("see_details")}</Link>
</Button>
</div>
</div>
</CardContent>
</Card>
);
}

export default function FacilityOrganizationView({ id, facilityId }: Props) {
const { t } = useTranslation();
const { qParams, Pagination, resultsPerPage } = useFilters({
limit: 12,
cacheBlacklist: ["username"],
});
const [searchQuery, setSearchQuery] = useState("");
const limit = 12; // 3x4 grid

const { data: children, isLoading } = useQuery({
queryKey: [
"facilityOrganization",
"list",
facilityId,
id,
page,
limit,
qParams.page,
resultsPerPage,
searchQuery,
],
queryFn: query.debounced(routes.facilityOrganization.list, {
pathParams: { facilityId },
queryParams: {
parent: id,
offset: (page - 1) * limit,
limit,
offset: ((qParams.page || 1) - 1) * resultsPerPage,
limit: resultsPerPage,
name: searchQuery || undefined,
},
}),
});

return (
<FacilityOrganizationLayout id={id} facilityId={facilityId}>
<div className="space-y-6">
<div className="space-y-6 mx-auto max-w-4xl">
<div className="flex flex-col lg:flex-row justify-between item-start lg:items-center gap-4">
<h2 className="text-lg font-semibold">{t("departments")}</h2>
<div className="flex flex-col items-center md:flex-row sm:items-center gap-4 w-full lg:justify-end">
<div className="w-full lg:w-1/3">
<Input
placeholder="Search by name..."
value={searchQuery}
onChange={(e) => {
setSearchQuery(e.target.value);
setPage(1); // Reset to first page on search
}}
className="w-full"
/>
<div className="flex flex-col items-start md:flex-row sm:items-center gap-4 w-full lg:justify-between">
<div className="w-full lg:w-1/3 relative">
<div className="relative">
<CareIcon
icon="l-search"
className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-500 h-4 w-4"
/>
<Input
placeholder={t("search_by_department_team_name")}
value={searchQuery}
onChange={(e) => {
setSearchQuery(e.target.value);
}}
className="w-full pl-8"
/>
</div>
</div>
<div className="w-auto">
<CreateFacilityOrganizationSheet
Expand All @@ -84,40 +125,14 @@ export default function FacilityOrganizationView({ id, facilityId }: Props) {
</div>
) : (
<div className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="space-y-4">
{children?.results?.length ? (
children.results.map((org) => (
<Card key={org.id}>
<CardContent className="p-6">
<div className="space-y-4">
<div className="flex items-center justify-between flex-wrap">
<div className="space-y-1 mb-2">
<h3 className="text-lg font-semibold">
{org.name}
</h3>
<div className="flex items-center gap-2">
<Badge variant="outline">{org.org_type}</Badge>
<Badge variant="outline">{org.org_type}</Badge>
</div>
</div>
<Button variant="link" asChild>
<Link href={`/departments/${org.id}`}>
{t("view_details")}
<CareIcon
icon="l-arrow-right"
className="h-4 w-4"
/>
</Link>
</Button>
</div>
{org.description && (
<p className="text-sm text-gray-500 line-clamp-2">
{org.description}
</p>
)}
</div>
</CardContent>
</Card>
<OrganizationCard
key={org.id}
org={org}
facilityId={facilityId}
/>
))
) : (
<Card className="col-span-full">
Expand All @@ -127,14 +142,9 @@ export default function FacilityOrganizationView({ id, facilityId }: Props) {
</Card>
)}
</div>
{children && children.count > limit && (
{children && children.count > resultsPerPage && (
<div className="flex justify-center">
<Pagination
data={{ totalCount: children.count }}
onChange={(page, _) => setPage(page)}
defaultPerPage={limit}
cPage={page}
/>
<Pagination totalCount={children.count} />
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { useQuery } from "@tanstack/react-query";
import { Link, usePath } from "raviger";
import { useTranslation } from "react-i18next";

import CareIcon, { IconName } from "@/CAREUI/icons/CareIcon";

import { Menubar, MenubarMenu, MenubarTrigger } from "@/components/ui/menubar";
import { Badge } from "@/components/ui/badge";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { Skeleton } from "@/components/ui/skeleton";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";

import Page from "@/components/Common/Page";
import { CardGridSkeleton } from "@/components/Common/SkeletonLoading";
Expand All @@ -25,7 +32,7 @@ interface Props {
interface NavItem {
path: string;
title: string;
icon: IconName;
value: string;
}

export default function FacilityOrganizationLayout({
Expand All @@ -34,20 +41,24 @@ export default function FacilityOrganizationLayout({
children,
}: Props) {
const path = usePath() || "";
const { t } = useTranslation();

const navItems: NavItem[] = [
{
path: `/departments/${id}`,
title: "Departments",
icon: "d-hospital",
title: t("departments_or_teams"),
value: "departments",
},
{
path: `/departments/${id}/users`,
title: "Users",
icon: "d-people",
title: t("users"),
value: "users",
},
];

const currentTab =
navItems.find((item) => item.path === path)?.value || "departments";

const { data: org, isLoading } = useQuery<FacilityOrganization>({
queryKey: ["facilityOrganization", id],
queryFn: query(routes.facilityOrganization.get, {
Expand All @@ -67,9 +78,9 @@ export default function FacilityOrganizationLayout({
</div>
);
}
// add loading state

if (!org) {
return <div>Not found</div>;
return <div>{t("not_found")}</div>;
}

const orgParents: FacilityOrganizationParent[] = [];
Expand All @@ -82,31 +93,74 @@ export default function FacilityOrganizationLayout({
}

return (
<Page title={`${org.name} `}>
{/* Navigation */}
<div className="mt-4">
<Menubar>
{navItems.map((item) => (
<MenubarMenu key={item.path}>
<MenubarTrigger
className={`${
path === item.path
? "font-medium text-primary-700 bg-gray-100"
: "hover:text-primary-500 hover:bg-gray-100 text-gray-700"
}`}
asChild
>
<Link href={item.path} className="cursor-pointer">
<CareIcon icon={item.icon} className="mr-2 h-4 w-4" />
{item.title}
<>
{orgParents.length > 0 && (
<div className="md:px-6 py-2 flex items-center gap-2 mx-auto max-w-4xl">
<Breadcrumb>
<BreadcrumbList>
{orgParents.reverse().map((parent) => (
<>
<BreadcrumbItem key={parent.id}>
<BreadcrumbLink
asChild
className="text-sm text-gray-900 hover:underline hover:underline-offset-2"
>
<Link href={parent.id}>{parent.name}</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbItem key={`ellipsis-${parent.id}`}>
<BreadcrumbSeparator />
</BreadcrumbItem>
</>
))}
<BreadcrumbItem key={org.id}>
<span className="text-sm font-semibold text-gray-900">
{org.name}
</span>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</div>
)}
<Page
title={org.name}
componentRight={
<Badge
variant="outline"
className="border border-transparent ml-2 text-indigo-800 bg-indigo-100 px-2 py-1 w-max"
>
{t(`facility_organization_type__${org.org_type}`)}
</Badge>
}
className="mx-auto max-w-4xl"
>
<div className="mt-2">
{org.description && (
<p className="text-sm text-gray-500 line-clamp-2">
{org.description}
</p>
)}
<Tabs
defaultValue={currentTab}
className="w-full mt-2"
value={currentTab}
>
<TabsList className="w-full justify-start border-b border-gray-300 bg-transparent p-0 h-auto rounded-none">
{navItems.map((item) => (
<Link key={item.path} href={item.path}>
<TabsTrigger
value={item.value}
className="border-b-2 border-transparent px-2 py-2 text-gray-600 hover:text-gray-900 data-[state=active]:text-primary-800 data-[state=active]:border-primary-700 data-[state=active]:bg-transparent data-[state=active]:shadow-none rounded-none"
>
{item.title}
</TabsTrigger>
</Link>
</MenubarTrigger>
</MenubarMenu>
))}
</Menubar>
</div>
{/* Page Content */}
<div className="mt-4">{children}</div>
</Page>
))}
</TabsList>
</Tabs>
</div>
<div className="mt-4">{children}</div>
</Page>
</>
);
}

0 comments on commit 2c7e95f

Please sign in to comment.