Migrate pagination from page to scroll one

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-02-19 11:32:21 +01:00
parent d9c76878c0
commit b27f69756e
3 changed files with 532 additions and 18 deletions

View File

@@ -21,7 +21,7 @@ import { VendorListPageCreateVendorMutation } from "./__generated__/VendorListPa
import { VendorListPageDeleteVendorMutation } from "./__generated__/VendorListPageDeleteVendorMutation.graphql";
import { toast } from "@/hooks/use-toast";
const ITEMS_PER_PAGE = 20;
const ITEMS_PER_PAGE = 25;
const vendorListPageQuery = graphql`
query VendorListPageQuery(
@@ -102,6 +102,58 @@ const vendorsList = [
{ id: "17", name: "CircleCI", createdAt: new Date().toISOString() },
];
function LoadAboveButton({
pageInfo,
isPending,
onPageChange,
}: {
pageInfo: {
hasNextPage: boolean;
hasPreviousPage: boolean;
} | null | undefined;
isPending: boolean;
onPageChange: (direction: "prev") => void;
}) {
return (
<div className="flex justify-center">
<Button
variant="outline"
onClick={() => onPageChange("prev")}
disabled={isPending || !pageInfo?.hasPreviousPage}
className="w-full"
>
{isPending ? "Loading..." : "Load above"}
</Button>
</div>
);
}
function LoadBelowButton({
pageInfo,
isPending,
onPageChange,
}: {
pageInfo: {
hasNextPage: boolean;
hasPreviousPage: boolean;
} | null | undefined;
isPending: boolean;
onPageChange: (direction: "next") => void;
}) {
return (
<div className="flex justify-center">
<Button
variant="outline"
onClick={() => onPageChange("next")}
disabled={isPending || !pageInfo?.hasNextPage}
className="w-full"
>
{isPending ? "Loading..." : "Load below"}
</Button>
</div>
);
}
function VendorListContent({
queryRef,
onPageChange,
@@ -245,6 +297,13 @@ function VendorListContent({
</div>
</div>
</div>
<LoadAboveButton
pageInfo={pageInfo}
isPending={isPending}
onPageChange={() => handlePageChange("prev")}
/>
<div className="space-y-2">
{vendors.map((vendor) => (
<div
@@ -316,24 +375,13 @@ function VendorListContent({
</div>
</div>
))}
<div className="flex gap-2 justify-end mt-4">
<Button
variant="outline"
onClick={() => handlePageChange("prev")}
disabled={isPending || !pageInfo?.hasPreviousPage}
>
{isPending ? "Loading..." : "Previous"}
</Button>
<Button
variant="outline"
onClick={() => handlePageChange("next")}
disabled={isPending || !pageInfo?.hasNextPage}
>
{isPending ? "Loading..." : "Next"}
</Button>
</div>
</div>
<LoadBelowButton
pageInfo={pageInfo}
isPending={isPending}
onPageChange={() => handlePageChange("next")}
/>
</div>
);
}

View File

@@ -0,0 +1,258 @@
/**
* @generated SignedSource<<87314e850c396bef91d3fa31ec8a04b8>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type VendorListPagePaginationQuery$variables = {
after?: any | null | undefined;
first?: number | null | undefined;
id: string;
};
export type VendorListPagePaginationQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"VendorListPage_vendors">;
};
};
export type VendorListPagePaginationQuery = {
response: VendorListPagePaginationQuery$data;
variables: VendorListPagePaginationQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "first"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v4 = [
{
"kind": "Variable",
"name": "after",
"variableName": "after"
},
{
"kind": "Variable",
"name": "first",
"variableName": "first"
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "VendorListPagePaginationQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "VendorListPage_vendors"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "VendorListPagePaginationQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": "VendorConnection",
"kind": "LinkedField",
"name": "vendors",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "VendorEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Vendor",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
(v2/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": (v4/*: any*/),
"filters": null,
"handle": "connection",
"key": "VendorListPage_vendors",
"kind": "LinkedHandle",
"name": "vendors"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "73f269ef13a930c0629d857caae56a34",
"id": null,
"metadata": {},
"name": "VendorListPagePaginationQuery",
"operationKind": "query",
"text": "query VendorListPagePaginationQuery(\n $after: CursorKey\n $first: Int\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...VendorListPage_vendors\n id\n }\n}\n\nfragment VendorListPage_vendors on Organization {\n vendors(first: $first, after: $after) {\n edges {\n node {\n id\n name\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "753e6b32cc21645852de27cf6f23c769";
export default node;

View File

@@ -0,0 +1,208 @@
/**
* @generated SignedSource<<048f9d727dd07032be161da7019c6ebe>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type VendorListPage_vendors$data = {
readonly id: string;
readonly vendors: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: any;
readonly id: string;
readonly name: string;
readonly updatedAt: any;
};
}>;
readonly pageInfo: {
readonly endCursor: any | null | undefined;
readonly hasNextPage: boolean;
readonly hasPreviousPage: boolean;
readonly startCursor: any | null | undefined;
};
};
readonly " $fragmentType": "VendorListPage_vendors";
};
export type VendorListPage_vendors$key = {
readonly " $data"?: VendorListPage_vendors$data;
readonly " $fragmentSpreads": FragmentRefs<"VendorListPage_vendors">;
};
const node: ReaderFragment = (function(){
var v0 = [
"vendors"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"kind": "RootArgument",
"name": "after"
},
{
"kind": "RootArgument",
"name": "first"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": "first",
"cursor": "after",
"direction": "forward",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "first",
"cursor": "after"
},
"backward": null,
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": require('./VendorListPagePaginationQuery.graphql'),
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "VendorListPage_vendors",
"selections": [
{
"alias": "vendors",
"args": null,
"concreteType": "VendorConnection",
"kind": "LinkedField",
"name": "__VendorListPage_vendors_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "VendorEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Vendor",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "Organization",
"abstractKey": null
};
})();
(node as any).hash = "753e6b32cc21645852de27cf6f23c769";
export default node;