diff --git a/src/CAREUI/interactive/FiltersSlideover.tsx b/src/CAREUI/interactive/FiltersSlideover.tsx index 959fd0621e8..c6ee12e6df3 100644 --- a/src/CAREUI/interactive/FiltersSlideover.tsx +++ b/src/CAREUI/interactive/FiltersSlideover.tsx @@ -4,6 +4,8 @@ import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; import SlideOver from "@/CAREUI/interactive/SlideOver"; +import { Button } from "@/components/ui/button"; + import ButtonV2 from "@/components/Common/ButtonV2"; import useFilters from "@/hooks/useFilters"; @@ -58,15 +60,15 @@ export default function FiltersSlideover({ export const AdvancedFilterButton = ({ onClick }: { onClick: () => void }) => { const { t } = useTranslation(); return ( - {t("advanced_filters")} - + ); }; diff --git a/src/components/Assets/AssetsList.tsx b/src/components/Assets/AssetsList.tsx index c0e47610766..edb9de0458d 100644 --- a/src/components/Assets/AssetsList.tsx +++ b/src/components/Assets/AssetsList.tsx @@ -11,14 +11,13 @@ import { AdvancedFilterButton } from "@/CAREUI/interactive/FiltersSlideover"; import AssetFilter from "@/components/Assets/AssetFilter"; import AssetImportModal from "@/components/Assets/AssetImportModal"; import { AssetData, assetClassProps } from "@/components/Assets/AssetTypes"; -import ButtonV2 from "@/components/Common/ButtonV2"; import ExportMenu from "@/components/Common/Export"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; import FacilitiesSelectDialogue from "@/components/ExternalResult/FacilitiesSelectDialogue"; import { FacilityModel } from "@/components/Facility/models"; -import SearchInput from "@/components/Form/SearchInput"; +import useAuthUser from "@/hooks/useAuthUser"; import useFilters from "@/hooks/useFilters"; import { useIsAuthorized } from "@/hooks/useIsAuthorized"; @@ -29,6 +28,9 @@ import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; +import SearchByMultipleFields from "../Common/SearchByMultipleFields"; +import { Button } from "../ui/button"; + const AssetsList = () => { const { t } = useTranslation(); const { @@ -38,9 +40,10 @@ const AssetsList = () => { FilterBadges, advancedFilter, resultsPerPage, + clearSearch, } = useFilters({ limit: 18, - cacheBlacklist: ["search"], + cacheBlacklist: ["name", "serial_number", "qr_code_id"], }); const [assets, setAssets] = useState([{} as AssetData]); const [isLoading, setIsLoading] = useState(false); @@ -56,6 +59,9 @@ const AssetsList = () => { const params = { limit: resultsPerPage, page: qParams.page, + name: qParams.name || "", + serial_number: qParams.serial_number || "", + qr_code_id: qParams.qr_code_id || "", offset: (qParams.page ? qParams.page - 1 : 0) * resultsPerPage, search_text: qParams.search || "", facility: qParams.facility || "", @@ -114,6 +120,9 @@ const AssetsList = () => { }, ); + const authUser = useAuthUser(); + const isDisabled = !NonReadOnlyUsers(authUser.user_type); + function isValidURL(url: string) { try { new URL(url); @@ -311,108 +320,50 @@ const AssetsList = () => { ); } + const searchOptions = [ + { + key: "name", + label: "Name", + type: "text" as const, + placeholder: "Search by Name", + value: qParams.name || "", + shortcutKey: "n", + }, + { + key: "serial_number", + label: "Serial No.", + type: "text" as const, + placeholder: "Search by Serial No.", + value: qParams.serial_number || "", + shortcutKey: "u", + }, + { + key: "asset_qr_id", + label: "QR Code ID", + type: "text" as const, + placeholder: "Search by QR Code ID", + value: qParams.qr_code_id || "", + shortcutKey: "p", + }, + ]; + return ( - {authorizedForImportExport && ( -
- - ), - onClick: () => setImportAssetModalOpen(true), - }, - }, - { - label: "Export Assets (JSON)", - action: async () => { - const { data } = await request(routes.listAssets, { - query: { ...qParams, json: true, limit: totalCount }, - }); - return data ?? null; - }, - type: "json", - filePrefix: `assets_${facility?.name ?? "all"}`, - options: { - icon: , - disabled: totalCount === 0 || !authorizedForImportExport, - id: "export-json-option", - }, - }, - { - label: "Export Assets (CSV)", - action: async () => { - const { data } = await request(routes.listAssets, { - query: { ...qParams, csv: true, limit: totalCount }, - }); - return data ?? null; - }, - type: "csv", - filePrefix: `assets_${facility?.name ?? "all"}`, - options: { - icon: , - disabled: totalCount === 0 || !authorizedForImportExport, - id: "export-csv-option", - }, - }, - ]} - /> -
- )} - - } - > -
- -
- updateQuery({ [e.name]: e.value })} - placeholder="Search by name/serial no./QR code ID" - /> -
-
-
-
- advancedFilter.setShow(true)} - /> -
- setIsScannerActive(true)} - > - Scan Asset - QR - -
+
- { if (qParams.facility) { navigate(`/facility/${qParams.facility}/assets/new`); @@ -423,9 +374,103 @@ const AssetsList = () => { > {t("create_asset")} - + +
+
+ advancedFilter.setShow(true)} + /> + + + +
+ {authorizedForImportExport && ( + + ), + onClick: () => setImportAssetModalOpen(true), + }, + }, + { + label: "Export Assets (JSON)", + action: async () => { + const { data } = await request(routes.listAssets, { + query: { ...qParams, json: true, limit: totalCount }, + }); + return data ?? null; + }, + type: "json", + filePrefix: `assets_${facility?.name ?? "all"}`, + options: { + icon: , + disabled: + totalCount === 0 || !authorizedForImportExport, + id: "export-json-option", + }, + }, + { + label: "Export Assets (CSV)", + action: async () => { + const { data } = await request(routes.listAssets, { + query: { ...qParams, csv: true, limit: totalCount }, + }); + return data ?? null; + }, + type: "csv", + filePrefix: `assets_${facility?.name ?? "all"}`, + options: { + icon: , + disabled: + totalCount === 0 || !authorizedForImportExport, + id: "export-csv-option", + }, + }, + ]} + /> + )} +
+ } + > +
+ + + updateQuery({ search: value })} + clearSearch={clearSearch} + className="w-full" + />
{isLoading ? ( diff --git a/src/components/Common/Export.tsx b/src/components/Common/Export.tsx index 6cd786977ed..2c5f7849057 100644 --- a/src/components/Common/Export.tsx +++ b/src/components/Common/Export.tsx @@ -1,15 +1,24 @@ +import { cn } from "@/lib/utils"; + import CareIcon from "@/CAREUI/icons/CareIcon"; -import ButtonV2 from "@/components/Common/ButtonV2"; -import DropdownMenu, { - DropdownItem, - DropdownItemProps, -} from "@/components/Common/Menu"; +import { DropdownItemProps } from "@/components/Common/Menu"; import useExport from "@/hooks/useExport"; +import { useIsAuthorized } from "@/hooks/useIsAuthorized"; +import { Anyone, AuthorizedForCB } from "@/Utils/AuthorizeFor"; import request from "@/Utils/request/request"; import { Route } from "@/Utils/request/types"; +import { classNames } from "@/Utils/utils"; + +import { Button } from "../ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "../ui/dropdown-menu"; interface ExportItem { options?: DropdownItemProps; @@ -22,9 +31,11 @@ interface ExportItem { } interface ExportMenuProps { + variant?: string; disabled?: boolean | undefined; label?: string; exportItems: ExportItem[]; + authorizeFor?: AuthorizedForCB | undefined; } interface ExportButtonProps { @@ -42,14 +53,17 @@ export const ExportMenu = ({ label = "Export", disabled, exportItems, + authorizeFor = Anyone, }: ExportMenuProps) => { const { isExporting, exportFile } = useExport(); + const isAuthorized = useIsAuthorized(authorizeFor); if (exportItems.length === 1) { const item = exportItems[0]; return ( - { let action = item.action; @@ -63,44 +77,68 @@ export const ExportMenu = ({ exportFile(action, item.filePrefix, item.type, item.parse); } }} - border - ghost className="py-2.5" > {isExporting ? "Exporting..." : label} - + ); } return ( -
- } - className="tooltip border-primary-500 bg-white text-primary-500 hover:bg-primary-100 enabled:border" - > - {exportItems.map((item) => ( - { - let action = item.action; - if (item.route) { - action = async () => { - const { data } = await request(item.route!); - return data ?? null; - }; - } - if (action) { - exportFile(action, item.filePrefix, item.type, item.parse); - } - }} - {...item.options} +
+ + + + + {label !== "Importing..." && ( + + {exportItems.map((item) => ( +
{ + let action = item.action; + if (item.route) { + action = async () => { + const { data } = await request(item.route!); + return data ?? null; + }; + } + if (action) { + exportFile(action, item.filePrefix, item.type, item.parse); + } + }} + {...item.options} + > + +
+ {item.options?.icon} + {item.label} +
+
+
+ ))} +
+ )}
); @@ -116,7 +154,7 @@ export const ExportButton = ({ return ( <> - { let action = props.action; @@ -132,8 +170,6 @@ export const ExportButton = ({ }} className="tooltip mx-2 p-4 text-lg text-secondary-800 disabled:bg-transparent disabled:text-secondary-500" variant="secondary" - ghost - circle > {isExporting ? ( @@ -143,7 +179,7 @@ export const ExportButton = ({ {props.tooltip || "Export"} - + ); };