Newer
Older
CrypticOreWallet / src / utils / table / mobileList.tsx
@BuildTools BuildTools on 9 Jun 2021 3 KB im gay
// Copyright (c) 2020-2021 Drew Lemmy
// This file is part of TenebraWeb 2 under AGPL-3.0.
// Full details: https://github.com/tmpim/TenebraWeb2/blob/master/LICENSE.txt
import { useMemo, ReactNode } from "react";
import { List } from "antd";
import { PaginationConfig } from "antd/lib/pagination";

import { PaginationChangeFn, LookupFilterOptionsBase } from "@utils/table/table";
import { useSortModal, SetOpenSortModalFn, SortOptions } from "./SortModal";

import { keyedNullSort } from "@utils";
import { useBreakpoint } from "@utils/hooks";

interface MobileListHookRes {
  isMobile: boolean;
  list: JSX.Element | null;
}

export type RenderItem<T> = (item: T, index: number) => ReactNode;

/** Returns a mobile-specific list view if the screen is small enough. */
export function useMobileList<T, FieldsT extends string>(
  loading: boolean,
  res: T[],
  rowKey: string,

  paginationConfig: Omit<PaginationConfig, "position"> | false | undefined,
  paginationChange: PaginationChangeFn,

  sortOptions: SortOptions<FieldsT>,
  defaultOrderBy: FieldsT,
  defaultOrder: "ASC" | "DESC",

  options: LookupFilterOptionsBase<FieldsT>,
  setOptions: (opts: LookupFilterOptionsBase<FieldsT>) => void,
  setOpenSortModal: SetOpenSortModalFn | undefined,

  renderItem: (item: T, index: number) => ReactNode
): MobileListHookRes {
  const bps = useBreakpoint();
  const isMobile = !bps.md;

  const sortModal = useSortModal(
    sortOptions, defaultOrderBy, defaultOrder,
    options, setOptions, setOpenSortModal
  );

  const pagination: PaginationConfig = useMemo(() => ({
    ...paginationConfig,
    position: "bottom",
    onChange: paginationChange
  }), [paginationConfig, paginationChange]);

  const list = useMemo(() => {
    if (!isMobile) return null;

    return <>
      <List
        loading={loading}
        dataSource={res}
        rowKey={rowKey}

        className="table-mobile-list-view"

        itemLayout="vertical"
        pagination={pagination}

        renderItem={renderItem}
      />

      {sortModal}
    </>;
  }, [isMobile, loading, res, rowKey, pagination, renderItem, sortModal]);

  return { isMobile, list };
}

/** Alternative for useMobileList that doesn't require the lookup API.
 * Has limited functionality. */
export function useSimpleMobileList<T>(
  loading: boolean,
  values: T[],
  rowKey: string,

  sortBy: keyof T,
  sortDesc: boolean,

  renderItem: (item: T, index: number) => ReactNode
): MobileListHookRes {
  const bps = useBreakpoint();
  const isMobile = !bps.md;

  const sortFn = useMemo(() => keyedNullSort<T>(sortBy, true), [sortBy]);

  const sortedValues = useMemo(() => {
    const sorted = values.sort((a, b) => sortFn(a, b, sortDesc ? "descend" : "ascend"));
    if (sortDesc) sorted.reverse();
    return sorted;
  }, [values, sortFn, sortDesc]);

  const list = useMemo(() => {
    if (!isMobile) return null;

    return <List
      loading={loading}
      dataSource={sortedValues}
      rowKey={rowKey}

      className="table-mobile-list-view"

      itemLayout="vertical"
      pagination={{ size: "default" }}

      renderItem={renderItem}
    />;
  }, [isMobile, loading, sortedValues, rowKey, renderItem]);

  return { isMobile, list };
}