Skip to content

Commit

Permalink
#65 Refactor Pagination to include Intl
Browse files Browse the repository at this point in the history
  • Loading branch information
Felix Beceic committed Mar 6, 2023
1 parent 4ae047e commit 211542b
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 25 deletions.
64 changes: 46 additions & 18 deletions libs/core/src/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,30 @@ import * as React from "react";

import { range, slice } from "lodash";

import { Intl, useIntlContext } from "@tiller-ds/intl";
import { ComponentTokens, cx, useIcon, useTokens } from "@tiller-ds/theme";
import { useViewport } from "@tiller-ds/util";

import ButtonGroups from "./ButtonGroups";

import { useViewport } from "@tiller-ds/util";

export type PaginationProps = {
/**
* Complex values of types PageInfo and Components for formatting purposes.
*/
children?: (pageInfo: PageInfo, components: Components) => React.ReactNode;

/**
* Custom function activated when the page changes (takes the current page as a parameter)
* Custom additional class name for the main component.
*/
className?: string;

/**
* Custom icon for going to the next page.
*/
nextIcon?: React.ReactElement;

/**
* Custom function activated when the page changes (takes the current page as a parameter).
*/
onPageChange?: (page: number) => void;

Expand All @@ -42,28 +52,29 @@ export type PaginationProps = {
pageNumber: number;

/**
* Defines the size of each page (number of shown elements on each page).
* Defines a calculator for displaying page numbers.
*/
pageSize: number;
pagerCalculator?: (pageNumber: number, pageCount: number) => PagerPage[];

/**
* Defines the total number of elements on a source that the component is hooked up to.
* Enables or disables the page summary text next to the pagination.
*/
totalElements: number;
pageSummary?: boolean;

/**
* Defines a calculator for displaying page numbers.
* Defines the size of each page (number of shown elements on each page).
*/
pagerCalculator?: (pageNumber: number, pageCount: number) => PagerPage[];
pageSize: number;

/**
* Custom icon for going to the previous page.
*/
previousIcon?: React.ReactElement;

nextIcon?: React.ReactElement;

/**
* Custom additional class name for the main component.
* Defines the total number of elements on a source that the component is hooked up to.
*/
className?: string;
totalElements: number;
} & PaginationTokensProps;

type PaginationTokensProps = {
Expand Down Expand Up @@ -130,7 +141,7 @@ export function useLocalPagination<T>(data: T[], pageSize = 10): [PaginationStat
}

export default function Pagination(props: PaginationProps) {
const { pageNumber, pageSize, totalElements } = props;
const { pageNumber, pageSize, totalElements, pageSummary = true } = props;
const tokens = useTokens("Pagination", props.tokens);

const calculatedProps: CalculatedProps = {
Expand All @@ -140,15 +151,17 @@ export default function Pagination(props: PaginationProps) {

return (
<section className={tokens.master}>
<PageSummary {...props} />
{pageSummary && <PageSummary {...props} />}
<Pager {...props} {...calculatedProps} />
</section>
);
}

function PageSummary({ pageNumber, pageSize, totalElements, children, ...props }: PaginationProps) {
const calculatedFrom = pageNumber * pageSize;
const intl = useIntlContext();
const tokens = useTokens("Pagination", props.tokens);

const calculatedFrom = pageNumber * pageSize;
// user counting starts from 1
const from = totalElements === 0 ? calculatedFrom : calculatedFrom + 1;
const to = Math.min(totalElements, (pageNumber + 1) * pageSize);
Expand All @@ -162,13 +175,28 @@ function PageSummary({ pageNumber, pageSize, totalElements, children, ...props }
if (children) {
return children(
{ pageNumber, pageSize, totalElements, from, to },
{ from: fromElement, to: toElement, totalElements: totalElement }
{ from: fromElement, to: toElement, totalElements: totalElement },
) as React.ReactElement;
}

return (
<p className={pageSummaryClassName}>
Showing {fromElement} to {toElement} of {totalElement} results
{intl ? (
<Intl
name={intl.commonKeys["paginationDefault"] ?? "pagination.default"}
params={{ from: fromElement, to: toElement, total: totalElement }}
>
{{
from: () => fromElement,
to: () => toElement,
total: () => totalElement,
}}
</Intl>
) : (
<>
Showing {fromElement} to {toElement} of {totalElement} results
</>
)}
</p>
);
}
Expand Down
12 changes: 7 additions & 5 deletions libs/intl/src/IntlProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type CommonKeys = {
autocompleteAddTag?: string;
autocompleteNoResults?: string;
selectNoResults?: string;
paginationDefault?: string;
};

type IntlProviderProps = {
Expand Down Expand Up @@ -75,11 +76,11 @@ type IntlValue = {
commonKeys: CommonKeys;
};

type IntlContext = IntlValue & {
export type IntlContextType = IntlValue & {
intl: IntlShape;
};

export const IntlContext = createNamedContext<IntlContext>("IntlContext");
export const IntlContext = createNamedContext<IntlContextType>("IntlContext");

export function useIntl(
language: string,
Expand All @@ -91,7 +92,8 @@ export function useIntl(
autocompleteAddTag: "autocomplete.addTag",
autocompleteNoResults: "autocomplete.noResults",
selectNoResults: "select.noResults",
}
paginationDefault: "pagination.default",
},
): IntlValue {
const [lang, setLang] = React.useState<string>(language);
const [dictionary, setDictionary] = React.useState<Dictionary>(dict || ({} as Dictionary));
Expand All @@ -112,7 +114,7 @@ export function useIntl(
}
}
},
[loadDictionary]
[loadDictionary],
);

React.useEffect(() => {
Expand All @@ -133,7 +135,7 @@ export function useIntl(
intlUtil: new IntlUtil(dictionary, lang),
commonKeys: keyConfig,
}),
[lang, dictionary, changeLang]
[lang, dictionary, changeLang],
);
}

Expand Down
5 changes: 3 additions & 2 deletions libs/intl/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*
*/

import { CommonKeys as InternalCommonKeys } from "./IntlProvider";
import { CommonKeys as InternalCommonKeys, IntlContextType as InternalIntlContextType } from "./IntlProvider";

import {
Messages as InternalMessages,
Expand All @@ -29,8 +29,9 @@ export type Translations = InternalTranslations;
export type CommonKeys = InternalCommonKeys;
export type Dictionary = InternalDictionary;
export type LanguageTranslation = InternalLanguageTranslation;
export type IntlContextType = InternalIntlContextType;

export { default as Intl } from "./Intl";
export { default as IntlProvider, useIntl, IntlContext } from "./IntlProvider";
export { default as IntlProvider, useIntl } from "./IntlProvider";
export { useIntlContext } from "./useIntlContext";
export { useLabel } from "./useLabel";
3 changes: 3 additions & 0 deletions libs/intl/src/intlDictionary.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export default {
"autocomplete.addTag": "Add tag:",
"autocomplete.noResults": "No results for:",
"select.noResults": "No results",
"pagination.default": "Showing {from} to {to} of {total} results",
},
translations: {
hr: {
Expand All @@ -13,13 +14,15 @@ export default {
"autocomplete.addTag": "Dodaj oznaku:",
"autocomplete.noResults": "Nema rezultata za:",
"select.noResults": "Nema rezultata",
"pagination.default": "Prikazuje se {from} do {to} od {total} rezultata",
},
en: {
required: "Required field",
"autocomplete.noTags": "No tags selected",
"autocomplete.addTag": "Add tag:",
"autocomplete.noResults": "No results for:",
"select.noResults": "No results",
"pagination.default": "Showing {from} to {to} of {total} results",
},
},
};

0 comments on commit 211542b

Please sign in to comment.