All files / store/components/PackageList PackageList.tsx

79.48% Statements 31/39
84.21% Branches 32/38
75% Functions 6/8
79.48% Lines 31/39

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                            1x   1x             32x 32x   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 {
  Button,
  Col,
  Pagination,
  Row,
  Strip,
} from "@canonical/react-components";
import Banner from "../Banner";
import { useRef } from "react";
import { useSearchParams } from "react-router-dom";
import { Category, Package, Store } from "../../types";
import { PackageFilter } from "../PackageFilter";
import { DefaultCard, LoadingCard } from "@canonical/store-components";
 
const ITEMS_PER_PAGE = 15;
 
export const PackageList = ({
  data,
  isFetching,
}: {
  data?: Store;
  isFetching: boolean;
}) => {
  const searchRef = useRef<HTMLInputElement | null>(null);
  const searchSummaryRef = useRef<HTMLDivElement>(null);
 
  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) => {
    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 = () => {
    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 (
    <>
      <Banner searchRef={searchRef} searchSummaryRef={searchSummaryRef} />
      <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>
    </>
  );
};