saleor-dashboard/src/hooks/usePaginator.ts
Dawid 1621feb691
Apps marketplace (#2850)
* Add new Apps List

* Update apps routing

* Add marketplace apps list

* Update apps urls

* Update app list style

* Add installed apps section

* Update apps sections and connect actions with mutations

* Add latest missing buttons and labels to installed apps list

* Update installed apps list

* Update installed apps list

* Add tests and marketplace error handling

* Update environment configuration

* Update GitHub actions env configuration

* Refactor AppListCard component

* Test InstallWithManifestFormButton

* Test AppListCard

* Extract InstalledAppListRow with tests

* Update GitHub actions env configuration

* Tests of apps dialogs

* Update GitHub actions env configuration

* Update messages

* Update GitHub actions env configuration

* Quote untrusted GitHub actions variables

* Change useFetch to useMarketplaceApps and add tests

* Fix strict null check errors

* Refactor apps details components

* Add strict null checks for /new-apps/ components
2023-01-10 11:04:30 +01:00

141 lines
3.1 KiB
TypeScript

import { stringifyQs } from "@saleor/utils/urls";
import { createContext, useContext, useMemo } from "react";
import { Pagination } from "../types";
export interface PageInfo {
endCursor: string;
hasNextPage: boolean;
hasPreviousPage: boolean;
startCursor: string;
}
export interface PaginationState {
after?: string;
before?: string;
first?: number;
last?: number;
}
export function createPaginationState(
paginateBy: number,
queryString: Pagination,
): PaginationState {
return queryString && (queryString.before || queryString.after)
? queryString.after
? {
after: queryString.after,
first: paginateBy,
}
: {
before: queryString.before,
last: paginateBy,
}
: {
first: paginateBy,
};
}
interface UsePaginatorArgs {
pageInfo: PageInfo;
paginationState: PaginationState;
queryString: Pagination;
}
function usePaginator({
queryString,
paginationState,
pageInfo,
}: UsePaginatorArgs) {
const newPageInfo = useMemo<PageInfo | undefined>(
() =>
pageInfo
? {
...pageInfo,
hasNextPage: !!paginationState.before || pageInfo.hasNextPage,
hasPreviousPage:
!!paginationState.after || pageInfo.hasPreviousPage,
}
: undefined,
[paginationState, pageInfo],
);
const nextHref = useMemo(() => {
if (!newPageInfo?.hasNextPage || !pageInfo?.endCursor) {
return undefined;
}
return (
"?" +
stringifyQs({
...queryString,
after: pageInfo.endCursor,
before: undefined,
})
);
}, [pageInfo?.endCursor, newPageInfo?.hasNextPage, queryString]);
const prevHref = useMemo(() => {
if (!newPageInfo?.hasPreviousPage || !pageInfo?.startCursor) {
return undefined;
}
return (
"?" +
stringifyQs({
...queryString,
after: undefined,
before: pageInfo.startCursor,
})
);
}, [pageInfo?.startCursor, newPageInfo?.hasPreviousPage, queryString]);
return {
nextHref,
prevHref,
paginatorType: "link" as const,
...newPageInfo,
};
}
export default usePaginator;
export interface PaginatorContextValuesCommon {
hasNextPage?: boolean;
hasPreviousPage?: boolean;
endCursor?: string | null;
startCursor?: string | null;
}
export type PaginatorContextValues = PaginatorContextValuesCommon &
(
| {
paginatorType: "link";
nextHref?: string;
prevHref?: string;
loadNextPage?: never;
loadPreviousPage?: never;
}
| {
paginatorType: "click";
nextHref?: never;
prevHref?: never;
loadNextPage: () => void;
loadPreviousPage: () => void;
}
);
export const PaginatorContext = createContext<PaginatorContextValues | null>(
null,
);
export const usePaginatorContext = () => {
const context = useContext(PaginatorContext);
if (context === null) {
throw new Error(
"usePaginatorContext must be used within a PaginatorContext.Provider",
);
}
return context;
};