Skip to content
This repository has been archived by the owner on Jul 23, 2024. It is now read-only.

Commit

Permalink
created LoadMoreTable and Button components
Browse files Browse the repository at this point in the history
  • Loading branch information
kaimsfd committed Oct 12, 2023
1 parent 3d2d043 commit 3150769
Show file tree
Hide file tree
Showing 9 changed files with 3,272 additions and 137 deletions.
4 changes: 3 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@
"graphql": "^16.8.1",
"http-proxy-middleware": "^2.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-native": "^0.72.5",
"react-native-web": "^0.19.9"
},
"jest": {
"roots": [
Expand Down
80 changes: 66 additions & 14 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,81 @@
/* eslint-disable react/jsx-no-undef */
import { useQuery, gql, DocumentNode } from "@apollo/client";
import React from "react";
import { Pagination, Table, theme } from "@diamondlightsource/ui-components"
import { theme } from "@diamondlightsource/ui-components"
import { ChakraProvider } from "@chakra-ui/react";
import { LoadMoreTable } from "./components/LoadMoreTable";

const GET_INFO: DocumentNode = gql`
query pinInfo {
libraryPins {
barcode,
loopSize,
status
query pinInfo ($after: String) {
libraryPins(first: 2, after: $after) {
pageInfo {
hasPreviousPage,
hasNextPage,
startCursor,
endCursor
},
edges {
cursor
node {
barcode,
loopSize,
status
}
}
}
}
`;

function DisplayPinInfo(): React.JSX.Element {
const { loading, error, data } = useQuery(GET_INFO);
const { loading, error, data, fetchMore } = useQuery(GET_INFO);

if (loading) return <p>Loading...</p>;
if (error) return <p>Error : {error.message} {error.extraInfo}</p>;


// function to load more content and update query result
const loadMore = () => {
// fetchMore function from `useQuery` to fetch more content with `updateQuery`
fetchMore({

// update `after` variable with `endCursor` from previous result
variables: {
after: data.libraryPins.pageInfo.endCursor,
},

// pass previous query result and the new results to `updateQuery`
updateQuery: (previousQueryResult, { fetchMoreResult }) => {
// define edges and pageInfo from new results
const newEdges = fetchMoreResult.libraryPins.edges;
const pageInfo = fetchMoreResult.libraryPins.pageInfo;
console.log(pageInfo)

// if newEdges actually have items,
return newEdges.length
? // return a reconstruction of the query result with updated values
{
// spread the value of the previous result
...previousQueryResult,

libraryPins: {
// spread the value of the previous `allStarhips` data into this object
...previousQueryResult.libraryPins,

// concatenate edges
edges: [...previousQueryResult.libraryPins.edges, ...newEdges],

// override with new pageInfo
pageInfo,
},
}
: // else, return the previous result
previousQueryResult;
},
});
};

return (
<><Table
<>
<LoadMoreTable
headers={[
{
key: 'barcode',
Expand All @@ -35,11 +90,8 @@ function DisplayPinInfo(): React.JSX.Element {
label: 'Status'
}
]}
data={data.libraryPins} />
<Pagination
total={6} onPageChange={(page) => {
console.log(`On page: ${page}`)
}}
data={data.libraryPins.edges.map((edge) => edge.node)}
onButtonClick={loadMore}
/>
</>
);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/BarcodeTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class BarcodeTable extends Component {
<table>
<thead>
<tr>
<th className={'wrapper th-td-spacing'}>Barcode</th>
<th className='wrapper th-td-spacing'>Barcode</th>
<th className={'wrapper th-td-spacing'}>Loop Size</th>
<th className={'wrapper th-td-spacing'}>Status</th>
</tr>
Expand Down
30 changes: 30 additions & 0 deletions frontend/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { Text, StyleSheet, Pressable } from 'react-native';

export default function Button(props) {
const { onPress, title = 'Load More' } = props;
return (
<Pressable style={styles.button} onPress={onPress}>
<Text style={styles.text}>{title}</Text>
</Pressable>
);
}

const styles = StyleSheet.create({
button: {
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 12,
paddingHorizontal: 32,
borderRadius: 4,
elevation: 3,
backgroundColor: 'black',
},
text: {
fontSize: 16,
lineHeight: 21,
fontWeight: 'bold',
letterSpacing: 0.25,
color: 'white',
},
});
123 changes: 123 additions & 0 deletions frontend/src/components/CursorPaginator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import {
Box,
HStack,
Button,
Divider,
Stack,
BoxProps,
} from "@chakra-ui/react";
import React from "react";
import { useEffect, useState } from "react";

type PageChangeCallback = (page: number) => void;
type ItemChangeCallback = (items: number) => void;

export interface PaginationProps extends BoxProps {
/** Total number of items to paginate */
total: number;
/** Array with all available "items per page" amounts */
possibleItemsPerPage?: Array<number>;
/** External bind for current page */
page?: number;
/** Number of items to display per page */
limit?: number;
/** Callback for page change events */
onPageChange?: PageChangeCallback;
/** Callback for item count change event */
onItemCountChange?: ItemChangeCallback;
}

const CursorPaginator = ({
total,
possibleItemsPerPage = [5, 10, 15, 20, 30, 50, 100],
limit = 5,
page,
onPageChange,
onItemCountChange,
...props
}: PaginationProps) => {
const [internalPage, setInternalPage] = useState(page || 1);
// Use limit set in instance, unless it does not exist in the list of possible items per page.
// Default to middle.
const [itemsPerPage] = useState(
possibleItemsPerPage.includes(limit)
? limit
: possibleItemsPerPage[Math.floor(possibleItemsPerPage.length / 2)],
);
const [pageAmount, setPageAmount] = useState(1);

useEffect(() => {
if (page) {
setInternalPage(page);
}
}, [page]);

useEffect(() => {
if (onPageChange !== undefined) {
onPageChange(internalPage);
}
}, [internalPage, onPageChange]);

useEffect(() => {
if (onItemCountChange !== undefined) {
onItemCountChange(itemsPerPage);
}
}, [itemsPerPage, onItemCountChange]);


useEffect(() => {
const newPageAmount = Math.ceil(total / itemsPerPage);
setInternalPage((prevPage) => (prevPage > newPageAmount ? 1 : prevPage));
setPageAmount(newPageAmount);
}, [total, itemsPerPage, setInternalPage]);

return (
<Box py={2} {...props}>
<Stack w='100%' direction={{ base: "column", md: "row" }}>
<HStack>
<Button
aria-label='First Page'
size='sm'
variant='pgNotSelected'
onClick={() => setInternalPage(1)}
isDisabled={internalPage <= 1}
>
&lt;&lt;
</Button>
<Button
aria-label='Previous Page'
size='sm'
variant='pgNotSelected'
isDisabled={internalPage <= 1}
onClick={() => setInternalPage(internalPage - 1)}
>
&lt;
</Button>
<Button
aria-label='Next Page'
size='sm'
variant='pgNotSelected'
isDisabled={internalPage >= pageAmount}
onClick={() => setInternalPage(internalPage + 1)}
>
&gt;
</Button>
<Button
aria-label='Last Page'
size='sm'
variant='pgNotSelected'
isDisabled={internalPage >= pageAmount}
onClick={() => setInternalPage(pageAmount)}
>
&gt;&gt;
</Button>
</HStack>
<Divider display={{ base: "none", md: "initial" }} orientation='vertical' h='30px' />
<HStack flexGrow='1'>
</HStack>
</Stack>
</Box>
);
};

export { CursorPaginator };
85 changes: 85 additions & 0 deletions frontend/src/components/LoadMorePaginator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {
Box,
HStack,
Button,
Divider,
Stack,
BoxProps,
} from "@chakra-ui/react";
import React from "react";
import { useEffect, useState } from "react";

type PageChangeCallback = (page: number) => void;
type ItemChangeCallback = (items: number) => void;

export interface PaginationProps extends BoxProps {
/** Total number of items to paginate */
total: number;
/** Array with all available "items per page" amounts */
possibleItemsPerPage?: Array<number>;
/** External bind for current page */
page?: number;
/** Number of items to display per page */
limit?: number;
/** Callback for page change events */
onPageChange?: PageChangeCallback;
/** Callback for item count change event */
onItemCountChange?: ItemChangeCallback;
}

const LoadMorePaginator = ({
total,
possibleItemsPerPage = [5, 10, 15, 20, 30, 50, 100],
limit = 5,
page,
onPageChange,
onItemCountChange,
...props
}: PaginationProps) => {
const [internalPage, setInternalPage] = useState(page || 1);
// Use limit set in instance, unless it does not exist in the list of possible items per page.
// Default to middle.
const [itemsPerPage] = useState(
possibleItemsPerPage.includes(limit)
? limit
: possibleItemsPerPage[Math.floor(possibleItemsPerPage.length / 2)],
);
const [pageAmount, setPageAmount] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [page2, setPage] = useState(1);
const [loading, setLoading] = useState(false);

useEffect(() => {
if (page) {
setInternalPage(page);
}
}, [page]);

useEffect(() => {
if (onPageChange !== undefined) {
onPageChange(internalPage);
}
}, [internalPage, onPageChange]);

useEffect(() => {
if (onItemCountChange !== undefined) {
onItemCountChange(itemsPerPage);
}
}, [itemsPerPage, onItemCountChange]);


useEffect(() => {
const newPageAmount = Math.ceil(total / itemsPerPage);
setInternalPage((prevPage) => (prevPage > newPageAmount ? 1 : prevPage));
setPageAmount(newPageAmount);
}, [total, itemsPerPage, setInternalPage]);

return (
<div className="LoadMorePaginator">
<div className="clearfix"></div>
{totalPages !== page && <button className="btn-load-more" onClick={() => setPage(page + 1)}>{loading ? 'Loading...' : 'Load More'}</button>}
</div>
);
};

export { LoadMorePaginator };
Loading

0 comments on commit 3150769

Please sign in to comment.