import Input from '@/components/elements/Input'; import InputSpinner from '@/components/elements/InputSpinner'; import { debounce } from 'debounce'; import React, { useCallback, useState } from 'react'; import { TableCheckbox } from '@/components/admin/AdminCheckbox'; import Spinner from '@/components/elements/Spinner'; import tw, { styled } from 'twin.macro'; import { PaginatedResult, PaginationDataSet } from '@/api/http'; import { ListContext as TableHooks } from '@/api/admin'; export function useTableHooks (): TableHooks { const [ page, setPage ] = useState(1); const [ filters, setFilters ] = useState(null); const [ sort, setSortState ] = useState(null); const [ sortDirection, setSortDirection ] = useState(false); const setSort = (newSort: string | null) => { if (sort === newSort) { setSortDirection(!sortDirection); } else { setSortState(newSort); setSortDirection(false); } }; return { page, setPage, filters, setFilters, sort, setSort, sortDirection, setSortDirection }; } export const TableHeader = ({ name, onClick, direction }: { name?: string, onClick?: (e: React.MouseEvent) => void, direction?: number | null }) => { if (!name) { return ; } return ( {name} {direction !== undefined ?
{(direction === null || direction === 1) ? : null} {(direction === null || direction === 2) ? : null}
: null }
); }; export const TableHead = ({ children }: { children: React.ReactNode }) => { return ( {children} ); }; export const TableBody = ({ children }: { children: React.ReactNode }) => { return ( {children} ); }; export const TableRow = ({ children }: { children: React.ReactNode }) => { return ( {children} ); }; interface Props { data?: PaginatedResult; onPageSelect: (page: number) => void; children: React.ReactNode; } const PaginationButton = styled.button<{ active?: boolean }>` ${tw`relative items-center px-3 py-1 -ml-px text-sm font-normal leading-5 transition duration-150 ease-in-out border border-neutral-500 focus:z-10 focus:outline-none focus:border-primary-300 inline-flex`}; ${props => props.active ? tw`bg-neutral-500 text-neutral-50` : tw`bg-neutral-600 text-neutral-200 hover:text-neutral-50`}; `; const PaginationArrow = styled.button` ${tw`relative inline-flex items-center px-1 py-1 text-sm font-medium leading-5 transition duration-150 ease-in-out border border-neutral-500 bg-neutral-600 text-neutral-400 hover:text-neutral-50 focus:z-10 focus:outline-none focus:border-primary-300`}; &:disabled { ${tw`bg-neutral-700`} } &:hover:disabled { ${tw`text-neutral-400 cursor-default`}; } `; export function Pagination ({ data, onPageSelect, children }: Props) { let pagination: PaginationDataSet; if (data === undefined) { pagination = { total: 0, count: 0, perPage: 0, currentPage: 1, totalPages: 1, }; } else { pagination = data.pagination; } const setPage = (page: number) => { if (page < 1 || page > pagination.totalPages) { return; } onPageSelect(page); }; const isFirstPage = pagination.currentPage === 1; const isLastPage = pagination.currentPage >= pagination.totalPages; const pages = []; if (pagination.totalPages < 7) { for (let i = 1; i <= pagination.totalPages; i++) { pages.push(i); } } else { // Don't ask me how this works, all I know is that this code will always have 7 items in the pagination, // and keeps the current page centered if it is not too close to the start or end. let start = Math.max(pagination.currentPage - 3, 1); const end = Math.min(pagination.totalPages, pagination.currentPage + ((pagination.currentPage < 4) ? 7 - pagination.currentPage : 3)); while (start !== 1 && end - start !== 6) { start--; } for (let i = start; i <= end; i++) { pages.push(i); } } return ( <> {children}

Showing {((pagination.currentPage - 1) * pagination.perPage) + (pagination.total > 0 ? 1 : 0)} to {((pagination.currentPage - 1) * pagination.perPage) + pagination.count} of {pagination.total} results

{isFirstPage && isLastPage ? null :
}
); } export const Loading = () => { return (
); }; export const NoItems = () => { return (
{'No

No items could be found, it's almost like they are hiding.

); }; interface Params { checked: boolean; onSelectAllClick: (e: React.ChangeEvent) => void; onSearch?: (query: string) => Promise; children: React.ReactNode; } export const ContentWrapper = ({ checked, onSelectAllClick, onSearch, children }: Params) => { const [ loading, setLoading ] = useState(false); const [ inputText, setInputText ] = useState(''); const search = useCallback( debounce((query: string) => { if (onSearch === undefined) { return; } setLoading(true); onSearch(query).then(() => setLoading(false)); }, 200), [], ); return ( <>
{ setInputText(e.currentTarget.value); search(e.currentTarget.value); }} />
{children} ); }; export default ({ children }: { children: React.ReactNode }) => { return (
{children}
); };