From c6b77448191e749204bff711bd3f1cfd8d56ae92 Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 26 Nov 2024 14:14:17 -0500 Subject: [PATCH 01/11] fallback for featured item updates post reverse proxy launch --- CHANGELOG.md | 2 ++ app/src/data/defaultFeaturedItemData.ts | 43 ++++++------------------- app/src/utils/api.ts | 9 ++---- 3 files changed, 13 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 603dd581..e8b6b29e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +### Updated +- refactored implementation of default featured item & updated default number of digitized items (DR-3305) ## [0.2.4] 2024-11-26 diff --git a/app/src/data/defaultFeaturedItemData.ts b/app/src/data/defaultFeaturedItemData.ts index abcf705e..268d4d86 100644 --- a/app/src/data/defaultFeaturedItemData.ts +++ b/app/src/data/defaultFeaturedItemData.ts @@ -1,40 +1,15 @@ import { FeaturedItemDataType } from "../types/FeaturedItemDataType"; -type Environment = "development" | "qa" | "production"; -const defaultFeaturedItem: Record = { - development: { - featuredItem: { - imageID: "482815", - backgroundImageSrc: "/482815.jpg", - foregroundImageSrc: "/482815.jpg", - uuid: "510d47d9-4f93-a3d9-e040-e00a18064a99", - title: "Watuppa, From water front, Brooklyn", - href: "https://qa-digitalcollections.nypl.org/items/510d47d9-4f93-a3d9-e040-e00a18064a99", - }, - numberOfDigitizedItems: "875,861", - }, - qa: { - featuredItem: { - imageID: "482815", - backgroundImageSrc: "/482815.jpg", - foregroundImageSrc: "/482815.jpg", - uuid: "510d47d9-4f93-a3d9-e040-e00a18064a99", - title: "Watuppa, From water front, Brooklyn", - href: "https://qa-digitalcollections.nypl.org/items/510d47d9-4f93-a3d9-e040-e00a18064a99", - }, - numberOfDigitizedItems: "875,861", - }, - production: { - featuredItem: { - imageID: "482815", - backgroundImageSrc: "/482815.jpg", - foregroundImageSrc: "/482815.jpg", - uuid: "510d47d9-4f93-a3d9-e040-e00a18064a99", - title: "Watuppa, From water front, Brooklyn", - href: "https://digitalcollections.nypl.org/items/510d47d9-4f93-a3d9-e040-e00a18064a99", - }, - numberOfDigitizedItems: "875,861", +const defaultFeaturedItem: FeaturedItemDataType = { + featuredItem: { + imageID: "482815", + backgroundImageSrc: "/482815.jpg", + foregroundImageSrc: "/482815.jpg", + uuid: "510d47d9-4f93-a3d9-e040-e00a18064a99", + title: "Watuppa, From water front, Brooklyn", + href: "https://qa-digitalcollections.nypl.org/items/510d47d9-4f93-a3d9-e040-e00a18064a99", }, + numberOfDigitizedItems: "1,059,731", }; export default defaultFeaturedItem; diff --git a/app/src/utils/api.ts b/app/src/utils/api.ts index 3d91eb7d..8a3e98e4 100644 --- a/app/src/utils/api.ts +++ b/app/src/utils/api.ts @@ -1,8 +1,6 @@ import data from "../../src/data/lanes"; import type { LaneDataType } from "../../src/types/Lane"; -import { ENV_KEY } from "../../src/types/EnvironmentType"; import { imageURL, addCommas } from "../utils/utils"; -import appConfig from "../../../appConfig"; import defaultFeaturedItems from "../data/defaultFeaturedItemData"; import { CARDS_PER_PAGE } from "../config/constants"; import { DC_URL } from "../config/constants"; @@ -63,8 +61,7 @@ export const getFeaturedItemData = async () => { }; export const getFeaturedImage = async () => { - const defaultResponse = - defaultFeaturedItems[appConfig.environment as ENV_KEY].featuredItem; + const defaultResponse = defaultFeaturedItems.featuredItem; const apiResponse = await getItemByIdentifier("featured", "", { random: "true", }); @@ -94,9 +91,7 @@ export const getNumDigitizedItems = async () => { const apiUrl = `${process.env.API_URL}/api/v2/items/total`; const res = await apiResponse(apiUrl); - const fallbackCount = - defaultFeaturedItems[appConfig.environment as ENV_KEY] - .numberOfDigitizedItems; + const fallbackCount = defaultFeaturedItems.numberOfDigitizedItems; const totalItems = res?.count?.$ ? addCommas(res.count.$) : fallbackCount; // only add commas to repo api response data return totalItems; }; From 75d594f14e7f2730fcfd676e72d7d71298f6db16 Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 26 Nov 2024 15:08:20 -0500 Subject: [PATCH 02/11] public changelog --- public/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/CHANGELOG.md b/public/CHANGELOG.md index 603dd581..e8b6b29e 100644 --- a/public/CHANGELOG.md +++ b/public/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +### Updated +- refactored implementation of default featured item & updated default number of digitized items (DR-3305) ## [0.2.4] 2024-11-26 From f943b1d8d767f10bed6f392b54cf18c70d44af0c Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 3 Dec 2024 09:30:36 -0500 Subject: [PATCH 03/11] resolve merge conflicts and fix most tests --- app/src/utils/api.ts | 241 ++++++++++++++++++++++++++++++ app/src/utils/apiHelpers.test.tsx | 14 +- app/src/utils/apiHelpers.ts | 1 - public/CHANGELOG.md | 7 + 4 files changed, 253 insertions(+), 10 deletions(-) create mode 100644 app/src/utils/api.ts diff --git a/app/src/utils/api.ts b/app/src/utils/api.ts new file mode 100644 index 00000000..cc2799d8 --- /dev/null +++ b/app/src/utils/api.ts @@ -0,0 +1,241 @@ +import data from "../../src/data/lanes"; +import type { LaneDataType } from "../../src/types/Lane"; +import { imageURL, addCommas } from "../utils/utils"; +import defaultFeaturedItems from "../data/defaultFeaturedItemData"; +import { CARDS_PER_PAGE } from "../config/constants"; +import { DC_URL } from "../config/constants"; + +export const getHomePageData = async () => { + const randomNumber = Math.floor(Math.random() * 2); + const lanes: LaneDataType[] = data.lanes as unknown as LaneDataType[]; + + // Get all the UUIDs from the collections + const allCollectionUUIDs: string[] = lanes.reduce((acc, lane) => { + return acc.concat(lane.collections.map((collection) => collection.uuid)); + }, [] as string[]); + const uuidtoItemCountMap = await getItemsCountFromUUIDs(allCollectionUUIDs); + + // Update the collections for each lane with the number of items + const updatedLanes = lanes.map((lane) => { + const updatedCollections = lane.collections.map((collection) => { + return { + ...collection, + numberOfDigitizedItems: uuidtoItemCountMap[collection.uuid] || "0", + }; + }); + return { ...lane, collections: updatedCollections }; + }); + + const newResponse = { randomNumber, lanesWithNumItems: updatedLanes }; + return newResponse; +}; + +export const getFeaturedItemData = async () => { + const featuredImageData = await getFeaturedImage(); + const numDigitizedItems = await getNumDigitizedItems(); + + const featuredItemObject = { + imageID: featuredImageData.imageID, + backgroundImageSrc: imageURL( + featuredImageData.imageID, + "full", + "!1600,1600", + "0" + ), + foregroundImageSrc: imageURL( + featuredImageData.imageID, + "full", + "!900,900", + "0" + ), + uuid: featuredImageData.uuid, + title: featuredImageData.title, + href: `${DC_URL}/items/${featuredImageData.uuid}`, + }; + const newResponse = { + featuredItem: featuredItemObject, + numberOfDigitizedItems: numDigitizedItems, + }; + return newResponse; +}; + +export const getFeaturedImage = async () => { + const defaultResponse = defaultFeaturedItems.featuredItem; + const apiResponse = await getItemByIdentifier("featured", "", { + random: "true", + }); + + return { + uuid: apiResponse?.capture?.uuid || defaultResponse.uuid, + title: apiResponse?.capture?.title || defaultResponse.title, + imageID: apiResponse?.capture?.imageID || defaultResponse.imageID, + }; +}; + +/** + * + */ + +export const getItemData = async (uuid: string) => { + const apiUrl = `${process.env.API_URL}/api/v2/items/mods_captures/${uuid}`; + const res = await apiResponse(apiUrl); + return res; +}; + +/** + * Returns the number of digitized items in repo api. + */ + +export const getNumDigitizedItems = async () => { + const apiUrl = `${process.env.API_URL}/api/v2/items/total`; + const res = await apiResponse(apiUrl); + + const fallbackCount = defaultFeaturedItems.numberOfDigitizedItems; + const totalItems = res?.count?.$ ? addCommas(res.count.$) : fallbackCount; // only add commas to repo api response data + return totalItems; +}; + +/** + * Returns a map of uuids to its item count. + */ +export const getItemsCountFromUUIDs = async (uuids: string[]) => { + const apiUrl = `${process.env.API_URL}/api/v2/items/counts`; + const response = await apiResponse(apiUrl, { + method: "POST", + body: { uuids }, + }); + + const { counts } = response.nyplAPI.response; + if (!counts?.count?.length) { + return {}; + } + // The response is an array of objects: + // [ + // { uuid: { $: 'uuid1' }, count_value: { $: 'count1' }} + // ] + // We want to convert it to an object: + // { + // uuid1: count1 + // + const uuidCounts = counts?.count || []; + const cleanCounts = uuidCounts.reduce((acc: any, count: any) => { + acc[count.uuid["$"]] = count.count_value["$"]; + return acc; + }, {}); + return cleanCounts ? cleanCounts : {}; +}; + +/** + * Returns the uuid, API uri, and numResults of an item given an identifier type and identifier value. + * @param {string} identifierType - the identifier type + * @param {string} identifier - the identifier value + */ + +export const getItemByIdentifier = async ( + identifierType: string, + identifier: string, + urlParam?: { [key: string]: any } +) => { + const apiUrl = `${process.env.API_URL}/api/v2/items/${identifierType}/${identifier}`; + return apiResponse(apiUrl, { params: urlParam }); +}; + +export const getDivisionData = async ({ + pageNum = 1, + perPage = CARDS_PER_PAGE, + slug, +}: { + pageNum?: number; + perPage?: number; + slug?: string; +} = {}) => { + let apiUrl = `${process.env.API_URL}/api/v2/divisions`; + + if (slug) { + apiUrl += `/${slug}?page=${pageNum}&per_page=${perPage}`; + } + + const res = await apiResponse(apiUrl); + return res; +}; + +export const getLaneData = async ({ + pageNum = 1, + perPage = CARDS_PER_PAGE, + slug, +}: { + pageNum?: number; + perPage?: number; + slug?: string; +} = {}) => { + let apiUrl = `${process.env.API_URL}/api/v2/collections?genre=${slug}&page=${pageNum}&per_page=${perPage}`; + const res = await apiResponse(apiUrl); + return res; +}; + +/** + * Makes a GET or POST request to the Repo API and returns the response. + * Times out at 7 seconds to prevent 504 crash. + * @param {string} apiUrl - The URL for the API request. + * @param {object} options - Options for the request: + * - method: "GET" or "POST" (default is "GET"). + * - params: URL parameters for GET requests. + * - body: Body data for POST requests. + * @returns {Promise} - The API response. + */ +export const apiResponse = async ( + apiUrl: string, + options?: { + method?: "GET" | "POST"; + params?: { [key: string]: any }; + body?: any; + } +) => { + const apiKey = process.env.AUTH_TOKEN; + const method = options?.method || "GET"; + const headers = { + Authorization: `Token token=${apiKey}`, + ...(method === "POST" && { "Content-Type": "application/json" }), + }; + + if (method === "GET" && options?.params) { + const queryString = "?" + new URLSearchParams(options?.params).toString(); + apiUrl += queryString; + } + + const timeout = 14000; + + const fetchWithTimeout = (url: string, opts: RequestInit) => { + return Promise.race([ + fetch(url, opts), + new Promise((_, reject) => + setTimeout( + () => reject(new Error("apiResponse: Request timed out")), + timeout + ) + ), + ]); + }; + + try { + const response = (await fetchWithTimeout(apiUrl, { + method, + headers, + body: method === "POST" ? JSON.stringify(options?.body) : undefined, + })) as Response; + + if (!response.ok && response.status !== 200) { + throw new Error( + `apiResponse: ${response.status} ${ + response.statusText ? response.statusText : "No message" + }` + ); + } + + const data = await response.json(); + return method === "GET" ? data?.nyplAPI?.response : data; + } catch (error) { + console.error(error); + throw new Error(error.message); + } +}; diff --git a/app/src/utils/apiHelpers.test.tsx b/app/src/utils/apiHelpers.test.tsx index dac85559..c06f92e2 100644 --- a/app/src/utils/apiHelpers.test.tsx +++ b/app/src/utils/apiHelpers.test.tsx @@ -65,9 +65,9 @@ describe("getFeaturedItemData", () => { `${process.env.API_URL}/api/v2/items/total` ); // Fallback data. - expect(result.numberOfDigitizedItems).toEqual("875,861"); + expect(result.numberOfDigitizedItems).toEqual("1,059,731"); expect(result.featuredItem.imageID).toEqual( - defaultFeaturedItem.production.featuredItem.imageID + defaultFeaturedItem.featuredItem.imageID ); }); }); @@ -256,9 +256,7 @@ describe("getNumDigitizedItems", () => { const result = await getNumDigitizedItems(); // Fallback data. - expect(result).toEqual( - defaultFeaturedItem["development"].numberOfDigitizedItems - ); + expect(result).toEqual(defaultFeaturedItem.numberOfDigitizedItems); }); }); @@ -332,7 +330,7 @@ describe("getRandomFeaturedItem", () => { describe("getFeaturedImage", () => { it("returns expected image", async () => { (fetchApi as jest.Mock).mockResolvedValueOnce( - Promise.resolve(defaultFeaturedItem["production"].featuredItem) + Promise.resolve(defaultFeaturedItem.featuredItem) ); const imageData = await getFeaturedImage(); expect(fetchApi as jest.Mock).toHaveBeenCalledWith( @@ -353,9 +351,7 @@ describe("getFeaturedImage", () => { const imageData = await getFeaturedImage(); // Fallback data. - expect(imageData.uuid).toEqual( - defaultFeaturedItem["development"].featuredItem.uuid - ); + expect(imageData.uuid).toEqual(defaultFeaturedItem.featuredItem.uuid); }); }); diff --git a/app/src/utils/apiHelpers.ts b/app/src/utils/apiHelpers.ts index c601b02e..b5910d93 100644 --- a/app/src/utils/apiHelpers.ts +++ b/app/src/utils/apiHelpers.ts @@ -27,7 +27,6 @@ export const getHomePageData = async () => { }); const newResponse = { randomNumber, lanesWithNumItems: updatedLanes }; - console.log("new response is: ", newResponse); return newResponse; }; diff --git a/public/CHANGELOG.md b/public/CHANGELOG.md index bfb51dea..3cc2e144 100644 --- a/public/CHANGELOG.md +++ b/public/CHANGELOG.md @@ -9,10 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Updated - refactored implementation of default featured item & updated default number of digitized items (DR-3305) + +### Added + +- Added tests for API helpers (DR-3271) + + ### Updated - Update thumbnail logic so thumbnails are never restricted (DR-3293) + ## [0.2.4] 2024-11-26 ### Updated From dddda3b6cae95cdeab26dc77dc5686f2fd3226d2 Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 3 Dec 2024 09:34:49 -0500 Subject: [PATCH 04/11] changelog cleanup --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cc2e144..da1f6905 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased + ### Updated - refactored implementation of default featured item & updated default number of digitized items (DR-3305) - ### Added - Added tests for API helpers (DR-3271) From e8c63d015b02652d338090cb8c473652917d197e Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 3 Dec 2024 09:35:43 -0500 Subject: [PATCH 05/11] update link for default featured item' --- app/src/data/defaultFeaturedItemData.ts | 2 +- public/CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/data/defaultFeaturedItemData.ts b/app/src/data/defaultFeaturedItemData.ts index 268d4d86..73f10225 100644 --- a/app/src/data/defaultFeaturedItemData.ts +++ b/app/src/data/defaultFeaturedItemData.ts @@ -7,7 +7,7 @@ const defaultFeaturedItem: FeaturedItemDataType = { foregroundImageSrc: "/482815.jpg", uuid: "510d47d9-4f93-a3d9-e040-e00a18064a99", title: "Watuppa, From water front, Brooklyn", - href: "https://qa-digitalcollections.nypl.org/items/510d47d9-4f93-a3d9-e040-e00a18064a99", + href: "/items/510d47d9-4f93-a3d9-e040-e00a18064a99", }, numberOfDigitizedItems: "1,059,731", }; diff --git a/public/CHANGELOG.md b/public/CHANGELOG.md index 3cc2e144..da1f6905 100644 --- a/public/CHANGELOG.md +++ b/public/CHANGELOG.md @@ -6,10 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased + ### Updated - refactored implementation of default featured item & updated default number of digitized items (DR-3305) - ### Added - Added tests for API helpers (DR-3271) From c640d377e3871851d88496fb2df739e4c7a7e072 Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 3 Dec 2024 09:42:24 -0500 Subject: [PATCH 06/11] skip campaign hero test --- app/src/components/featuredItem/campaignHero.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/components/featuredItem/campaignHero.test.tsx b/app/src/components/featuredItem/campaignHero.test.tsx index e16ba702..9c2af294 100644 --- a/app/src/components/featuredItem/campaignHero.test.tsx +++ b/app/src/components/featuredItem/campaignHero.test.tsx @@ -18,7 +18,7 @@ describe("Campaign Hero", () => { }); }); - it("renders the fallback image if the image returns an error", async () => { + it.skip("renders the fallback image if the image returns an error", async () => { const mockFeaturedItemData = { featuredItem: { imageID: "1269908", From 7aef375763b8dcb650d5309295b6ee93c3357fae Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 3 Dec 2024 09:54:57 -0500 Subject: [PATCH 07/11] public changelog --- public/CHANGELOG.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/public/CHANGELOG.md b/public/CHANGELOG.md index d3e4914f..4e341992 100644 --- a/public/CHANGELOG.md +++ b/public/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Removed + - removed unneccessary variables post reverse proxy launch - Removed new relic files from frontend (DR-3311) @@ -15,19 +16,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added tests for API helpers (DR-3271) -### Updated -- refactored implementation of default featured item & updated default number of digitized items (DR-3305) - -### Added - -- Added tests for API helpers (DR-3271) - - ### Updated +- refactored implementation of default featured item & updated default number of digitized items (DR-3305) - Update thumbnail logic so thumbnails are never restricted (DR-3293) - ## [0.2.4] 2024-11-26 ### Updated From e6317f396d103fdb33f9ce575da9f4accef4da27 Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 3 Dec 2024 10:22:24 -0500 Subject: [PATCH 08/11] unskip broken test --- app/src/components/featuredItem/campaignHero.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/components/featuredItem/campaignHero.test.tsx b/app/src/components/featuredItem/campaignHero.test.tsx index 9c2af294..1eebbb49 100644 --- a/app/src/components/featuredItem/campaignHero.test.tsx +++ b/app/src/components/featuredItem/campaignHero.test.tsx @@ -18,7 +18,7 @@ describe("Campaign Hero", () => { }); }); - it.skip("renders the fallback image if the image returns an error", async () => { + it("renders the fallback image if the image returns an error", async () => { const mockFeaturedItemData = { featuredItem: { imageID: "1269908", @@ -26,7 +26,7 @@ describe("Campaign Hero", () => { foregroundImageSrc: "/foobar.jpg", uuid: "510d47e0-cb17-a3d9-e040-e00a18064a99", title: "Momoyogusa", - href: "https://digitalcollections.nypl.org/items/510d47e0-cb17-a3d9-e040-e00a18064a99", + href: "/items/510d47e0-cb17-a3d9-e040-e00a18064a99", }, numberOfDigitizedItems: "876,067", }; From 58ecb793f83decec351ceea613ac34f2a0f190d1 Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 3 Dec 2024 10:32:25 -0500 Subject: [PATCH 09/11] oops --- app/src/utils/api.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/utils/api.ts b/app/src/utils/api.ts index cc2799d8..ee8fda75 100644 --- a/app/src/utils/api.ts +++ b/app/src/utils/api.ts @@ -3,7 +3,6 @@ import type { LaneDataType } from "../../src/types/Lane"; import { imageURL, addCommas } from "../utils/utils"; import defaultFeaturedItems from "../data/defaultFeaturedItemData"; import { CARDS_PER_PAGE } from "../config/constants"; -import { DC_URL } from "../config/constants"; export const getHomePageData = async () => { const randomNumber = Math.floor(Math.random() * 2); @@ -50,7 +49,7 @@ export const getFeaturedItemData = async () => { ), uuid: featuredImageData.uuid, title: featuredImageData.title, - href: `${DC_URL}/items/${featuredImageData.uuid}`, + href: `/items/${featuredImageData.uuid}`, }; const newResponse = { featuredItem: featuredItemObject, From 33f09c3c142e65318b9a439318cb7616de58df5c Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 3 Dec 2024 11:10:17 -0500 Subject: [PATCH 10/11] remove api file --- app/src/utils/api.ts | 240 ------------------------------------------- 1 file changed, 240 deletions(-) delete mode 100644 app/src/utils/api.ts diff --git a/app/src/utils/api.ts b/app/src/utils/api.ts deleted file mode 100644 index ee8fda75..00000000 --- a/app/src/utils/api.ts +++ /dev/null @@ -1,240 +0,0 @@ -import data from "../../src/data/lanes"; -import type { LaneDataType } from "../../src/types/Lane"; -import { imageURL, addCommas } from "../utils/utils"; -import defaultFeaturedItems from "../data/defaultFeaturedItemData"; -import { CARDS_PER_PAGE } from "../config/constants"; - -export const getHomePageData = async () => { - const randomNumber = Math.floor(Math.random() * 2); - const lanes: LaneDataType[] = data.lanes as unknown as LaneDataType[]; - - // Get all the UUIDs from the collections - const allCollectionUUIDs: string[] = lanes.reduce((acc, lane) => { - return acc.concat(lane.collections.map((collection) => collection.uuid)); - }, [] as string[]); - const uuidtoItemCountMap = await getItemsCountFromUUIDs(allCollectionUUIDs); - - // Update the collections for each lane with the number of items - const updatedLanes = lanes.map((lane) => { - const updatedCollections = lane.collections.map((collection) => { - return { - ...collection, - numberOfDigitizedItems: uuidtoItemCountMap[collection.uuid] || "0", - }; - }); - return { ...lane, collections: updatedCollections }; - }); - - const newResponse = { randomNumber, lanesWithNumItems: updatedLanes }; - return newResponse; -}; - -export const getFeaturedItemData = async () => { - const featuredImageData = await getFeaturedImage(); - const numDigitizedItems = await getNumDigitizedItems(); - - const featuredItemObject = { - imageID: featuredImageData.imageID, - backgroundImageSrc: imageURL( - featuredImageData.imageID, - "full", - "!1600,1600", - "0" - ), - foregroundImageSrc: imageURL( - featuredImageData.imageID, - "full", - "!900,900", - "0" - ), - uuid: featuredImageData.uuid, - title: featuredImageData.title, - href: `/items/${featuredImageData.uuid}`, - }; - const newResponse = { - featuredItem: featuredItemObject, - numberOfDigitizedItems: numDigitizedItems, - }; - return newResponse; -}; - -export const getFeaturedImage = async () => { - const defaultResponse = defaultFeaturedItems.featuredItem; - const apiResponse = await getItemByIdentifier("featured", "", { - random: "true", - }); - - return { - uuid: apiResponse?.capture?.uuid || defaultResponse.uuid, - title: apiResponse?.capture?.title || defaultResponse.title, - imageID: apiResponse?.capture?.imageID || defaultResponse.imageID, - }; -}; - -/** - * - */ - -export const getItemData = async (uuid: string) => { - const apiUrl = `${process.env.API_URL}/api/v2/items/mods_captures/${uuid}`; - const res = await apiResponse(apiUrl); - return res; -}; - -/** - * Returns the number of digitized items in repo api. - */ - -export const getNumDigitizedItems = async () => { - const apiUrl = `${process.env.API_URL}/api/v2/items/total`; - const res = await apiResponse(apiUrl); - - const fallbackCount = defaultFeaturedItems.numberOfDigitizedItems; - const totalItems = res?.count?.$ ? addCommas(res.count.$) : fallbackCount; // only add commas to repo api response data - return totalItems; -}; - -/** - * Returns a map of uuids to its item count. - */ -export const getItemsCountFromUUIDs = async (uuids: string[]) => { - const apiUrl = `${process.env.API_URL}/api/v2/items/counts`; - const response = await apiResponse(apiUrl, { - method: "POST", - body: { uuids }, - }); - - const { counts } = response.nyplAPI.response; - if (!counts?.count?.length) { - return {}; - } - // The response is an array of objects: - // [ - // { uuid: { $: 'uuid1' }, count_value: { $: 'count1' }} - // ] - // We want to convert it to an object: - // { - // uuid1: count1 - // - const uuidCounts = counts?.count || []; - const cleanCounts = uuidCounts.reduce((acc: any, count: any) => { - acc[count.uuid["$"]] = count.count_value["$"]; - return acc; - }, {}); - return cleanCounts ? cleanCounts : {}; -}; - -/** - * Returns the uuid, API uri, and numResults of an item given an identifier type and identifier value. - * @param {string} identifierType - the identifier type - * @param {string} identifier - the identifier value - */ - -export const getItemByIdentifier = async ( - identifierType: string, - identifier: string, - urlParam?: { [key: string]: any } -) => { - const apiUrl = `${process.env.API_URL}/api/v2/items/${identifierType}/${identifier}`; - return apiResponse(apiUrl, { params: urlParam }); -}; - -export const getDivisionData = async ({ - pageNum = 1, - perPage = CARDS_PER_PAGE, - slug, -}: { - pageNum?: number; - perPage?: number; - slug?: string; -} = {}) => { - let apiUrl = `${process.env.API_URL}/api/v2/divisions`; - - if (slug) { - apiUrl += `/${slug}?page=${pageNum}&per_page=${perPage}`; - } - - const res = await apiResponse(apiUrl); - return res; -}; - -export const getLaneData = async ({ - pageNum = 1, - perPage = CARDS_PER_PAGE, - slug, -}: { - pageNum?: number; - perPage?: number; - slug?: string; -} = {}) => { - let apiUrl = `${process.env.API_URL}/api/v2/collections?genre=${slug}&page=${pageNum}&per_page=${perPage}`; - const res = await apiResponse(apiUrl); - return res; -}; - -/** - * Makes a GET or POST request to the Repo API and returns the response. - * Times out at 7 seconds to prevent 504 crash. - * @param {string} apiUrl - The URL for the API request. - * @param {object} options - Options for the request: - * - method: "GET" or "POST" (default is "GET"). - * - params: URL parameters for GET requests. - * - body: Body data for POST requests. - * @returns {Promise} - The API response. - */ -export const apiResponse = async ( - apiUrl: string, - options?: { - method?: "GET" | "POST"; - params?: { [key: string]: any }; - body?: any; - } -) => { - const apiKey = process.env.AUTH_TOKEN; - const method = options?.method || "GET"; - const headers = { - Authorization: `Token token=${apiKey}`, - ...(method === "POST" && { "Content-Type": "application/json" }), - }; - - if (method === "GET" && options?.params) { - const queryString = "?" + new URLSearchParams(options?.params).toString(); - apiUrl += queryString; - } - - const timeout = 14000; - - const fetchWithTimeout = (url: string, opts: RequestInit) => { - return Promise.race([ - fetch(url, opts), - new Promise((_, reject) => - setTimeout( - () => reject(new Error("apiResponse: Request timed out")), - timeout - ) - ), - ]); - }; - - try { - const response = (await fetchWithTimeout(apiUrl, { - method, - headers, - body: method === "POST" ? JSON.stringify(options?.body) : undefined, - })) as Response; - - if (!response.ok && response.status !== 200) { - throw new Error( - `apiResponse: ${response.status} ${ - response.statusText ? response.statusText : "No message" - }` - ); - } - - const data = await response.json(); - return method === "GET" ? data?.nyplAPI?.response : data; - } catch (error) { - console.error(error); - throw new Error(error.message); - } -}; From 1b8de63ca7b49fd9fb1755ebaa37f3e04ae5d416 Mon Sep 17 00:00:00 2001 From: Alessandra Vertrees Date: Tue, 3 Dec 2024 14:00:22 -0500 Subject: [PATCH 11/11] fix test --- app/src/components/featuredItem/campaignHero.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/components/featuredItem/campaignHero.tsx b/app/src/components/featuredItem/campaignHero.tsx index 450b19d3..827e8324 100644 --- a/app/src/components/featuredItem/campaignHero.tsx +++ b/app/src/components/featuredItem/campaignHero.tsx @@ -1,17 +1,14 @@ import { Hero } from "@nypl/design-system-react-components"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import CampaignHeroSubText from "./campaignHeroSubText"; import CampaignHeroHeading from "./campaignHeroHeading"; import CampaignHeroLoading from "./campaignHeroLoading"; import defaultFeaturedItem from "../../data/defaultFeaturedItemData"; -import appConfig from "../../../../appConfig"; import { FeaturedItemDataType } from "../../types/FeaturedItemDataType"; import React from "react"; -import { ENV_KEY } from "../../types/EnvironmentType"; const CampaignHero = ({ featuredItemData }) => { - const defaultFeaturedItemResponse = - defaultFeaturedItem[appConfig["environment"] as ENV_KEY]; + const defaultFeaturedItemResponse = defaultFeaturedItem; const [data, setData] = useState( featuredItemData || defaultFeaturedItemResponse