Skip to content

Commit

Permalink
Merge pull request #208 from NYPL/feature/DR-3193/refactor-grid-compo…
Browse files Browse the repository at this point in the history
…nent

DR-3193/refactor grid component
  • Loading branch information
avertrees authored Oct 15, 2024
2 parents ad0ab5f + a0f0825 commit 40743fa
Show file tree
Hide file tree
Showing 12 changed files with 506 additions and 395 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Updated

- Refactored collection/item lanes into one `Lane` component (DR-3191)
- Refactored collections/items grid into one `CardsGrid` component (DR-3193)
- Updated header on /divisions/:slug page to have a tabIndex of -1 (DR-3229)
- General cleanup (DR-3194)

Expand Down
14 changes: 9 additions & 5 deletions app/src/components/card/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { TRUNCATED_LENGTH } from "@/src/config/constants";
import ItemCardDataType from "@/src/types/ItemCardDataType";
import { CollectionCardDataType } from "../../types/CollectionCardDataType";
import { Offset } from "@/src/hooks/useTooltipOffset";
import { stringToSlug } from "@/src/utils/utils";
interface DCCardProps {
tooltipOffset?: Offset;
id: string;
Expand All @@ -32,16 +33,19 @@ export const Card = forwardRef<HTMLDivElement, DCCardProps>(
({ tooltipOffset, id, isLargerThanLargeTablet, slug, record }, ref) => {
const truncatedTitle = record.title.length > TRUNCATED_LENGTH;
const isCollection = isCollectionCardDataType(record);
const identifier = slug
? `${slug}-${id}`
: `${stringToSlug(record.title)}-${id}`; // should probably truncate
const card = (
<ChakraCard
ref={ref}
id={`card-${slug}-${id}`}
id={`card-${identifier}`}
mainActionLink={record.url}
imageProps={
record.imageID
? {
alt: "",
id: isCollection ? `image-${slug}-${id}` : `image-${id}`,
id: `image-${identifier}`,
isLazy: true,
aspectRatio: "twoByOne",
fallbackSrc: "/noImage.png",
Expand All @@ -53,7 +57,7 @@ export const Card = forwardRef<HTMLDivElement, DCCardProps>(
}
: {
alt: "",
id: `no-image-${id}`,
id: `no-image-${identifier}`,
isLazy: true,
aspectRatio: "twoByOne",
src: "/noImage.png",
Expand All @@ -68,7 +72,7 @@ export const Card = forwardRef<HTMLDivElement, DCCardProps>(
)}
</CardContent>
<CardHeading
id={`row-card-heading-${slug}-${id}`}
id={`row-card-heading-${identifier}`}
level="h3"
size="heading5"
noOfLines={3}
Expand All @@ -88,7 +92,7 @@ export const Card = forwardRef<HTMLDivElement, DCCardProps>(
<CardContent sx={{ alignContent: "top" }}>
{isCollection && (
<Text
id={`item-count-${slug}-${id}`}
id={`item-count-${identifier}`}
size="subtitle2"
fontWeight="medium"
__css={{
Expand Down
24 changes: 24 additions & 0 deletions app/src/components/grids/cardsGrid.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { render, screen, within } from "@testing-library/react";
import { mockCollections } from "__tests__/__mocks__/data/mockCollections";
import { mockItems } from "__tests__/__mocks__/data/mockItems";
import { CardsGrid } from "./cardsGrid";

describe("Collections CardsGrid component", () => {
it("renders the correct collection data", async () => {
render(<CardsGrid records={mockCollections} />);
const headingElement = screen.getByRole("heading", {
name: /Posada Collection/i,
});
expect(headingElement).toBeInTheDocument();
});
});

describe("Item CardsGrid component", () => {
it("renders the correct item data", async () => {
render(<CardsGrid records={mockItems} />);
const headingElement = screen.getByRole("heading", {
name: /Sarah Myers Blackwell sitting in a tree/i,
});
expect(headingElement).toBeInTheDocument();
});
});
55 changes: 55 additions & 0 deletions app/src/components/grids/cardsGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"use client";

import React, { useRef } from "react";
import useBreakpoints from "../../hooks/useBreakpoints";
import CollectionDataType from "../../types/CollectionDataType";
import ItemDataType from "@/src/types/ItemDataType";
import { isCollectionType } from "@/src/utils/utils";
import { CollectionCardModel } from "../../models/collectionCard";
import { ItemCardModel } from "@/src/models/itemCard";
import { SimpleGrid as DCSimpleGrid } from "../simpleGrid/simpleGrid";
import { Card as DCCard } from "../card/card";
import { useTooltipOffset } from "@/src/hooks/useTooltipOffset";

interface CardsGridProps {
records: CollectionDataType[] | ItemDataType[];
}

export const CardsGrid = ({ records }: CardsGridProps) => {
const { isLargerThanLargeTablet } = useBreakpoints();
const isCollections = isCollectionType(records);
const cardRef = useRef<HTMLDivElement>(null);
const tooltipOffset = useTooltipOffset(cardRef);

return (
<DCSimpleGrid>
{records?.map((record, index) => {
if (isCollections) {
const collectionCardModel = new CollectionCardModel(record);
return (
<DCCard
key={index}
id={index}
ref={cardRef}
tooltipOffset={tooltipOffset}
record={collectionCardModel}
isLargerThanLargeTablet={isLargerThanLargeTablet}
/>
);
} else {
const itemCardModel = new ItemCardModel(record);
return (
<DCCard
key={index}
id={index}
ref={cardRef}
tooltipOffset={tooltipOffset}
record={itemCardModel}
isLargerThanLargeTablet={isLargerThanLargeTablet}
/>
);
}
})}
</DCSimpleGrid>
);
};
29 changes: 0 additions & 29 deletions app/src/components/grids/collectionsGrid.tsx

This file was deleted.

29 changes: 0 additions & 29 deletions app/src/components/grids/itemsGrid.tsx

This file was deleted.

8 changes: 1 addition & 7 deletions app/src/components/lane/lane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import CollectionDataType from "@/src/types/CollectionDataType";
import ItemDataType from "@/src/types/ItemDataType";
import useBreakpoints from "@/src/hooks/useBreakpoints";
import { useTooltipOffset } from "@/src/hooks/useTooltipOffset";
import { isCollectionType } from "@/src/utils/utils";

interface LaneProps {
seeMoreLink: string;
Expand All @@ -27,12 +28,6 @@ interface LaneProps {
laneSlug?: string;
}

function isCollectionType(
records: CollectionDataType[] | ItemDataType[]
): records is CollectionDataType[] {
return "numberOfDigitizedItems" in records[0];
}

export const Lane = ({
records,
seeMoreLink,
Expand Down Expand Up @@ -121,7 +116,6 @@ export const Lane = ({
return (
<DCCard
key={index}
slug={laneSlug}
id={`${index}`}
record={collectionCardModel}
isLargerThanLargeTablet={isLargerThanLargeTablet}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
import { useParams } from "next/navigation";
import { headerBreakpoints } from "../../../utils/breakpoints";
import { slugToString } from "../../../utils/utils";
import { mockCollectionCards } from "__tests__/__mocks__/data/mockCollectionCards";
import { CollectionsGrid } from "../../grids/collectionsGrid";
import { mockCollections } from "__tests__/__mocks__/data/mockCollections";
import { CardsGrid } from "../../grids/cardsGrid";
import React, { useEffect, useRef, useState } from "react";
import PageLayout from "../../pageLayout/pageLayout";
import useBreakpoints from "@/src/hooks/useBreakpoints";
Expand Down Expand Up @@ -54,7 +54,7 @@ export default function CollectionLanePage() {
<HorizontalRule sx={{ marginTop: "xxl", marginBottom: "xxl" }} />
{isLoaded ? (
<>
<CollectionsGrid collections={mockCollectionCards} />
<CardsGrid records={mockCollections} />
</>
) : (
<>
Expand Down
10 changes: 7 additions & 3 deletions app/src/components/pages/divisionPage/divisionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import React, { useEffect, useState, useRef } from "react";
import PageLayout from "../../pageLayout/pageLayout";
import { headerBreakpoints } from "../../../utils/breakpoints";
import { CollectionsGrid } from "../../grids/collectionsGrid";
import { CardsGrid } from "../../grids/cardsGrid";
import { slugToString, totalNumPages } from "../../../utils/utils";
import useBreakpoints from "../../../hooks/useBreakpoints";
import { DC_URL } from "@/src/config/constants";
Expand Down Expand Up @@ -120,9 +120,13 @@ export default function DivisionPage({ data }: any) {
</Heading>

{isLoaded ? (
<CollectionsGrid collections={data.collections} />
<CardsGrid records={data.collections} />
) : (
<LaneLoading withTitle={false} />
<>
<LaneLoading withTitle={false} />
<LaneLoading withTitle={false} />
<LaneLoading withTitle={false} />
</>
)}
{totalPages > 1 && (
<Pagination
Expand Down
17 changes: 10 additions & 7 deletions app/src/components/search/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import {
Text,
Pagination,
} from "@nypl/design-system-react-components";
import { useSearchParams, usePathname, useRouter } from "next/navigation";
import { CollectionsGrid } from "../grids/collectionsGrid";
import React, { useState } from "react";
import { ItemsGrid } from "../grids/itemsGrid";
import { useSearchParams, usePathname, useRouter } from "next/navigation";
import { CardsGrid } from "../grids/cardsGrid";
import LaneLoading from "../lane/laneLoading";

const SearchContent = ({ showFilter, isSearchPage, data }) => {
const isLoaded = true;
Expand Down Expand Up @@ -84,11 +84,14 @@ const SearchContent = ({ showFilter, isSearchPage, data }) => {
) : null}
</Box>

{/* certainly a better way to handle this but it's annoying me. */}
{isLoaded && isSearchPage ? (
<CollectionsGrid collections={data} />
{isLoaded ? (
<CardsGrid records={data} />
) : (
<ItemsGrid items={data} />
<>
<LaneLoading withTitle={false} />,
<LaneLoading withTitle={false} />,
<LaneLoading withTitle={false} />,
</>
)}

{totalPages > 1 && (
Expand Down
8 changes: 8 additions & 0 deletions app/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
} from "../config/constants";
import { ENV_KEY } from "../types/EnvironmentType";
import appConfig from "../../../appConfig";
import CollectionDataType from "@/src/types/CollectionDataType";
import ItemDataType from "@/src/types/ItemDataType";

/**
* Represents a IIIF Image API URL, which will be used globally throughout the application.
Expand Down Expand Up @@ -97,3 +99,9 @@ export const titleToDCParam = (string: string = ""): string => {
export const totalNumPages = (numResults: string, perPage: string): number => {
return Math.ceil(parseInt(numResults) / parseInt(perPage));
};

export function isCollectionType(
records: CollectionDataType[] | ItemDataType[]
): records is CollectionDataType[] {
return "numberOfDigitizedItems" in records[0];
}
Loading

0 comments on commit 40743fa

Please sign in to comment.