Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #7316 : header is redesigned to be consistent in all pages #7324

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@
"last 1 safari version"
]
},

"lint-staged": {
"*.{ts,tsx,js,jsx}": [
"prettier --write --ignore-unknown",
Expand Down
28 changes: 27 additions & 1 deletion src/CAREUI/display/Count.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ interface Props {
icon: IconName;
className?: string;
}
interface HeaderCountProps {
count: number;
loading: boolean;
className?: string;
}

export default function CountBlock(props: Props) {
export function CountBlock(props: Props) {
return (
<div
className={classNames("rounded-lg bg-white p-4 shadow", props.className)}
Expand All @@ -34,3 +39,24 @@ export default function CountBlock(props: Props) {
</div>
);
}

export function HeaderCountBlock(props: HeaderCountProps) {
return (
<div
className={classNames(
"flex h-8 items-center rounded-lg bg-primary-300 px-4 text-lg font-bold ",
props.className
)}
>
<dl>
{props.loading ? (
<dd className="h-2 w-[5px] animate-pulse rounded-lg bg-black" />
) : (
<dd id="count" className="text-md font-black ">
{props.count}
</dd>
)}
</dl>
</div>
);
}
4 changes: 1 addition & 3 deletions src/CAREUI/interactive/FiltersSlideover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,15 @@ export default function FiltersSlideover({
}

export const AdvancedFilterButton = ({ onClick }: { onClick: () => void }) => {
const { t } = useTranslation();
return (
<ButtonV2
ghost
border
className="w-full bg-white sm:w-auto"
className="w-full bg-primary-100 sm:w-auto"
onClick={onClick}
id="advanced-filter"
>
<CareIcon className="care-l-filter" />
<span className="py-0.5">{t("advanced_filters")}</span>
</ButtonV2>
);
};
206 changes: 107 additions & 99 deletions src/Components/Assets/AssetsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ import AuthorizeFor, { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
import ButtonV2 from "../Common/components/ButtonV2";
import FacilitiesSelectDialogue from "../ExternalResult/FacilitiesSelectDialogue";
import ExportMenu from "../Common/Export";
import CountBlock from "../../CAREUI/display/Count";
import { HeaderCountBlock } from "../../CAREUI/display/Count";
import AssetImportModal from "./AssetImportModal";
import Page from "../Common/components/Page";
import { AdvancedFilterButton } from "../../CAREUI/interactive/FiltersSlideover";
import { useTranslation } from "react-i18next";
import request from "../../Utils/request/request";
import routes from "../../Redux/api";
import useQuery from "../../Utils/request/useQuery";
import Header from "../Common/components/Header.js";

const Loading = lazy(() => import("../Common/Loading"));

Expand Down Expand Up @@ -261,115 +262,122 @@ const AssetsList = () => {
title="Assets"
breadcrumbs={false}
hideBack
options={
<>
{authorizedForImportExport && (
<div className="tooltip" data-testid="import-asset-button">
<ExportMenu
label={importAssetModalOpen ? "Importing..." : "Import/Export"}
exportItems={[
{
label: "Import Assets",
options: {
icon: (
<CareIcon className="care-l-import import-assets-button" />
),
onClick: () => setImportAssetModalOpen(true),
},
},
{
label: "Export Assets (JSON)",
action: () =>
authorizedForImportExport &&
listAssets({
...qParams,
json: true,
limit: totalCount,
}),
type: "json",
filePrefix: `assets_${facility?.name ?? "all"}`,
options: {
icon: <CareIcon className="care-l-export" />,
disabled: totalCount === 0 || !authorizedForImportExport,
id: "export-json-option",
},
},
{
label: "Export Assets (CSV)",
action: () =>
authorizedForImportExport &&
listAssets({
...qParams,
csv: true,
limit: totalCount,
}),
type: "csv",
filePrefix: `assets_${facility?.name ?? "all"}`,
options: {
icon: <CareIcon className="care-l-export" />,
disabled: totalCount === 0 || !authorizedForImportExport,
id: "export-csv-option",
},
},
]}
/>
</div>
)}
</>
}
>
<div className="mt-5 gap-3 space-y-2 lg:flex">
<CountBlock
text="Total Assets"
componentRight={
<HeaderCountBlock
count={totalCount}
loading={loading}
icon="l-monitor-heart-rate"
className="flex-1"
className="ml-2"
/>
<div className="flex-1">
<SearchInput
name="search"
value={qParams.search}
onChange={(e) => updateQuery({ [e.name]: e.value })}
placeholder="Search by name/serial no./QR code ID"
/>
</div>
<div className="flex flex-col items-start justify-start gap-2 lg:ml-2">
<div className="flex w-full flex-col gap-2 md:flex-row lg:w-auto">
<div className="w-full">
<AdvancedFilterButton
onClick={() => advancedFilter.setShow(true)}
/>
</div>
}
options={
<Header
searchBox={
<SearchInput
name="search"
value={qParams.search}
onChange={(e) => updateQuery({ [e.name]: e.value })}
placeholder="Search by name/serial no./QR code ID"
/>
}
qrScan={
<ButtonV2
className="w-full py-[11px]"
onClick={() => setIsScannerActive(true)}
>
<CareIcon icon="l-search" className="mr-1 text-base" /> Scan Asset
QR
</ButtonV2>
</div>
<div
className="flex w-full flex-col md:flex-row"
data-testid="create-asset-buttom"
>
<ButtonV2
authorizeFor={NonReadOnlyUsers}
className="inline-flex w-full items-center justify-center"
onClick={() => {
if (qParams.facility) {
navigate(`/facility/${qParams.facility}/assets/new`);
} else {
setShowFacilityDialog(true);
}
}}
}
advancedFilter={
<AdvancedFilterButton
onClick={() => advancedFilter.setShow(true)}
/>
}
exportButton={
<>
{" "}
{authorizedForImportExport && (
<div className="tooltip" data-testid="import-asset-button">
<ExportMenu
label={
importAssetModalOpen ? "Importing..." : "Import/Export"
}
exportItems={[
{
label: "Import Assets",
options: {
icon: (
<CareIcon className="care-l-import import-assets-button" />
),
onClick: () => setImportAssetModalOpen(true),
},
},
{
label: "Export Assets (JSON)",
action: () =>
authorizedForImportExport &&
listAssets({
...qParams,
json: true,
limit: totalCount,
}),
type: "json",
filePrefix: `assets_${facility?.name ?? "all"}`,
options: {
icon: <CareIcon className="care-l-export" />,
disabled:
totalCount === 0 || !authorizedForImportExport,
id: "export-json-option",
},
},
{
label: "Export Assets (CSV)",
action: () =>
authorizedForImportExport &&
listAssets({
...qParams,
csv: true,
limit: totalCount,
}),
type: "csv",
filePrefix: `assets_${facility?.name ?? "all"}`,
options: {
icon: <CareIcon className="care-l-export" />,
disabled:
totalCount === 0 || !authorizedForImportExport,
id: "export-csv-option",
},
},
]}
/>
</div>
)}
</>
}
addComponentDetails={
<div
className="flex w-full flex-col md:flex-row"
data-testid="create-asset-buttom"
>
<CareIcon className="care-l-plus-circle text-lg" />
<span>{t("create_asset")}</span>
</ButtonV2>
</div>
</div>
</div>
<ButtonV2
authorizeFor={NonReadOnlyUsers}
className="inline-flex w-full items-center justify-center"
onClick={() => {
if (qParams.facility) {
navigate(`/facility/${qParams.facility}/assets/new`);
} else {
setShowFacilityDialog(true);
}
}}
>
<CareIcon className="care-l-plus-circle text-lg" />
<span className="lg:my-[2px]">{t("create_asset")}</span>
</ButtonV2>
</div>
}
/>
}
>
<AssetFilter {...advancedFilter} key={window.location.search} />
{isLoading ? (
<Loading />
Expand Down
36 changes: 36 additions & 0 deletions src/Components/Common/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
interface HeaderComponentProps {
searchBox: React.ReactNode;
secondarySearchBox?: React.ReactNode;
switchTabs?: React.ReactNode;
externalButton?: React.ReactNode;
advancedFilter: React.ReactNode;
sortDropDown?: React.ReactNode;
exportButton?: React.ReactNode;
addComponentDetails?: React.ReactNode;
qrScan?: React.ReactNode;
}
const Header = (props: HeaderComponentProps) => {
return (
<>
<div className="flex w-full flex-col items-center justify-between lg:flex-row">
<div className="mr-2 w-full">{props.searchBox}</div>
{props.secondarySearchBox && (
<div className="mr-2 w-full">{props.secondarySearchBox}</div>
)}
<div className="flex w-full flex-col items-center justify-end gap-2 lg:w-fit lg:flex-row">
{props.switchTabs && <> {props.switchTabs}</>}

{props.externalButton && <> {props.externalButton}</>}
{props.advancedFilter && <> {props.advancedFilter}</>}
{props.sortDropDown && <>{props.sortDropDown}</>}
{props.exportButton && <>{props.exportButton}</>}
<div className="mb-2 flex w-full flex-col items-center lg:mb-0 lg:w-fit lg:flex-row lg:gap-5">
{props.addComponentDetails && <>{props.addComponentDetails}</>}
</div>
</div>
</div>
</>
);
};

export default Header;
Loading