All files / store/components/PackageList PackageList.tsx

77.77% Statements 28/36
84.21% Branches 32/38
75% Functions 6/8
77.77% Lines 28/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160                              1x                         32x     32x   32x     32x   32x 32x   32x   32x 12x 39x   12x     32x 32x 13x     19x 7x     12x       12x 2x     10x 2x     8x     32x                     32x       32x                                                                   255x             15x                                                          
import { useSearchParams } from "react-router-dom";
import { DefaultCard, LoadingCard } from "@canonical/store-components";
import {
  Button,
  Col,
  Pagination,
  Row,
  Strip,
} from "@canonical/react-components";
 
import { PackageFilter } from "../PackageFilter";
 
import type { RefObject } from "react";
import type { Category, Package, Packages } from "../../types";
 
const ITEMS_PER_PAGE = 15;
 
function PackageList({
  data,
  isFetching,
  searchRef,
  searchSummaryRef,
}: {
  data?: Packages;
  isFetching: boolean;
  searchRef: RefObject<HTMLInputElement>;
  searchSummaryRef: RefObject<HTMLDivElement>;
}): React.JSX.Element {
  const [searchParams, setSearchParams] = useSearchParams();
 
  const selectedCategories =
    searchParams.get("categories")?.split(",").filter(Boolean) || [];
  const isFeatured =
    selectedCategories.length === 0 ||
    (selectedCategories.length === 1 && selectedCategories[0] === "featured");
 
  const packagesCount = data?.packages ? data?.packages.length : 0;
 
  const currentPage = searchParams.get("page") || "1";
  const firstResultNumber = (parseInt(currentPage) - 1) * ITEMS_PER_PAGE + 1;
  const lastResultNumber =
    (parseInt(currentPage) - 1) * ITEMS_PER_PAGE + packagesCount;
 
  const getCategoryDisplayName = (name: string): string | undefined => {
    const category = data?.categories?.find(
      (cat: Category) => cat.name === name,
    );
    return category?.display_name;
  };
 
  const getResultsTitle = () => {
    if (searchParams.get("q")) {
      return "Snaps";
    }
 
    if (isFeatured) {
      return "Featured snaps";
    }
 
    Iif (selectedCategories.length === 0) {
      return;
    }
 
    if (selectedCategories.length === 2) {
      return `${getCategoryDisplayName(selectedCategories[0])} and 1 more category`;
    }
 
    if (selectedCategories.length > 1) {
      return `${getCategoryDisplayName(selectedCategories[0])} and ${selectedCategories.length - 1} more categories`;
    }
 
    return getCategoryDisplayName(selectedCategories[0]);
  };
 
  const onClear = (): void => {
    searchParams.delete("q");
    searchParams.delete("page");
    setSearchParams(searchParams);
 
    if (searchRef.current) {
      searchRef.current.value = "";
    }
  };
 
  const overHundredText =
    data?.total_items && data?.total_items > 100
      ? "over 100"
      : data?.total_items;
 
  return (
    <>
      <Strip>
        <Row>
          <Col size={3}>
            <PackageFilter data={data} disabled={isFetching} />
          </Col>
          <Col size={9}>
            <div ref={searchSummaryRef}>
              <h2>{getResultsTitle()}</h2>
              <Row>
                <Col size={6}>
                  {searchParams.get("q") ? (
                    <p>
                      Showing {currentPage === "1" ? "1" : firstResultNumber} to{" "}
                      {lastResultNumber} of {overHundredText} results for{" "}
                      <strong>"{searchParams.get("q")}"</strong>.{" "}
                      <Button appearance="link" onClick={onClear}>
                        Clear search
                      </Button>
                    </p>
                  ) : (
                    <p>
                      Showing {currentPage === "1" ? "1" : firstResultNumber} to{" "}
                      {lastResultNumber} of {overHundredText} items
                    </p>
                  )}
                </Col>
              </Row>
            </div>
 
            <Row>
              {isFetching &&
                [...Array(ITEMS_PER_PAGE)].map((_item, index) => (
                  <Col size={3} key={index}>
                    <LoadingCard />
                  </Col>
                ))}
              {!isFetching &&
                data &&
                data.packages.map((packageData: Package) => (
                  <Col
                    size={3}
                    style={{ marginBottom: "1.5rem" }}
                    key={packageData.id}
                  >
                    <DefaultCard data={packageData} />
                  </Col>
                ))}
            </Row>
 
            <Pagination
              itemsPerPage={ITEMS_PER_PAGE}
              totalItems={data ? data.total_items : 0}
              paginate={(pageNumber) => {
                searchParams.set("page", pageNumber.toString());
                setSearchParams(searchParams);
              }}
              currentPage={parseInt(currentPage)}
              centered
              scrollToTop
            />
          </Col>
        </Row>
      </Strip>
    </>
  );
}
 
export default PackageList;