From 6fb57607a7920baf45bc4b7086a623161a3d0373 Mon Sep 17 00:00:00 2001 From: selankon Date: Wed, 21 Aug 2024 09:53:58 +0200 Subject: [PATCH] Refactor to use ui components --- src/components/Blocks/BlocksList.tsx | 2 +- .../Organizations/Details/Elections.tsx | 4 +- src/components/Organizations/Details/Fees.tsx | 4 +- .../Organizations/Details/Transfers.tsx | 4 +- src/components/Organizations/List.tsx | 2 +- src/components/Pagination/Pagination.tsx | 229 ------------------ .../Pagination/PaginationProvider.tsx | 49 ---- .../Pagination/RoutedPagination.tsx | 3 +- src/components/Process/Detail.tsx | 4 +- src/components/Process/ProcessList.tsx | 2 +- .../Transactions/TransactionList.tsx | 2 +- src/theme/components/Paginator.ts | 19 ++ src/theme/components/index.ts | 2 + 13 files changed, 35 insertions(+), 291 deletions(-) delete mode 100644 src/components/Pagination/Pagination.tsx delete mode 100644 src/components/Pagination/PaginationProvider.tsx create mode 100644 src/theme/components/Paginator.ts diff --git a/src/components/Blocks/BlocksList.tsx b/src/components/Blocks/BlocksList.tsx index fd38ee91..d68226fd 100644 --- a/src/components/Blocks/BlocksList.tsx +++ b/src/components/Blocks/BlocksList.tsx @@ -6,7 +6,7 @@ import { BlockCard } from '~components/Blocks/BlockCard' import { PopoverInputSearch } from '~components/Layout/Inputs' import { LoadingCards } from '~components/Layout/Loading' import { ContentError, NoResultsError } from '~components/Layout/ContentError' -import { RoutedPaginationProvider, useRoutedPagination } from '~components/Pagination/PaginationProvider' +import { RoutedPaginationProvider, useRoutedPagination } from '@vocdoni/react-providers' import { RoutedPagination } from '~components/Pagination/RoutedPagination' import { PaginationItemsPerPage, RefreshIntervalBlocks, RoutePath } from '~constants' import { useBlockList } from '~queries/blocks' diff --git a/src/components/Organizations/Details/Elections.tsx b/src/components/Organizations/Details/Elections.tsx index 60a2b6b9..c46c1aed 100644 --- a/src/components/Organizations/Details/Elections.tsx +++ b/src/components/Organizations/Details/Elections.tsx @@ -2,8 +2,8 @@ import { Flex, Text } from '@chakra-ui/react' import { AccountData } from '@vocdoni/sdk' import { Trans } from 'react-i18next' import { LoadingCards } from '~components/Layout/Loading' -import { RoutedPagination } from '~components/Pagination/Pagination' -import { RoutedPaginationProvider, useRoutedPagination } from '~components/Pagination/PaginationProvider' +import { RoutedPagination } from '~components/Pagination/RoutedPagination' +import { RoutedPaginationProvider, useRoutedPagination } from '@vocdoni/react-providers' import { ElectionCard } from '~components/Process/Card' import { RoutePath } from '~constants' import { useOrganizationElections } from '~queries/organizations' diff --git a/src/components/Organizations/Details/Fees.tsx b/src/components/Organizations/Details/Fees.tsx index 9fef0c0a..80a9c3a9 100644 --- a/src/components/Organizations/Details/Fees.tsx +++ b/src/components/Organizations/Details/Fees.tsx @@ -3,8 +3,8 @@ import { Trans } from 'react-i18next' import { LoadingCards } from '~components/Layout/Loading' import { useDateFns } from '~i18n/use-date-fns' import { AccountData, TransactionType } from '@vocdoni/sdk' -import { PaginationProvider, usePagination } from '~components/Pagination/PaginationProvider' -import { Pagination } from '~components/Pagination/Pagination' +import { Pagination } from '@vocdoni/chakra-components' +import { PaginationProvider, usePagination } from '@vocdoni/react-providers' import { useAccountFees } from '~queries/organizations' import { TransactionTypeBadge } from '~components/Transactions/TransactionCard' import { generatePath, Link as RouterLink } from 'react-router-dom' diff --git a/src/components/Organizations/Details/Transfers.tsx b/src/components/Organizations/Details/Transfers.tsx index 53b6dfe0..0b673b6a 100644 --- a/src/components/Organizations/Details/Transfers.tsx +++ b/src/components/Organizations/Details/Transfers.tsx @@ -23,9 +23,9 @@ import { useAccountTransfers } from '~queries/organizations' import { useDateFns } from '~i18n/use-date-fns' import { BiLogInCircle, BiLogOutCircle } from 'react-icons/bi' import { AccountData } from '@vocdoni/sdk' -import { PaginationProvider, usePagination } from '~components/Pagination/PaginationProvider' +import { Pagination } from '@vocdoni/chakra-components' +import { PaginationProvider, usePagination } from '@vocdoni/react-providers' import { ContentError, NoResultsError } from '~components/Layout/ContentError' -import { Pagination } from '~components/Pagination/Pagination' const FromToIcon = ({ isIncoming, ...rest }: { isIncoming: boolean } & IconProps) => { const { t } = useTranslation() diff --git a/src/components/Organizations/List.tsx b/src/components/Organizations/List.tsx index aa03bc06..84aa893e 100644 --- a/src/components/Organizations/List.tsx +++ b/src/components/Organizations/List.tsx @@ -4,7 +4,7 @@ import { generatePath, useNavigate, useParams } from 'react-router-dom' import { InputSearch } from '~components/Layout/Inputs' import { LoadingCards } from '~components/Layout/Loading' import { OrganizationCard } from '~components/Organizations/Card' -import { RoutedPaginationProvider, useRoutedPagination } from '~components/Pagination/PaginationProvider' +import { RoutedPaginationProvider, useRoutedPagination } from '@vocdoni/chakra-components' import { RoutedPagination } from '~components/Pagination/RoutedPagination' import { RoutePath } from '~constants' import { useOrganizationCount, useOrganizationList } from '~queries/organizations' diff --git a/src/components/Pagination/Pagination.tsx b/src/components/Pagination/Pagination.tsx deleted file mode 100644 index e77486dd..00000000 --- a/src/components/Pagination/Pagination.tsx +++ /dev/null @@ -1,229 +0,0 @@ -import { Button, ButtonGroup, ButtonGroupProps, ButtonProps, Input, InputProps, Text } from '@chakra-ui/react' -import { ReactElement, useMemo, useState } from 'react' -import { generatePath, Link as RouterLink, useLocation, useNavigate, useParams } from 'react-router-dom' -import { usePagination, useRoutedPagination } from './PaginationProvider' -import { PaginationResponse } from '@vocdoni/sdk' -import { Trans } from 'react-i18next' - -export type PaginationProps = ButtonGroupProps & { - maxButtons?: number | false - buttonProps?: ButtonProps - inputProps?: InputProps -} & PaginationResponse - -type PaginatorButtonProps = { - page: number - currentPage: number -} & ButtonProps - -const PageButton = ({ page, currentPage, ...rest }: PaginatorButtonProps) => ( - -) - -const RoutedPageButton = ({ page, currentPage, to, ...rest }: PaginatorButtonProps & { to: string }) => ( - -) - -type EllipsisButtonProps = ButtonProps & { - gotoPage: (page: number) => void - inputProps?: InputProps -} - -const EllipsisButton = ({ gotoPage, inputProps, ...rest }: EllipsisButtonProps) => { - const [ellipsisInput, setEllipsisInput] = useState(false) - - if (ellipsisInput) { - return ( - { - if (e.target instanceof HTMLInputElement && e.key === 'Enter') { - const pageNumber = Number(e.target.value) - gotoPage(pageNumber) - setEllipsisInput(false) - } - }} - onBlur={() => setEllipsisInput(false)} - autoFocus - /> - ) - } - - return ( - - ) -} - -type CreatePageButtonType = (i: number) => ReactElement -type GotoPageType = (page: number) => void - -const usePaginationPages = ( - currentPage: number, - totalPages: number | undefined, - maxButtons: number | undefined | false, - gotoPage: GotoPageType, - createPageButton: CreatePageButtonType, - inputProps?: InputProps, - buttonProps?: ButtonProps -) => { - return useMemo(() => { - if (totalPages === undefined) return [] - - let pages: ReactElement[] = [] - - // Create an array of all page buttons - for (let i = 0; i < totalPages; i++) { - pages.push(createPageButton(i)) - } - - if (!maxButtons || totalPages <= maxButtons) { - return pages - } - - const startEllipsis = ( - - ) - const endEllipsis = ( - - ) - - // Add ellipsis and slice the array accordingly - const sideButtons = 2 // First and last page - const availableButtons = maxButtons - sideButtons // Buttons we can distribute around the current page - - if (currentPage <= availableButtons / 2) { - // Near the start - return [...pages.slice(0, availableButtons), endEllipsis, pages[totalPages - 1]] - } else if (currentPage >= totalPages - 1 - availableButtons / 2) { - // Near the end - return [pages[0], startEllipsis, ...pages.slice(totalPages - availableButtons, totalPages)] - } else { - // In the middle - const startPage = currentPage - Math.floor((availableButtons - 1) / 2) - const endPage = currentPage + Math.floor(availableButtons / 2) - return [pages[0], startEllipsis, ...pages.slice(startPage, endPage - 1), endEllipsis, pages[totalPages - 1]] - } - }, [currentPage, totalPages, maxButtons, gotoPage]) -} - -const PaginationButtons = ({ - totalPages, - totalItems, - currentPage, - goToPage, - createPageButton, - maxButtons = 10, - buttonProps, - ...rest -}: { - totalPages: number | undefined - totalItems: number | undefined - currentPage: number - createPageButton: CreatePageButtonType - goToPage: GotoPageType -} & ButtonGroupProps & - Pick) => { - const pages = usePaginationPages( - currentPage, - totalPages, - maxButtons ? Math.max(5, maxButtons) : false, - (page) => { - if (page >= 0 && totalPages && page < totalPages) { - goToPage(page) - } - }, - createPageButton - ) - - return ( - <> - - {totalPages === undefined ? ( - <> - - - - ) : ( - pages - )} - - {totalItems && ( - - - Showing a total of {{ count: totalItems }} results - - - )} - - ) -} - -export const Pagination = ({ maxButtons = 10, buttonProps, inputProps, pagination, ...rest }: PaginationProps) => { - const { setPage } = usePagination() - const totalPages = pagination.lastPage + 1 - const page = pagination.currentPage - - return ( - setPage(page)} - createPageButton={(i) => ( - setPage(i)} {...buttonProps} /> - )} - currentPage={page} - totalPages={totalPages} - totalItems={pagination.totalItems} - {...rest} - /> - ) -} - -export const RoutedPagination = ({ maxButtons = 10, buttonProps, pagination, ...rest }: PaginationProps) => { - const { path } = useRoutedPagination() - const { search } = useLocation() - const { page, ...extraParams }: { page?: number } = useParams() - const navigate = useNavigate() - - const totalPages = pagination.lastPage + 1 - - const currentPage = pagination.currentPage - - const _generatePath = (page: number) => generatePath(path, { page, ...extraParams }) + search - - return ( - navigate(_generatePath(page))} - createPageButton={(i) => ( - - )} - currentPage={currentPage} - totalPages={totalPages} - totalItems={pagination.totalItems} - {...rest} - /> - ) -} diff --git a/src/components/Pagination/PaginationProvider.tsx b/src/components/Pagination/PaginationProvider.tsx deleted file mode 100644 index 52b8d20c..00000000 --- a/src/components/Pagination/PaginationProvider.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { createContext, PropsWithChildren, useContext, useState } from 'react' -import { useParams } from 'react-router-dom' - -export type PaginationContextProps = { - page: number - setPage: (page: number) => void -} - -export type RoutedPaginationContextProps = Omit & { - path: string -} - -const PaginationContext = createContext(undefined) -const RoutedPaginationContext = createContext(undefined) - -export const usePagination = (): PaginationContextProps => { - const context = useContext(PaginationContext) - if (!context) { - throw new Error('usePagination must be used within a PaginationProvider') - } - return context -} - -export const useRoutedPagination = (): RoutedPaginationContextProps => { - const context = useContext(RoutedPaginationContext) - if (!context) { - throw new Error('useRoutedPagination must be used within a RoutedPaginationProvider') - } - return context -} - -export type PaginationProviderProps = {} - -export type RoutedPaginationProviderProps = PaginationProviderProps & { - path: string -} - -export const RoutedPaginationProvider = ({ path, ...rest }: PropsWithChildren) => { - const { page }: { page?: number } = useParams() - const p = page && page > 0 ? page - 1 : 0 - - return -} - -export const PaginationProvider = ({ ...rest }: PropsWithChildren) => { - const [page, setPage] = useState(0) - - return -} diff --git a/src/components/Pagination/RoutedPagination.tsx b/src/components/Pagination/RoutedPagination.tsx index 3015b790..edd752cd 100644 --- a/src/components/Pagination/RoutedPagination.tsx +++ b/src/components/Pagination/RoutedPagination.tsx @@ -1,5 +1,6 @@ import { useBreakpointValue } from '@chakra-ui/react' -import { RoutedPagination as Pagination, PaginationProps } from './Pagination' +// import { RoutedPagination as Pagination, PaginationProps } from './Pagination' +import { RoutedPagination as Pagination, PaginationProps } from '@vocdoni/chakra-components' // Note this component is a custom definition of the pagination component that will end in chakra-components export const RoutedPagination = (props: PaginationProps) => { diff --git a/src/components/Process/Detail.tsx b/src/components/Process/Detail.tsx index a69b1770..eb698ebc 100644 --- a/src/components/Process/Detail.tsx +++ b/src/components/Process/Detail.tsx @@ -43,8 +43,8 @@ import { LoadingCards } from '~components/Layout/Loading' import { RawContentBox } from '~components/Layout/ShowRawButton' import { OrganizationCard } from '~components/Organizations/Card' import { ElectionStatusBadge } from '~components/Organizations/StatusBadge' -import { Pagination } from '~components/Pagination/Pagination' -import { PaginationProvider, usePagination } from '~components/Pagination/PaginationProvider' +import { Pagination } from '@vocdoni/chakra-components' +import { PaginationProvider, usePagination } from '@vocdoni/react-providers' import InvalidElection from '~components/Process/InvalidElection' import { FallbackHeaderImg, RoutePath } from '~constants' import { useElectionKeys, useElectionVotesList } from '~queries/processes' diff --git a/src/components/Process/ProcessList.tsx b/src/components/Process/ProcessList.tsx index 0c02f59f..4770b8a8 100644 --- a/src/components/Process/ProcessList.tsx +++ b/src/components/Process/ProcessList.tsx @@ -14,7 +14,7 @@ import { Trans, useTranslation } from 'react-i18next' import { InputSearch } from '~components/Layout/Inputs' import { LoadingCards } from '~components/Layout/Loading' import { ContentError, NoResultsError } from '~components/Layout/ContentError' -import { RoutedPaginationProvider, useRoutedPagination } from '~components/Pagination/PaginationProvider' +import { RoutedPaginationProvider, useRoutedPagination } from '@vocdoni/react-providers' import { RoutedPagination } from '~components/Pagination/RoutedPagination' import { RoutePath } from '~constants' import { useProcessList } from '~queries/processes' diff --git a/src/components/Transactions/TransactionList.tsx b/src/components/Transactions/TransactionList.tsx index dd912937..5a1c6654 100644 --- a/src/components/Transactions/TransactionList.tsx +++ b/src/components/Transactions/TransactionList.tsx @@ -5,7 +5,7 @@ import { Trans, useTranslation } from 'react-i18next' import { generatePath, useNavigate } from 'react-router-dom' import { PopoverInputSearch } from '~components/Layout/Inputs' import { LoadingCards } from '~components/Layout/Loading' -import { RoutedPaginationProvider, useRoutedPagination } from '~components/Pagination/PaginationProvider' +import { RoutedPaginationProvider, useRoutedPagination } from '@vocdoni/react-providers' import { RoutedPagination } from '~components/Pagination/RoutedPagination' import { TransactionCard } from '~components/Transactions/TransactionCard' import { PaginationItemsPerPage, RoutePath } from '~constants' diff --git a/src/theme/components/Paginator.ts b/src/theme/components/Paginator.ts new file mode 100644 index 00000000..4f943fa8 --- /dev/null +++ b/src/theme/components/Paginator.ts @@ -0,0 +1,19 @@ +import { createMultiStyleConfigHelpers } from '@chakra-ui/react' +import { PaginationAnatomy } from '@vocdoni/chakra-components' + +const { defineMultiStyleConfig, definePartsStyle } = createMultiStyleConfigHelpers(PaginationAnatomy) + +const Pagination = defineMultiStyleConfig({ + baseStyle: definePartsStyle({ + buttonGroup: { + flexWrap: 'wrap', + rowGap: '2', + }, + totalResults: { + pt: 2, + color: 'lighterText', + }, + }), +}) + +export default Pagination diff --git a/src/theme/components/index.ts b/src/theme/components/index.ts index 4cc4741d..35e668d5 100644 --- a/src/theme/components/index.ts +++ b/src/theme/components/index.ts @@ -2,6 +2,7 @@ import Card from './Card' import { ElectionHeader, ElectionTitle } from './Election' import ElectionResults from './ElectionResults' import Link from './Link' +import Pagination from './Paginator' import Questions from './Questions' import Radio from './Radio' import Tag from './Tag' @@ -12,6 +13,7 @@ const components = { ElectionTitle, ElectionHeader, Envelope, + Pagination, Questions, Radio, ElectionResults,