diff --git a/public/locale/en.json b/public/locale/en.json
index c827a055dd0..10179650df4 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -2112,6 +2112,8 @@
"use_phone_number_for_emergency": "Use this phone number for emergency contact",
"user_add_error": "Error while adding User",
"user_added_successfully": "User added successfully",
+ "user_count_one": "{{count}} user",
+ "user_count_other": "{{count}} users",
"user_delete_error": "Error while deleting User",
"user_deleted_successfully": "User Deleted Successfully",
"user_deleted_successfuly": "User Deleted Successfully",
@@ -2137,6 +2139,7 @@
"username_userdetails_not_found": "Unable to fetch details as username or user details not found",
"username_valid": "Username is valid",
"users": "Users",
+ "users_management": "Users Management",
"vacant": "Vacant",
"vaccinated": "Vaccinated",
"vaccine_name": "Vaccine name",
diff --git a/src/components/Facility/FacilityUsers.tsx b/src/components/Facility/FacilityUsers.tsx
index 4d4caed7e6e..696e1d06b9b 100644
--- a/src/components/Facility/FacilityUsers.tsx
+++ b/src/components/Facility/FacilityUsers.tsx
@@ -2,104 +2,202 @@ import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { useTranslation } from "react-i18next";
-import CountBlock from "@/CAREUI/display/Count";
+import CareIcon from "@/CAREUI/icons/CareIcon";
+import { Badge } from "@/components/ui/badge";
import { Card, CardContent } from "@/components/ui/card";
+import { Input } from "@/components/ui/input";
import { Skeleton } from "@/components/ui/skeleton";
+import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import Page from "@/components/Common/Page";
-import UserListView from "@/components/Users/UserListAndCard";
+import UserListAndCardView from "@/components/Users/UserListAndCard";
import useFilters from "@/hooks/useFilters";
import routes from "@/Utils/request/api";
import query from "@/Utils/request/query";
+const UserCardSkeleton = () => (
+
+
+ {Array.from({ length: 6 }).map((_, i) => (
+
+
+
+
+
+ ))}
+
+
+);
+
+const UserListSkeleton = () => (
+
+
+ {/* Header Skeleton */}
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ {/* Body Skeleton */}
+
+ {Array.from({ length: 7 }).map((_, i) => (
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+ ))}
+
+
+
+);
+
export default function FacilityUsers(props: { facilityId: string }) {
const { t } = useTranslation();
const { qParams, updateQuery, Pagination } = useFilters({
- limit: 18,
+ limit: 15,
cacheBlacklist: ["username"],
});
- const [activeTab, setActiveTab] = useState(0);
+ const [activeTab, setActiveTab] = useState<"card" | "list">("card");
const { facilityId } = props;
+ let usersList: JSX.Element = <>>;
+
const { data: userListData, isLoading: userListLoading } = useQuery({
- queryKey: ["facilityUsers", facilityId],
- queryFn: query(routes.facility.getUsers, {
+ queryKey: ["facilityUsers", facilityId, qParams],
+ queryFn: query.debounced(routes.facility.getUsers, {
pathParams: { facility_id: facilityId },
+ queryParams: {
+ username: qParams.username,
+ limit: qParams.limit,
+ offset: (qParams.page - 1) * qParams.limit,
+ },
}),
enabled: !!facilityId,
});
- if (userListLoading) {
- return (
-
-
-
-
-
- {Array.from({ length: 6 }).map((_, i) => (
-
-
-
-
-
- ))}
-
+ if (userListLoading || !userListData) {
+ usersList =
+ activeTab === "card" ?
:
;
+ } else {
+ usersList = (
+
);
}
- if (!userListData) {
- return
{t("no_users_found")}
;
- }
return (
-
-
-
- updateQuery({ username })}
- searchValue={qParams.username}
- activeTab={activeTab}
- onTabChange={setActiveTab}
- />
-
-
+
+ {t("user_count", { count: userListData?.count ?? 0 })}
+
+ }
+ >
+
+
+
updateQuery({ username: e.target.value })}
+ value={qParams.username}
+ placeholder={t("search_by_username")}
+ className="w-full max-w-sm"
+ />
+
setActiveTab(value as "card" | "list")}
+ className="ml-auto"
+ >
+
+
+
+
+ {t("card")}
+
+
+
+
+
+ {t("list")}
+
+
+
+
+
+ {usersList}
);
}
diff --git a/src/components/Users/UserListAndCard.tsx b/src/components/Users/UserListAndCard.tsx
index b1123f55d08..be13992ea2f 100644
--- a/src/components/Users/UserListAndCard.tsx
+++ b/src/components/Users/UserListAndCard.tsx
@@ -1,18 +1,15 @@
import { navigate } from "raviger";
import { useTranslation } from "react-i18next";
-import Card from "@/CAREUI/display/Card";
import CareIcon from "@/CAREUI/icons/CareIcon";
import { Badge } from "@/components/ui/badge";
+import { Card, CardContent } from "@/components/ui/card";
import { Avatar } from "@/components/Common/Avatar";
-import Tabs from "@/components/Common/Tabs";
-import SearchInput from "@/components/Form/SearchInput";
import useAuthUser from "@/hooks/useAuthUser";
import useSlug from "@/hooks/useSlug";
-import useWindowDimensions from "@/hooks/useWindowDimensions";
import {
formatName,
@@ -25,12 +22,13 @@ import { UserBase } from "@/types/user/user";
const GetDetailsButton = (username: string) => {
const { t } = useTranslation();
const facilityId = useSlug("facility");
+
return (
);
};
-const getNameAndStatusCard = (user: UserBase, showDetailsButton = false) => {
- return (
-
-
-
-
-
- {formatName(user)}
-
-
-
-
- {user.username}
-
-
-
{showDetailsButton && GetDetailsButton(user.username)}
-
-
- );
-};
export const UserStatusIndicator = ({
user,
@@ -102,55 +77,57 @@ export const UserStatusIndicator = ({
);
};
const UserCard = ({ user }: { user: UserBase }) => {
- const userOnline = isUserOnline(user);
- const { width } = useWindowDimensions();
- const mediumScreenBreakpoint = 640;
- const isMediumScreen = width <= mediumScreenBreakpoint;
- const isLessThanXLargeScreen = width <= 1280;
const { t } = useTranslation();
return (
-
-
-
-
-
-
- {isMediumScreen && getNameAndStatusCard(user, userOnline)}
-
-
- {!isMediumScreen &&
- getNameAndStatusCard(user, !isLessThanXLargeScreen)}
-
-
-
{t("role")}
-
- {user.user_type}
-
+
+
+
+
+
+
+
+
+ {user.first_name} {user.last_name}
+
+
+
+ {user.username}
+
+
+
+
+
+
{t("role")}
+
+ {user.user_type ?? "-"}
+
+
+
+
{t("phone_number")}
+
+ {formatPhoneNumber(user.phone_number) ?? "-"}
+
+
+
+
{GetDetailsButton(user.username)}
- {isLessThanXLargeScreen && (
- {GetDetailsButton(user.username)}
- )}
-
+
);
};
export const UserGrid = ({ users }: { users?: UserBase[] }) => (
-
+
{users?.map((user) => )}
);
@@ -236,66 +213,22 @@ export const UserList = ({ users }: { users?: UserBase[] }) => {
);
};
-interface UserListViewProps {
+interface UserListAndCardViewProps {
users: UserBase[];
- onSearch: (username: string) => void;
- searchValue: string;
- activeTab: number;
- onTabChange: (tab: number) => void;
+ activeTab: "card" | "list";
}
-export default function UserListView({
+export default function UserListAndCardView({
users,
- onSearch,
- searchValue,
activeTab,
- onTabChange,
-}: UserListViewProps) {
+}: UserListAndCardViewProps) {
const { t } = useTranslation();
return (
<>
-
-
- onSearch(e.value)}
- value={searchValue}
- placeholder={t("search_by_username")}
- />
-
-
-
- {t("card")}
-
- ),
- value: 0,
- id: "user-card-view",
- },
- {
- text: (
-
-
- {t("list")}
-
- ),
- value: 1,
- id: "user-list-view",
- },
- ]}
- currentTab={activeTab}
- onTabChange={(tab) => onTabChange(tab as number)}
- className="float-right"
- />
-
{users.length > 0 ? (
<>
- {activeTab === 0 ? (
+ {activeTab === "card" ? (
) : (