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

Implements useQuery & request data fetching utilities (used in Location Management page) #6269

Merged
merged 22 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
339d1b4
implement `useQuery` and `useMutation` hooks
rithviknishad Aug 11, 2023
7b36042
replace usages of `useSelector` with `useAuth` and `useConfig`
rithviknishad Aug 11, 2023
99485f5
Merge branch 'config-and-authuser-providers' into useQuery
rithviknishad Aug 11, 2023
fb29d2f
🧪 refine `useQuery` implementation
rithviknishad Aug 14, 2023
9e1e6b6
Merge branch 'develop' into config-and-authuser-providers
rithviknishad Aug 16, 2023
73987ef
Merge branch 'develop' into config-and-authuser-providers
khavinshankar Aug 16, 2023
35cc85e
refactor
rithviknishad Aug 16, 2023
2bdf621
implement `useQuery` and `useMutation` hooks
rithviknishad Aug 11, 2023
9e937b2
🧪 refine `useQuery` implementation
rithviknishad Aug 14, 2023
c74c468
refactor
rithviknishad Aug 16, 2023
8866a58
Merge branch 'useQuery' of github.com:coronasafe/care_fe into useQuery
rithviknishad Aug 16, 2023
2530e64
Merge branch 'develop' into useQuery
rithviknishad Aug 16, 2023
cc49058
Merge branch 'develop' into useQuery
rithviknishad Sep 7, 2023
59706b6
Merge branch 'develop' into useQuery
rithviknishad Sep 8, 2023
9757218
Merge branch 'develop' into useQuery
rithviknishad Sep 12, 2023
4d0e3c4
refactor location management
rithviknishad Sep 12, 2023
b035fd4
add paginator
rithviknishad Sep 12, 2023
59e5a81
remove unintended implementations
rithviknishad Sep 12, 2023
105ca02
Merge branch 'develop' into useQuery
rithviknishad Sep 12, 2023
c898f67
Merge branch 'develop' into useQuery
nihal467 Sep 13, 2023
08ed650
Update src/Components/Facility/LocationManagement.tsx
rithviknishad Sep 13, 2023
c18637a
apply changes based on QA
rithviknishad Sep 13, 2023
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
167 changes: 167 additions & 0 deletions src/CAREUI/misc/PaginatedList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { createContext, useContext, useState } from "react";
import { PaginatedResponse, QueryRoute } from "../../Utils/request/types";
import useQuery, { QueryOptions } from "../../Utils/request/useQuery";
import ButtonV2, {
CommonButtonProps,
} from "../../Components/Common/components/ButtonV2";
import CareIcon from "../icons/CareIcon";
import { classNames } from "../../Utils/utils";
import Pagination from "../../Components/Common/Pagination";

const DEFAULT_PER_PAGE_LIMIT = 14;

interface PaginatedListContext<TItem>
extends ReturnType<typeof useQuery<PaginatedResponse<TItem>>> {
items: TItem[];
perPage: number;
currentPage: number;
setPage: (page: number) => void;
}

const context = createContext<PaginatedListContext<object> | null>(null);

function useContextualized<TItem>() {
const ctx = useContext(context);

if (ctx === null) {
throw new Error("PaginatedList must be used within a PaginatedList");
}

return ctx as PaginatedListContext<TItem>;
}

interface Props<TItem> extends QueryOptions {
route: QueryRoute<PaginatedResponse<TItem>>;
perPage?: number;
children: (ctx: PaginatedListContext<TItem>) => JSX.Element | JSX.Element[];
}

export default function PaginatedList<TItem extends object>({
children,
route,
perPage = DEFAULT_PER_PAGE_LIMIT,
...queryOptions
}: Props<TItem>) {
const query = useQuery(route, {
...queryOptions,
query: { ...queryOptions.query, limit: perPage },
});
const [currentPage, setPage] = useState(1);

const items = query.data?.results ?? [];

return (
<context.Provider
value={{ ...query, items, perPage, currentPage, setPage }}
>
<context.Consumer>
{(ctx) => children(ctx as PaginatedListContext<TItem>)}
</context.Consumer>
</context.Provider>
);
}

interface WhenEmptyProps {
className?: string;
children: JSX.Element | JSX.Element[];
}

const WhenEmpty = <TItem extends object>(props: WhenEmptyProps) => {
const { items, loading } = useContextualized<TItem>();

if (loading || items.length > 0) {
return null;
}

return <div className={props.className}>{props.children}</div>;
};

PaginatedList.WhenEmpty = WhenEmpty;

const WhenLoading = <TItem extends object>(props: WhenEmptyProps) => {
const { loading } = useContextualized<TItem>();

if (!loading) {
return null;
}

return <div className={props.className}>{props.children}</div>;
};

PaginatedList.WhenLoading = WhenLoading;

const Refresh = ({ label = "Refresh", ...props }: CommonButtonProps) => {
const { loading, refetch } = useContextualized<object>();

return (
<ButtonV2
variant="secondary"
border
{...props}
onClick={() => refetch()}
disabled={loading}
>
<CareIcon
icon="l-sync"
className={classNames("text-lg", loading && "animate-spin")}
/>
<span>{label}</span>
</ButtonV2>
);
};

PaginatedList.Refresh = Refresh;

interface ItemsProps<TItem> {
className?: string;
children: (item: TItem) => JSX.Element | JSX.Element[];
shimmer?: JSX.Element;
shimmerCount?: number;
}

const Items = <TItem extends object>(props: ItemsProps<TItem>) => {
const { loading, items } = useContextualized<TItem>();

return (
<ul className={props.className}>
{loading && props.shimmer
? Array.from({ length: props.shimmerCount ?? 8 }).map((_, i) => (
<li key={i} className="w-full">
{props.shimmer}
</li>
))
: items.map((item, index) => (
<li key={index} className="w-full">
{props.children(item)}
</li>
))}
</ul>
);
};

PaginatedList.Items = Items;

interface PaginatorProps {
className?: string;
hideIfSinglePage?: boolean;
}

const Paginator = ({ className, hideIfSinglePage }: PaginatorProps) => {
const { data, perPage, currentPage, setPage } = useContextualized<object>();

if (hideIfSinglePage && (data?.count ?? 0) <= perPage) {
return null;
}

return (
<Pagination
className={className}
cPage={currentPage}
data={{ totalCount: data?.count ?? 0 }}
defaultPerPage={perPage}
onChange={setPage}
/>
);
};

PaginatedList.Paginator = Paginator;
2 changes: 1 addition & 1 deletion src/Components/Common/components/ButtonV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export default ButtonV2;

// Common buttons

type CommonButtonProps = ButtonProps & { label?: string };
export type CommonButtonProps = ButtonProps & { label?: string };

export const Submit = ({ label = "Submit", ...props }: CommonButtonProps) => {
const { t } = useTranslation();
Expand Down
Loading
Loading