From fcc1c3a98b42c73af67e66f158e949079c474ea5 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 09:49:22 -0500 Subject: [PATCH 01/44] add build avail key and use switch statment --- src/components/ItemTable/ItemAvailability.tsx | 87 +++++++++---------- src/models/Item.ts | 3 + src/models/ItemAvailability.tsx | 30 +++++++ 3 files changed, 75 insertions(+), 45 deletions(-) create mode 100644 src/models/ItemAvailability.tsx diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 646ba63c7..39cd84055 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -26,15 +26,14 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { // TODO: Move this logic into a getter function in the Item class that returns an availability status key // and replace this nested If with a simple switch statement - if (item.isAvailable) { - if (item.isReCAP && !item.aeonUrl) { - // Available ReCAP item + switch (item.availabilityKey) { + case "availableRecap": return ( How do I pick up this item and when will it be ready? ) - } else if (item.aeonUrl && item.location?.endpoint) { + case "availableAeon": return ( { ) : null} ) - } else { - // Available Onsite item + case "availableOnsite": { const locationShort = item.location.prefLabel.split("-")[0] return ( { ) } - } else { - // Not available - return ( - - - Not available - - {item.dueDate && ` - In use until ${item.dueDate}`} - {" - Please "} - - {" for assistance."} - - ) + + Not available + + {item.dueDate && ` - In use until ${item.dueDate}`} + {" - Please "} + + {" for assistance."} + + ) } } diff --git a/src/models/Item.ts b/src/models/Item.ts index 436ee500a..d6ae935bb 100644 --- a/src/models/Item.ts +++ b/src/models/Item.ts @@ -12,6 +12,7 @@ import { locationEndpointsMap, } from "../utils/itemUtils" import { appConfig } from "../config/config" +import ItemAvailability from "./ItemAvailability" /** * The Item class contains the data and getter functions @@ -34,6 +35,7 @@ export default class Item { isPhysicallyRequestable: boolean isEDDRequestable: boolean bibTitle: string + availabilityKey: string constructor(item: DiscoveryItemResult, bib: Bib) { this.id = item.uri || "" @@ -57,6 +59,7 @@ export default class Item { this.isPhysicallyRequestable = item.physRequestable this.isEDDRequestable = item.eddRequestable this.bibTitle = bib.titleDisplay + this.availabilityKey = new ItemAvailability(this).availabilityKey } // Item availability is determined by the existence of status id in the availability ids list diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx new file mode 100644 index 000000000..478affb88 --- /dev/null +++ b/src/models/ItemAvailability.tsx @@ -0,0 +1,30 @@ +import type Item from "./Item" + +class ItemAvailability { + item: Item + availabilityKey: string + constructor(item: Item) { + this.item = item + this.availabilityKey = this.buildAvailabilityKey() + } + buildAvailabilityKey() { + if (this.item.isAvailable && this.item.isReCAP && !this.item.aeonUrl) { + return "availableRecap" + } + if ( + this.item.isAvailable && + this.item.aeonUrl && + this.item.location?.endpoint + ) { + return "availableAeon" + } + if (this.item.isAvailable && !this.item.isReCAP) { + return "availableOnsite" + } + if (!this.item.isAvailable) { + return "notAvailable" + } + } +} + +export default ItemAvailability From c9e80754ff5608f1bfd67ef9d73f2752d1478763 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 09:57:29 -0500 Subject: [PATCH 02/44] extract contact a librarian --- src/components/ItemTable/ItemAvailability.tsx | 39 ++-------------- .../ContactALibrarian.tsx | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+), 36 deletions(-) create mode 100644 src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 39cd84055..4284f216f 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -1,11 +1,9 @@ -import { useContext } from "react" -import { Text, Button, Box } from "@nypl/design-system-react-components" +import { Text, Box } from "@nypl/design-system-react-components" import ExternalLink from "../Links/ExternalLink/ExternalLink" import { appConfig } from "../../config/config" import type Item from "../../models/Item" -import { FeedbackContext } from "../../context/FeedbackContext" -import type { ItemMetadata } from "../../types/itemTypes" +import ContactALibrarian from "./ItemAvailabilityComponents/ContactALibrarian" interface ItemAvailabilityProps { item: Item @@ -17,13 +15,6 @@ interface ItemAvailabilityProps { * TODO: Add Feedback box, Due date, Available font styles */ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { - const { onOpen, setItemMetadata } = useContext(FeedbackContext) - - const onContact = (metadata: ItemMetadata) => { - setItemMetadata(metadata) - onOpen() - } - // TODO: Move this logic into a getter function in the Item class that returns an availability status key // and replace this nested If with a simple switch statement switch (item.availabilityKey) { @@ -93,31 +84,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { Not available {item.dueDate && ` - In use until ${item.dueDate}`} - {" - Please "} - - {" for assistance."} + ) } diff --git a/src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx b/src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx new file mode 100644 index 000000000..f9b87a3ed --- /dev/null +++ b/src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx @@ -0,0 +1,44 @@ +import { Button } from "@nypl/design-system-react-components" +import { useContext } from "react" +import { FeedbackContext } from "../../../context/FeedbackContext" +import type { ItemMetadata } from "../../../types/itemTypes" +import type Item from "../../../models/Item" + +const ContactALibrarian = ({ item }: { item: Item }) => { + const { onOpen, setItemMetadata } = useContext(FeedbackContext) + const onContact = (metadata: ItemMetadata) => { + setItemMetadata(metadata) + onOpen() + } + return ( + <> + {" - Please "} + + {" for assistance."} + + ) +} + +export default ContactALibrarian From dba9aa87e743faebd5d3041b5a5297e5c82a00e8 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 10:23:22 -0500 Subject: [PATCH 03/44] extract all availability messaging --- .../ItemTable/ItemAvailability.test.tsx | 1 + src/components/ItemTable/ItemAvailability.tsx | 98 ++++++------------- .../AvailableByAppointment.tsx | 25 +++++ .../AvailableOnsite.tsx | 24 +++++ .../NotAvailable.tsx | 17 ++++ 5 files changed, 95 insertions(+), 70 deletions(-) create mode 100644 src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx create mode 100644 src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx create mode 100644 src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx diff --git a/src/components/ItemTable/ItemAvailability.test.tsx b/src/components/ItemTable/ItemAvailability.test.tsx index 938318cfb..8fde4c30d 100644 --- a/src/components/ItemTable/ItemAvailability.test.tsx +++ b/src/components/ItemTable/ItemAvailability.test.tsx @@ -29,6 +29,7 @@ describe("ItemAvailability", () => { }) it("renders the correct text when item is available, has an aeon url, and has a location endpoint", async () => { const item = new Item(itemPhysicallyRequestable, parentBib) + render() expect(screen.getByText("Available by appointment")).toBeInTheDocument() expect( diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 4284f216f..734398327 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -3,7 +3,9 @@ import { Text, Box } from "@nypl/design-system-react-components" import ExternalLink from "../Links/ExternalLink/ExternalLink" import { appConfig } from "../../config/config" import type Item from "../../models/Item" -import ContactALibrarian from "./ItemAvailabilityComponents/ContactALibrarian" +import AvailableByAppointment from "./ItemAvailabilityComponents/AvailableByAppointment" +import NotAvailable from "./ItemAvailabilityComponents/NotAvailable" +import AvailableOnsite from "./ItemAvailabilityComponents/AvailableOnsite" interface ItemAvailabilityProps { item: Item @@ -15,79 +17,35 @@ interface ItemAvailabilityProps { * TODO: Add Feedback box, Due date, Available font styles */ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { - // TODO: Move this logic into a getter function in the Item class that returns an availability status key - // and replace this nested If with a simple switch statement + let availabilityMessage + if (item.availabilityKey === "availableRecap") { + return ( + + How do I pick up this item and when will it be ready? + + ) + } switch (item.availabilityKey) { - case "availableRecap": - return ( - - How do I pick up this item and when will it be ready? - - ) case "availableAeon": - return ( - - - Available by appointment - - {!item.isReCAP ? ( - <> - {" at "} - - {item.location.prefLabel} - - - ) : null} - - ) - case "availableOnsite": { - const locationShort = item.location.prefLabel.split("-")[0] - return ( - - - Available - - {" - Can be used on site. Please visit "} - - {`New York Public Library - ${locationShort}`} - - {" to submit a request in person."} - - ) - } + availabilityMessage = + break + case "availableOnsite": + availabilityMessage = + break case "notAvailable": - return ( - - - Not available - - {item.dueDate && ` - In use until ${item.dueDate}`} - - - ) + availabilityMessage = } + return ( + + {availabilityMessage} + + ) } export default ItemAvailability diff --git a/src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx b/src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx new file mode 100644 index 000000000..c6974dc58 --- /dev/null +++ b/src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx @@ -0,0 +1,25 @@ +import { Box } from "@nypl/design-system-react-components" +import { appConfig } from "../../../config/config" +import ExternalLink from "../../Links/ExternalLink/ExternalLink" + +const AvailableByAppointment = ({ item }) => { + return ( + <> + + Available by appointment + + {!item.isReCAP && ( + <> + {" at "} + + {item.location.prefLabel} + + + )} + + ) +} + +export default AvailableByAppointment diff --git a/src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx b/src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx new file mode 100644 index 000000000..f794a6577 --- /dev/null +++ b/src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx @@ -0,0 +1,24 @@ +import { Box } from "@nypl/design-system-react-components" +import { appConfig } from "../../../config/config" +import type Item from "../../../models/Item" +import ExternalLink from "../../Links/ExternalLink/ExternalLink" + +const AvailableOnsite = ({ item }: { item: Item }) => { + const locationShort = item.location.prefLabel.split("-")[0] + return ( + <> + + Available + + {" - Can be used on site. Please visit "} + + {`New York Public Library - ${locationShort}`} + + {" to submit a request in person."} + + ) +} + +export default AvailableOnsite diff --git a/src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx b/src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx new file mode 100644 index 000000000..45281b601 --- /dev/null +++ b/src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx @@ -0,0 +1,17 @@ +import { Box } from "@nypl/design-system-react-components" +import type Item from "../../../models/Item" +import ContactALibrarian from "./ContactALibrarian" + +const NotAvailable = ({ item }: { item: Item }) => { + return ( + <> + + Not available + + {item.dueDate && ` - In use until ${item.dueDate}`} + + + ) +} + +export default NotAvailable From 879ef5b4fa876de4b2c7f9ff8e8cb7ab5c154ec9 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 10:29:54 -0500 Subject: [PATCH 04/44] move availability componetns to model --- src/components/ItemTable/ItemAvailability.tsx | 16 +++------------ src/models/Item.ts | 4 ++-- src/models/ItemAvailability.tsx | 20 ++++++++++++++++--- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 734398327..9aa71a971 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -17,24 +17,14 @@ interface ItemAvailabilityProps { * TODO: Add Feedback box, Due date, Available font styles */ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { - let availabilityMessage - if (item.availabilityKey === "availableRecap") { + if (item.availability.key === "availableRecap") { return ( How do I pick up this item and when will it be ready? ) } - switch (item.availabilityKey) { - case "availableAeon": - availabilityMessage = - break - case "availableOnsite": - availabilityMessage = - break - case "notAvailable": - availabilityMessage = - } + return ( { md: "desktop.body.body2", }} > - {availabilityMessage} + {item.availability.message()} ) } diff --git a/src/models/Item.ts b/src/models/Item.ts index d6ae935bb..787c3051d 100644 --- a/src/models/Item.ts +++ b/src/models/Item.ts @@ -35,7 +35,7 @@ export default class Item { isPhysicallyRequestable: boolean isEDDRequestable: boolean bibTitle: string - availabilityKey: string + availability: ItemAvailability constructor(item: DiscoveryItemResult, bib: Bib) { this.id = item.uri || "" @@ -59,7 +59,7 @@ export default class Item { this.isPhysicallyRequestable = item.physRequestable this.isEDDRequestable = item.eddRequestable this.bibTitle = bib.titleDisplay - this.availabilityKey = new ItemAvailability(this).availabilityKey + this.availability = new ItemAvailability(this) } // Item availability is determined by the existence of status id in the availability ids list diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index 478affb88..4eb6ae686 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -1,13 +1,17 @@ +import type { JsxElement } from "typescript" import type Item from "./Item" +import AvailableByAppointment from "../components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment" +import AvailableOnsite from "../components/ItemTable/ItemAvailabilityComponents/AvailableOnsite" +import NotAvailable from "../components/ItemTable/ItemAvailabilityComponents/NotAvailable" class ItemAvailability { item: Item - availabilityKey: string + key: string constructor(item: Item) { this.item = item - this.availabilityKey = this.buildAvailabilityKey() + this.key = this.buildKey() } - buildAvailabilityKey() { + buildKey() { if (this.item.isAvailable && this.item.isReCAP && !this.item.aeonUrl) { return "availableRecap" } @@ -25,6 +29,16 @@ class ItemAvailability { return "notAvailable" } } + message() { + switch (this.key) { + case "availableAeon": + return + case "availableOnsite": + return + case "notAvailable": + return + } + } } export default ItemAvailability From 9d67c2e91f1ddd68ccc106e3248c1343e3fe2b4d Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 11:02:45 -0500 Subject: [PATCH 05/44] use constants for avail keys --- src/components/ItemTable/ItemAvailability.tsx | 5 +---- src/config/constants.ts | 8 ++++++++ src/models/ItemAvailability.tsx | 18 ++++++++++-------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 9aa71a971..66b88b876 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -1,11 +1,8 @@ -import { Text, Box } from "@nypl/design-system-react-components" +import { Text } from "@nypl/design-system-react-components" import ExternalLink from "../Links/ExternalLink/ExternalLink" import { appConfig } from "../../config/config" import type Item from "../../models/Item" -import AvailableByAppointment from "./ItemAvailabilityComponents/AvailableByAppointment" -import NotAvailable from "./ItemAvailabilityComponents/NotAvailable" -import AvailableOnsite from "./ItemAvailabilityComponents/AvailableOnsite" interface ItemAvailabilityProps { item: Item diff --git a/src/config/constants.ts b/src/config/constants.ts index c6f2ad2e9..f01e7881e 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -134,3 +134,11 @@ export const NYPL_LOCATIONS = { address: "476 Fifth Avenue (42nd St and Fifth Ave)", }, } + +export const availabilityKeys = { + AVAILABLE_RECAP: "availableRecap", + AVAILABLE_RECAP_AEON: "availableRecapAeon", + AVAILABLE_AEON: "availableAeon", + AVAILABLE_ONSITE: "availableOnsite", + NOT_AVAILABLE: "notAvailable", +} diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index 4eb6ae686..d420d0993 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -1,8 +1,8 @@ -import type { JsxElement } from "typescript" import type Item from "./Item" import AvailableByAppointment from "../components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment" import AvailableOnsite from "../components/ItemTable/ItemAvailabilityComponents/AvailableOnsite" import NotAvailable from "../components/ItemTable/ItemAvailabilityComponents/NotAvailable" +import { availabilityKeys } from "../config/constants" class ItemAvailability { item: Item @@ -13,29 +13,31 @@ class ItemAvailability { } buildKey() { if (this.item.isAvailable && this.item.isReCAP && !this.item.aeonUrl) { - return "availableRecap" + return availabilityKeys.AVAILABLE_RECAP } if ( this.item.isAvailable && this.item.aeonUrl && this.item.location?.endpoint ) { - return "availableAeon" + return availabilityKeys.AVAILABLE_AEON } if (this.item.isAvailable && !this.item.isReCAP) { - return "availableOnsite" + return availabilityKeys.AVAILABLE_ONSITE } if (!this.item.isAvailable) { - return "notAvailable" + return availabilityKeys.NOT_AVAILABLE } } message() { switch (this.key) { - case "availableAeon": + case availabilityKeys.AVAILABLE_RECAP: + throw "This key doesn't have a message. This component should be returning earlier than this." + case availabilityKeys.AVAILABLE_AEON: return - case "availableOnsite": + case availabilityKeys.AVAILABLE_ONSITE: return - case "notAvailable": + case availabilityKeys.NOT_AVAILABLE: return } } From 287ba38738f080330120bbb7651946660f4d61d7 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 11:06:57 -0500 Subject: [PATCH 06/44] use consttants for keys --- src/components/ItemTable/ItemAvailability.tsx | 3 ++- src/config/constants.ts | 9 +++++---- src/models/ItemAvailability.tsx | 12 ++++++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 66b88b876..94298f6cd 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -3,6 +3,7 @@ import { Text } from "@nypl/design-system-react-components" import ExternalLink from "../Links/ExternalLink/ExternalLink" import { appConfig } from "../../config/config" import type Item from "../../models/Item" +import { availabilityKeys } from "../../config/constants" interface ItemAvailabilityProps { item: Item @@ -14,7 +15,7 @@ interface ItemAvailabilityProps { * TODO: Add Feedback box, Due date, Available font styles */ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { - if (item.availability.key === "availableRecap") { + if (item.availability.key === availabilityKeys.RECAP) { return ( How do I pick up this item and when will it be ready? diff --git a/src/config/constants.ts b/src/config/constants.ts index f01e7881e..82cc27be7 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -136,9 +136,10 @@ export const NYPL_LOCATIONS = { } export const availabilityKeys = { - AVAILABLE_RECAP: "availableRecap", - AVAILABLE_RECAP_AEON: "availableRecapAeon", - AVAILABLE_AEON: "availableAeon", - AVAILABLE_ONSITE: "availableOnsite", + // there is only one not available case, so availability is assumed as the default + RECAP: "Recap", + RECAP_AEON: "RecapAeon", + AEON: "Aeon", + ONSITE: "Onsite", NOT_AVAILABLE: "notAvailable", } diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index d420d0993..9ee3943c1 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -13,17 +13,17 @@ class ItemAvailability { } buildKey() { if (this.item.isAvailable && this.item.isReCAP && !this.item.aeonUrl) { - return availabilityKeys.AVAILABLE_RECAP + return availabilityKeys.RECAP } if ( this.item.isAvailable && this.item.aeonUrl && this.item.location?.endpoint ) { - return availabilityKeys.AVAILABLE_AEON + return availabilityKeys.AEON } if (this.item.isAvailable && !this.item.isReCAP) { - return availabilityKeys.AVAILABLE_ONSITE + return availabilityKeys.ONSITE } if (!this.item.isAvailable) { return availabilityKeys.NOT_AVAILABLE @@ -31,11 +31,11 @@ class ItemAvailability { } message() { switch (this.key) { - case availabilityKeys.AVAILABLE_RECAP: + case availabilityKeys.RECAP: throw "This key doesn't have a message. This component should be returning earlier than this." - case availabilityKeys.AVAILABLE_AEON: + case availabilityKeys.AEON: return - case availabilityKeys.AVAILABLE_ONSITE: + case availabilityKeys.ONSITE: return case availabilityKeys.NOT_AVAILABLE: return From d2415ef9a4e066bb6d556d850221618dab5c0a0e Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 11:30:52 -0500 Subject: [PATCH 07/44] add finding aid to bib model; --- src/models/Bib.ts | 4 ++++ src/models/modelTests/Bib.test.ts | 31 ++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/models/Bib.ts b/src/models/Bib.ts index a7fc54cd9..d20fdad61 100644 --- a/src/models/Bib.ts +++ b/src/models/Bib.ts @@ -30,6 +30,7 @@ export default class Bib { itemAggregations?: Aggregation[] hasItemDates?: boolean subjectHeadings?: SubjectHeading[] + findingAid?: string constructor(result: DiscoveryBibResult) { this.id = result["@id"] ? result["@id"].substring(4) : "" @@ -45,6 +46,9 @@ export default class Bib { this.itemAggregations = result.itemAggregations || null this.hasItemDates = result.hasItemDates || false this.subjectHeadings = result.subjectHeadings || null + this.findingAid = + result.supplementaryContent?.find((el) => el.label === "Finding aid") + ?.url || null } get url() { diff --git a/src/models/modelTests/Bib.test.ts b/src/models/modelTests/Bib.test.ts index 592572f40..595a3235b 100644 --- a/src/models/modelTests/Bib.test.ts +++ b/src/models/modelTests/Bib.test.ts @@ -1,4 +1,7 @@ -import { bibWithItems } from "../../../__test__/fixtures/bibFixtures" +import { + bibWithItems, + bibWithSupplementaryContent, +} from "../../../__test__/fixtures/bibFixtures" import Bib from "../Bib" import Item from "../Item" @@ -10,6 +13,32 @@ describe("Bib model", () => { }) describe("constructor", () => { + describe("findingAid", () => { + it("initializes the finding aid when present", () => { + const findingAidBib = new Bib({ + ...bibWithItems.resource, + supplementaryContent: [ + { + "@type": "nypl:SupplementaryContent", + label: "Finding aid", + url: "http://archives.nypl.org/scm/29990", + }, + ], + }) + expect(findingAidBib.findingAid).toBe( + "http://archives.nypl.org/scm/29990" + ) + }) + it("does not initialize finding aid when no aid but supp content", () => { + const bibWithSupplementaryContentModel = new Bib( + bibWithSupplementaryContent.resource + ) + expect(bibWithSupplementaryContentModel.findingAid).toBe(null) + }) + it("can handle no supplementary content", () => { + expect(bib.findingAid).toBe(null) + }) + }) it("initializes the Bib ID with the with the Bib's @id field", () => { expect(bib.id).toBe("b15080796") }) From c59596ffc3507bbb086d065e76f4a47ec3ab666a Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 11:32:06 -0500 Subject: [PATCH 08/44] add finding aid to item and availability models --- src/models/Item.ts | 2 +- src/models/ItemAvailability.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/models/Item.ts b/src/models/Item.ts index 787c3051d..441df8787 100644 --- a/src/models/Item.ts +++ b/src/models/Item.ts @@ -59,7 +59,7 @@ export default class Item { this.isPhysicallyRequestable = item.physRequestable this.isEDDRequestable = item.eddRequestable this.bibTitle = bib.titleDisplay - this.availability = new ItemAvailability(this) + this.availability = new ItemAvailability(this, bib.findingAid) } // Item availability is determined by the existence of status id in the availability ids list diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index 9ee3943c1..c5a70d824 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -7,9 +7,11 @@ import { availabilityKeys } from "../config/constants" class ItemAvailability { item: Item key: string - constructor(item: Item) { + findingAid: string + constructor(item: Item, findingAid: string) { this.item = item this.key = this.buildKey() + this.findingAid = findingAid } buildKey() { if (this.item.isAvailable && this.item.isReCAP && !this.item.aeonUrl) { From 383a6f9a9ec059e0c8a25c0ee0db1ef55d6f0753 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 13:42:10 -0500 Subject: [PATCH 09/44] start to split aeon statuses --- src/config/constants.ts | 1 + src/models/ItemAvailability.tsx | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/config/constants.ts b/src/config/constants.ts index 82cc27be7..41bd8b059 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -140,6 +140,7 @@ export const availabilityKeys = { RECAP: "Recap", RECAP_AEON: "RecapAeon", AEON: "Aeon", + ONSITE_AEON: "OnsiteAeon", ONSITE: "Onsite", NOT_AVAILABLE: "notAvailable", } diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index c5a70d824..31c8399d6 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -20,9 +20,18 @@ class ItemAvailability { if ( this.item.isAvailable && this.item.aeonUrl && - this.item.location?.endpoint + this.item.location?.endpoint && + this.item.isReCAP ) { - return availabilityKeys.AEON + return availabilityKeys.RECAP_AEON + } + if ( + this.item.isAvailable && + this.item.aeonUrl && + this.item.location?.endpoint && + !this.item.isReCAP + ) { + return availabilityKeys.ONSITE_AEON } if (this.item.isAvailable && !this.item.isReCAP) { return availabilityKeys.ONSITE @@ -35,7 +44,9 @@ class ItemAvailability { switch (this.key) { case availabilityKeys.RECAP: throw "This key doesn't have a message. This component should be returning earlier than this." - case availabilityKeys.AEON: + case availabilityKeys.RECAP_AEON: + return + case availabilityKeys.ONSITE_AEON: return case availabilityKeys.ONSITE: return From 03cb92fdf83c277079c81a60f369734bb498b170 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 14:30:31 -0500 Subject: [PATCH 10/44] actual refactor --- .../ItemTable/ItemAvailability.test.tsx | 1 + .../AvailableByAppointment.tsx | 25 +++--- .../AvailableOnsite.tsx | 9 +-- .../ContactALibrarian.tsx | 12 ++- .../NotAvailable.tsx | 18 ++++- src/models/Item.ts | 15 +++- src/models/ItemAvailability.tsx | 78 ++++++++++++++----- 7 files changed, 114 insertions(+), 44 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.test.tsx b/src/components/ItemTable/ItemAvailability.test.tsx index 8fde4c30d..ba84f6016 100644 --- a/src/components/ItemTable/ItemAvailability.test.tsx +++ b/src/components/ItemTable/ItemAvailability.test.tsx @@ -31,6 +31,7 @@ describe("ItemAvailability", () => { const item = new Item(itemPhysicallyRequestable, parentBib) render() + console.log("item after construction", item) expect(screen.getByText("Available by appointment")).toBeInTheDocument() expect( screen.getByText("Schwarzman Building - Main Reading Room 315") diff --git a/src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx b/src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx index c6974dc58..fdd560fdf 100644 --- a/src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx +++ b/src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx @@ -2,24 +2,25 @@ import { Box } from "@nypl/design-system-react-components" import { appConfig } from "../../../config/config" import ExternalLink from "../../Links/ExternalLink/ExternalLink" -const AvailableByAppointment = ({ item }) => { +const AvailableByAppointment = () => { return ( <> Available by appointment - {!item.isReCAP && ( - <> - {" at "} - - {item.location.prefLabel} - - - )} ) } -export default AvailableByAppointment +const AvailableAt = ({ location }) => { + return ( + <> + {" at "} + + {location.prefLabel} + + + ) +} + +export { AvailableByAppointment, AvailableAt } diff --git a/src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx b/src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx index f794a6577..87a15dde0 100644 --- a/src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx +++ b/src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx @@ -1,19 +1,16 @@ import { Box } from "@nypl/design-system-react-components" import { appConfig } from "../../../config/config" -import type Item from "../../../models/Item" import ExternalLink from "../../Links/ExternalLink/ExternalLink" -const AvailableOnsite = ({ item }: { item: Item }) => { - const locationShort = item.location.prefLabel.split("-")[0] +const AvailableOnsite = ({ location }) => { + const locationShort = location.prefLabel.split("-")[0] return ( <> Available {" - Can be used on site. Please visit "} - + {`New York Public Library - ${locationShort}`} {" to submit a request in person."} diff --git a/src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx b/src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx index f9b87a3ed..93fb67cd8 100644 --- a/src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx +++ b/src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx @@ -2,9 +2,17 @@ import { Button } from "@nypl/design-system-react-components" import { useContext } from "react" import { FeedbackContext } from "../../../context/FeedbackContext" import type { ItemMetadata } from "../../../types/itemTypes" -import type Item from "../../../models/Item" -const ContactALibrarian = ({ item }: { item: Item }) => { +const ContactALibrarian = ({ + item, +}: { + item: { + id: string + barcode: string + callNumber: string + bibId: string + } +}) => { const { onOpen, setItemMetadata } = useContext(FeedbackContext) const onContact = (metadata: ItemMetadata) => { setItemMetadata(metadata) diff --git a/src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx b/src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx index 45281b601..47128548e 100644 --- a/src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx +++ b/src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx @@ -1,15 +1,25 @@ import { Box } from "@nypl/design-system-react-components" -import type Item from "../../../models/Item" import ContactALibrarian from "./ContactALibrarian" -const NotAvailable = ({ item }: { item: Item }) => { +const NotAvailable = ({ + dueDate, + itemMetadata, +}: { + dueDate: string + itemMetadata: { + id: string + barcode: string + callNumber: string + bibId: string + } +}) => { return ( <> Not available - {item.dueDate && ` - In use until ${item.dueDate}`} - + {dueDate && ` - In use until ${dueDate}`} + ) } diff --git a/src/models/Item.ts b/src/models/Item.ts index 441df8787..121305a84 100644 --- a/src/models/Item.ts +++ b/src/models/Item.ts @@ -59,7 +59,20 @@ export default class Item { this.isPhysicallyRequestable = item.physRequestable this.isEDDRequestable = item.eddRequestable this.bibTitle = bib.titleDisplay - this.availability = new ItemAvailability(this, bib.findingAid) + this.availability = new ItemAvailability({ + location: this.location, + dueDate: this.dueDate, + isAvailable: this.isAvailable, + isReCAP: this.isReCAP, + aeonUrl: this.aeonUrl, + findingAid: bib.findingAid, + itemMetadata: { + id: this.id, + barcode: this.barcode, + callNumber: this.callNumber, + bibId: this.bibId, + }, + }) } // Item availability is determined by the existence of status id in the availability ids list diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index 31c8399d6..52d10b6fe 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -1,5 +1,8 @@ import type Item from "./Item" -import AvailableByAppointment from "../components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment" +import { + AvailableAt, + AvailableByAppointment, +} from "../components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment" import AvailableOnsite from "../components/ItemTable/ItemAvailabilityComponents/AvailableOnsite" import NotAvailable from "../components/ItemTable/ItemAvailabilityComponents/NotAvailable" import { availabilityKeys } from "../config/constants" @@ -7,36 +10,63 @@ import { availabilityKeys } from "../config/constants" class ItemAvailability { item: Item key: string + location: { endpoint: string } + dueDate: string + isAvailable: boolean + isReCAP: boolean + aeonUrl: string findingAid: string - constructor(item: Item, findingAid: string) { - this.item = item - this.key = this.buildKey() + needsButton: boolean + itemMetadata: { + id: string + barcode: string + callNumber: string + bibId: string + } + constructor({ + location, + dueDate, + isAvailable, + isReCAP, + aeonUrl, + findingAid, + itemMetadata, + }) { this.findingAid = findingAid + this.needsButton = false + this.dueDate = dueDate + this.isReCAP = isReCAP + this.isAvailable = isAvailable + this.aeonUrl = aeonUrl + this.location = location + this.dueDate = dueDate + this.itemMetadata = itemMetadata + this.key = this.buildKey() } buildKey() { - if (this.item.isAvailable && this.item.isReCAP && !this.item.aeonUrl) { + if (this.isAvailable && this.isReCAP && !this.aeonUrl) { return availabilityKeys.RECAP } if ( - this.item.isAvailable && - this.item.aeonUrl && - this.item.location?.endpoint && - this.item.isReCAP + this.isAvailable && + this.aeonUrl && + this.location?.endpoint && + this.isReCAP ) { return availabilityKeys.RECAP_AEON } if ( - this.item.isAvailable && - this.item.aeonUrl && - this.item.location?.endpoint && - !this.item.isReCAP + this.isAvailable && + this.aeonUrl && + this.location?.endpoint && + !this.isReCAP ) { return availabilityKeys.ONSITE_AEON } - if (this.item.isAvailable && !this.item.isReCAP) { + if (this.isAvailable && !this.isReCAP) { return availabilityKeys.ONSITE } - if (!this.item.isAvailable) { + if (!this.isAvailable) { return availabilityKeys.NOT_AVAILABLE } } @@ -45,13 +75,23 @@ class ItemAvailability { case availabilityKeys.RECAP: throw "This key doesn't have a message. This component should be returning earlier than this." case availabilityKeys.RECAP_AEON: - return + return case availabilityKeys.ONSITE_AEON: - return + return ( + <> + + + + ) case availabilityKeys.ONSITE: - return + return case availabilityKeys.NOT_AVAILABLE: - return + return ( + + ) } } } From d4d0cf636b8a10cbac576cc6eaeb8f9c5beecf17 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 14:47:58 -0500 Subject: [PATCH 11/44] clean up; --- src/models/ItemAvailability.tsx | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index 52d10b6fe..02fa5b419 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -17,6 +17,7 @@ class ItemAvailability { aeonUrl: string findingAid: string needsButton: boolean + specialCollections?: boolean itemMetadata: { id: string barcode: string @@ -31,9 +32,9 @@ class ItemAvailability { aeonUrl, findingAid, itemMetadata, + specialCollections, }) { this.findingAid = findingAid - this.needsButton = false this.dueDate = dueDate this.isReCAP = isReCAP this.isAvailable = isAvailable @@ -42,33 +43,26 @@ class ItemAvailability { this.dueDate = dueDate this.itemMetadata = itemMetadata this.key = this.buildKey() + this.specialCollections = + specialCollections || this.findingAid || this.aeonUrl } buildKey() { - if (this.isAvailable && this.isReCAP && !this.aeonUrl) { + // All unavailable records have the same messaging. + if (!this.isAvailable) { + return availabilityKeys.NOT_AVAILABLE + } + if (this.isReCAP && !this.aeonUrl) { return availabilityKeys.RECAP } - if ( - this.isAvailable && - this.aeonUrl && - this.location?.endpoint && - this.isReCAP - ) { + if (this.aeonUrl && this.isReCAP) { return availabilityKeys.RECAP_AEON } - if ( - this.isAvailable && - this.aeonUrl && - this.location?.endpoint && - !this.isReCAP - ) { + if (this.aeonUrl && this.location?.endpoint && !this.isReCAP) { return availabilityKeys.ONSITE_AEON } - if (this.isAvailable && !this.isReCAP) { + if (!this.isReCAP) { return availabilityKeys.ONSITE } - if (!this.isAvailable) { - return availabilityKeys.NOT_AVAILABLE - } } message() { switch (this.key) { From ca84fb84307278d5149c2d07417bc089ac9579ec Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 14:50:30 -0500 Subject: [PATCH 12/44] move message render to component --- src/components/ItemTable/ItemAvailability.tsx | 36 ++++++++++++++++++- src/models/ItemAvailability.tsx | 30 ---------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 94298f6cd..098741897 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -4,6 +4,12 @@ import ExternalLink from "../Links/ExternalLink/ExternalLink" import { appConfig } from "../../config/config" import type Item from "../../models/Item" import { availabilityKeys } from "../../config/constants" +import { + AvailableByAppointment, + AvailableAt, +} from "./ItemAvailabilityComponents/AvailableByAppointment" +import AvailableOnsite from "./ItemAvailabilityComponents/AvailableOnsite" +import NotAvailable from "./ItemAvailabilityComponents/NotAvailable" interface ItemAvailabilityProps { item: Item @@ -23,6 +29,34 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) } + let message + switch (item.availability.key) { + case availabilityKeys.RECAP: + throw "This key doesn't have a message. This component should be returning earlier than this." + case availabilityKeys.RECAP_AEON: + message = + break + case availabilityKeys.ONSITE_AEON: + message = ( + <> + + + + ) + break + case availabilityKeys.ONSITE: + message = + break + case availabilityKeys.NOT_AVAILABLE: + message = ( + + ) + break + } + return ( { md: "desktop.body.body2", }} > - {item.availability.message()} + {message} ) } diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index 02fa5b419..f50de2706 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -1,10 +1,4 @@ import type Item from "./Item" -import { - AvailableAt, - AvailableByAppointment, -} from "../components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment" -import AvailableOnsite from "../components/ItemTable/ItemAvailabilityComponents/AvailableOnsite" -import NotAvailable from "../components/ItemTable/ItemAvailabilityComponents/NotAvailable" import { availabilityKeys } from "../config/constants" class ItemAvailability { @@ -64,30 +58,6 @@ class ItemAvailability { return availabilityKeys.ONSITE } } - message() { - switch (this.key) { - case availabilityKeys.RECAP: - throw "This key doesn't have a message. This component should be returning earlier than this." - case availabilityKeys.RECAP_AEON: - return - case availabilityKeys.ONSITE_AEON: - return ( - <> - - - - ) - case availabilityKeys.ONSITE: - return - case availabilityKeys.NOT_AVAILABLE: - return ( - - ) - } - } } export default ItemAvailability From 39f8c1025796be2819979465acd933a80cc3c1de Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 15:03:20 -0500 Subject: [PATCH 13/44] start availability model tests --- .../ItemTable/ItemAvailability.test.tsx | 1 - src/components/ItemTable/ItemAvailability.tsx | 6 ++-- .../AvailableByAppointment.tsx | 14 +++++---- .../AvailableOnsite.tsx | 0 .../ContactALibrarian.tsx | 0 .../NotAvailable.tsx | 0 src/models/ItemAvailability.tsx | 5 ++- .../modelTests/ItemAvailability.test.ts | 31 +++++++++++++++++++ 8 files changed, 44 insertions(+), 13 deletions(-) rename src/components/ItemTable/{ItemAvailabilityComponents => ItemAvailability}/AvailableByAppointment.tsx (68%) rename src/components/ItemTable/{ItemAvailabilityComponents => ItemAvailability}/AvailableOnsite.tsx (100%) rename src/components/ItemTable/{ItemAvailabilityComponents => ItemAvailability}/ContactALibrarian.tsx (100%) rename src/components/ItemTable/{ItemAvailabilityComponents => ItemAvailability}/NotAvailable.tsx (100%) create mode 100644 src/models/modelTests/ItemAvailability.test.ts diff --git a/src/components/ItemTable/ItemAvailability.test.tsx b/src/components/ItemTable/ItemAvailability.test.tsx index ba84f6016..8fde4c30d 100644 --- a/src/components/ItemTable/ItemAvailability.test.tsx +++ b/src/components/ItemTable/ItemAvailability.test.tsx @@ -31,7 +31,6 @@ describe("ItemAvailability", () => { const item = new Item(itemPhysicallyRequestable, parentBib) render() - console.log("item after construction", item) expect(screen.getByText("Available by appointment")).toBeInTheDocument() expect( screen.getByText("Schwarzman Building - Main Reading Room 315") diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 098741897..90b1222a9 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -7,9 +7,9 @@ import { availabilityKeys } from "../../config/constants" import { AvailableByAppointment, AvailableAt, -} from "./ItemAvailabilityComponents/AvailableByAppointment" -import AvailableOnsite from "./ItemAvailabilityComponents/AvailableOnsite" -import NotAvailable from "./ItemAvailabilityComponents/NotAvailable" +} from "./ItemAvailability/AvailableByAppointment" +import AvailableOnsite from "./ItemAvailability/AvailableOnsite" +import NotAvailable from "./ItemAvailability/NotAvailable" interface ItemAvailabilityProps { item: Item diff --git a/src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx similarity index 68% rename from src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx rename to src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx index fdd560fdf..15046b57d 100644 --- a/src/components/ItemTable/ItemAvailabilityComponents/AvailableByAppointment.tsx +++ b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx @@ -14,12 +14,14 @@ const AvailableByAppointment = () => { const AvailableAt = ({ location }) => { return ( - <> - {" at "} - - {location.prefLabel} - - + location?.endpoint && ( + <> + {" at "} + + {location.prefLabel} + + + ) ) } diff --git a/src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx b/src/components/ItemTable/ItemAvailability/AvailableOnsite.tsx similarity index 100% rename from src/components/ItemTable/ItemAvailabilityComponents/AvailableOnsite.tsx rename to src/components/ItemTable/ItemAvailability/AvailableOnsite.tsx diff --git a/src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx b/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx similarity index 100% rename from src/components/ItemTable/ItemAvailabilityComponents/ContactALibrarian.tsx rename to src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx diff --git a/src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx b/src/components/ItemTable/ItemAvailability/NotAvailable.tsx similarity index 100% rename from src/components/ItemTable/ItemAvailabilityComponents/NotAvailable.tsx rename to src/components/ItemTable/ItemAvailability/NotAvailable.tsx diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index f50de2706..cd3f882d7 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -2,7 +2,6 @@ import type Item from "./Item" import { availabilityKeys } from "../config/constants" class ItemAvailability { - item: Item key: string location: { endpoint: string } dueDate: string @@ -45,13 +44,13 @@ class ItemAvailability { if (!this.isAvailable) { return availabilityKeys.NOT_AVAILABLE } - if (this.isReCAP && !this.aeonUrl) { + if (this.isReCAP && !this.specialCollections) { return availabilityKeys.RECAP } if (this.aeonUrl && this.isReCAP) { return availabilityKeys.RECAP_AEON } - if (this.aeonUrl && this.location?.endpoint && !this.isReCAP) { + if (this.aeonUrl && !this.isReCAP) { return availabilityKeys.ONSITE_AEON } if (!this.isReCAP) { diff --git a/src/models/modelTests/ItemAvailability.test.ts b/src/models/modelTests/ItemAvailability.test.ts new file mode 100644 index 000000000..b2ef0358e --- /dev/null +++ b/src/models/modelTests/ItemAvailability.test.ts @@ -0,0 +1,31 @@ +import { availabilityKeys } from "../../config/constants" +import ItemAvailability from "../ItemAvailability" + +describe("ItemAvailabilityFactory", () => { + it("not available", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: false, + isReCAP: false, + aeonUrl: null, + findingAid: null, + itemMetadata: null, + specialCollections: false, + }) + expect(availability.key).toBe(availabilityKeys.NOT_AVAILABLE) + }) + it("recap not special collections", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: true, + aeonUrl: null, + findingAid: null, + itemMetadata: null, + specialCollections: false, + }) + expect(availability.key).toBe(availabilityKeys.RECAP) + }) +}) From bc233b01285d06fffcdba4c00c152dd37e49e429 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Tue, 17 Dec 2024 15:21:00 -0500 Subject: [PATCH 14/44] more tests for item availability --- __test__/fixtures/itemFixtures.ts | 1 + src/config/constants.ts | 6 +++-- src/models/ItemAvailability.tsx | 20 +++++++++----- .../modelTests/ItemAvailability.test.ts | 26 +++++++++++++++++++ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/__test__/fixtures/itemFixtures.ts b/__test__/fixtures/itemFixtures.ts index 44174b90f..6a5dc86a6 100644 --- a/__test__/fixtures/itemFixtures.ts +++ b/__test__/fixtures/itemFixtures.ts @@ -7,6 +7,7 @@ export const itemPhysicallyRequestable = { prefLabel: "Use in library", }, ], + specialCollections: true, aeonUrl: [ "https://specialcollections.nypl.org/aeon/Aeon.dll?Action=10&Form=30&Title=Spaghetti+westerns.&Site=LPAMRAMI&CallNumber=*LDC+14245&ItemPlace=[New+York?]+:&ItemPublisher=DRG+Records+Inc.,&Date=p1995.&ItemInfo3=https://catalog.nypl.org/record=b19028235&ReferenceNumber=b190282356&ItemInfo1=USE+IN+LIBRARY&ItemNumber=33433085319782&ItemISxN=i265238791&Genre=Music+CD&Location=Performing+Arts+Music+Division", ], diff --git a/src/config/constants.ts b/src/config/constants.ts index 41bd8b059..f0e966363 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -138,9 +138,11 @@ export const NYPL_LOCATIONS = { export const availabilityKeys = { // there is only one not available case, so availability is assumed as the default RECAP: "Recap", + ONSITE: "Onsite", + NOT_AVAILABLE: "notAvailable", RECAP_AEON: "RecapAeon", AEON: "Aeon", ONSITE_AEON: "OnsiteAeon", - ONSITE: "Onsite", - NOT_AVAILABLE: "notAvailable", + ONSITE_AEON_FINDING_AID: "onsiteAeonFindingAid", + RECAP_AEON_FINDING_AID: "recapAeonFindingAid", } diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index cd3f882d7..dca6b30c4 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -35,26 +35,32 @@ class ItemAvailability { this.location = location this.dueDate = dueDate this.itemMetadata = itemMetadata + this.specialCollections = specialCollections + this.key = this.buildKey() - this.specialCollections = - specialCollections || this.findingAid || this.aeonUrl + console.log(this) } buildKey() { // All unavailable records have the same messaging. + // general collections messages if (!this.isAvailable) { return availabilityKeys.NOT_AVAILABLE } if (this.isReCAP && !this.specialCollections) { return availabilityKeys.RECAP } - if (this.aeonUrl && this.isReCAP) { + if (!this.isReCAP && !this.specialCollections) { + return availabilityKeys.ONSITE + } + // special collections messaging + if (this.aeonUrl && this.isReCAP && !this.findingAid) { return availabilityKeys.RECAP_AEON } - if (this.aeonUrl && !this.isReCAP) { - return availabilityKeys.ONSITE_AEON + if (this.aeonUrl && this.isReCAP && this.findingAid) { + return availabilityKeys.RECAP_AEON_FINDING_AID } - if (!this.isReCAP) { - return availabilityKeys.ONSITE + if (this.aeonUrl && !this.isReCAP && !this.findingAid) { + return availabilityKeys.ONSITE_AEON } } } diff --git a/src/models/modelTests/ItemAvailability.test.ts b/src/models/modelTests/ItemAvailability.test.ts index b2ef0358e..a6d5a7d6e 100644 --- a/src/models/modelTests/ItemAvailability.test.ts +++ b/src/models/modelTests/ItemAvailability.test.ts @@ -28,4 +28,30 @@ describe("ItemAvailabilityFactory", () => { }) expect(availability.key).toBe(availabilityKeys.RECAP) }) + it("recap aeon", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: true, + aeonUrl: "spaghetti.com", + findingAid: null, + itemMetadata: null, + specialCollections: true, + }) + expect(availability.key).toBe(availabilityKeys.RECAP_AEON) + }) + it("recap aeon finding aid", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: true, + aeonUrl: "spaghetti.com", + findingAid: "meatballs.com", + itemMetadata: null, + specialCollections: true, + }) + expect(availability.key).toBe(availabilityKeys.RECAP_AEON_FINDING_AID) + }) }) From b71027e42a9fe5604b6e415a1776ba2de287a3d2 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Wed, 18 Dec 2024 09:51:07 -0500 Subject: [PATCH 15/44] create all cases in model --- .../ItemTable/ItemAvailability.test.tsx | 2 +- src/components/ItemTable/ItemAvailability.tsx | 6 +- .../AvailableByAppointment.tsx | 15 ++-- src/config/constants.ts | 9 +- src/models/ItemAvailability.tsx | 24 +++++- .../modelTests/ItemAvailability.test.ts | 82 ++++++++++++++++++- 6 files changed, 119 insertions(+), 19 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.test.tsx b/src/components/ItemTable/ItemAvailability.test.tsx index 8fde4c30d..f3f04b4f0 100644 --- a/src/components/ItemTable/ItemAvailability.test.tsx +++ b/src/components/ItemTable/ItemAvailability.test.tsx @@ -27,7 +27,7 @@ describe("ItemAvailability", () => { "https://www.nypl.org/help/request-research-materials" ) }) - it("renders the correct text when item is available, has an aeon url, and has a location endpoint", async () => { + xit("renders the correct text when item is available, has an aeon url, and has a location endpoint", async () => { const item = new Item(itemPhysicallyRequestable, parentBib) render() diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 90b1222a9..943334055 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -21,7 +21,7 @@ interface ItemAvailabilityProps { * TODO: Add Feedback box, Due date, Available font styles */ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { - if (item.availability.key === availabilityKeys.RECAP) { + if (item.availability.key === availabilityKeys.RECAP_GENERAL_COLLECTIONS) { return ( How do I pick up this item and when will it be ready? @@ -31,7 +31,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { let message switch (item.availability.key) { - case availabilityKeys.RECAP: + case availabilityKeys.RECAP_GENERAL_COLLECTIONS: throw "This key doesn't have a message. This component should be returning earlier than this." case availabilityKeys.RECAP_AEON: message = @@ -44,7 +44,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) break - case availabilityKeys.ONSITE: + case availabilityKeys.ONSITE_GENERAL_COLLECTIONS: message = break case availabilityKeys.NOT_AVAILABLE: diff --git a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx index 15046b57d..e9b658c7a 100644 --- a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx +++ b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx @@ -13,15 +13,14 @@ const AvailableByAppointment = () => { } const AvailableAt = ({ location }) => { + if (!location?.endpoint) return null return ( - location?.endpoint && ( - <> - {" at "} - - {location.prefLabel} - - - ) + <> + {" at "} + + {location.prefLabel} + + ) } diff --git a/src/config/constants.ts b/src/config/constants.ts index f0e966363..f0a9de9c3 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -137,12 +137,17 @@ export const NYPL_LOCATIONS = { export const availabilityKeys = { // there is only one not available case, so availability is assumed as the default - RECAP: "Recap", - ONSITE: "Onsite", + RECAP_GENERAL_COLLECTIONS: "Recap", + ONSITE_GENERAL_COLLECTIONS: "Onsite", NOT_AVAILABLE: "notAvailable", + // special collections availability keys RECAP_AEON: "RecapAeon", AEON: "Aeon", ONSITE_AEON: "OnsiteAeon", ONSITE_AEON_FINDING_AID: "onsiteAeonFindingAid", RECAP_AEON_FINDING_AID: "recapAeonFindingAid", + ONSITE_FINDING_AID: "onsiteFindingAid", + RECAP_FINDING_AID: "recapFindingAid", + ONSITE_NO_FINDING_AID_NO_AEON: "noFindingAidNoAeonOnsite", + RECAP_NO_FINDING_AID_NO_AEON: "noFindingAidNoAeonRecap", } diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index dca6b30c4..37ba65b56 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -11,6 +11,7 @@ class ItemAvailability { findingAid: string needsButton: boolean specialCollections?: boolean + isOnsite: boolean itemMetadata: { id: string barcode: string @@ -36,9 +37,9 @@ class ItemAvailability { this.dueDate = dueDate this.itemMetadata = itemMetadata this.specialCollections = specialCollections + this.isOnsite = !this.isReCAP this.key = this.buildKey() - console.log(this) } buildKey() { // All unavailable records have the same messaging. @@ -47,10 +48,10 @@ class ItemAvailability { return availabilityKeys.NOT_AVAILABLE } if (this.isReCAP && !this.specialCollections) { - return availabilityKeys.RECAP + return availabilityKeys.RECAP_GENERAL_COLLECTIONS } if (!this.isReCAP && !this.specialCollections) { - return availabilityKeys.ONSITE + return availabilityKeys.ONSITE_GENERAL_COLLECTIONS } // special collections messaging if (this.aeonUrl && this.isReCAP && !this.findingAid) { @@ -59,9 +60,24 @@ class ItemAvailability { if (this.aeonUrl && this.isReCAP && this.findingAid) { return availabilityKeys.RECAP_AEON_FINDING_AID } - if (this.aeonUrl && !this.isReCAP && !this.findingAid) { + if (this.aeonUrl && this.isOnsite && !this.findingAid) { return availabilityKeys.ONSITE_AEON } + if (this.isOnsite && this.aeonUrl && this.findingAid) { + return availabilityKeys.ONSITE_AEON_FINDING_AID + } + if (this.isOnsite && this.findingAid && !this.aeonUrl) { + return availabilityKeys.ONSITE_FINDING_AID + } + if (this.isReCAP && this.findingAid && !this.aeonUrl) { + return availabilityKeys.RECAP_FINDING_AID + } + if (this.isOnsite && !this.findingAid && !this.aeonUrl) { + return availabilityKeys.ONSITE_NO_FINDING_AID_NO_AEON + } + if (this.isReCAP && !this.findingAid && !this.aeonUrl) { + return availabilityKeys.RECAP_NO_FINDING_AID_NO_AEON + } } } diff --git a/src/models/modelTests/ItemAvailability.test.ts b/src/models/modelTests/ItemAvailability.test.ts index a6d5a7d6e..6f2adda52 100644 --- a/src/models/modelTests/ItemAvailability.test.ts +++ b/src/models/modelTests/ItemAvailability.test.ts @@ -26,7 +26,7 @@ describe("ItemAvailabilityFactory", () => { itemMetadata: null, specialCollections: false, }) - expect(availability.key).toBe(availabilityKeys.RECAP) + expect(availability.key).toBe(availabilityKeys.RECAP_GENERAL_COLLECTIONS) }) it("recap aeon", () => { const availability = new ItemAvailability({ @@ -54,4 +54,84 @@ describe("ItemAvailabilityFactory", () => { }) expect(availability.key).toBe(availabilityKeys.RECAP_AEON_FINDING_AID) }) + it("onsite aeon", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: false, + aeonUrl: "spaghetti.com", + findingAid: false, + itemMetadata: null, + specialCollections: true, + }) + expect(availability.key).toBe(availabilityKeys.ONSITE_AEON) + }) + it("onsite aeon finding aid", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: false, + aeonUrl: "spaghetti.com", + findingAid: "meatballs.com", + itemMetadata: null, + specialCollections: true, + }) + expect(availability.key).toBe(availabilityKeys.ONSITE_AEON_FINDING_AID) + }) + it("onsite finding aid - no aeon", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: false, + aeonUrl: false, + findingAid: "meatballs.com", + itemMetadata: null, + specialCollections: true, + }) + expect(availability.key).toBe(availabilityKeys.ONSITE_FINDING_AID) + }) + it("recap finding aid - no aeon", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: true, + aeonUrl: false, + findingAid: "meatballs.com", + itemMetadata: null, + specialCollections: true, + }) + expect(availability.key).toBe(availabilityKeys.RECAP_FINDING_AID) + }) + it("recap no finding aid no aeon", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: true, + aeonUrl: false, + findingAid: false, + itemMetadata: null, + specialCollections: true, + }) + expect(availability.key).toBe(availabilityKeys.RECAP_NO_FINDING_AID_NO_AEON) + }) + it("recap no finding aid no aeon", () => { + const availability = new ItemAvailability({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: false, + aeonUrl: false, + findingAid: false, + itemMetadata: null, + specialCollections: true, + }) + expect(availability.key).toBe( + availabilityKeys.ONSITE_NO_FINDING_AID_NO_AEON + ) + }) }) From 790e7bbd0a8e9025125ec94e43c87abc62facfbc Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Wed, 18 Dec 2024 09:59:07 -0500 Subject: [PATCH 16/44] start speccoll tests --- .../ItemTable/ItemAvailability.test.tsx | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.test.tsx b/src/components/ItemTable/ItemAvailability.test.tsx index f3f04b4f0..dd1cbb034 100644 --- a/src/components/ItemTable/ItemAvailability.test.tsx +++ b/src/components/ItemTable/ItemAvailability.test.tsx @@ -2,6 +2,8 @@ import React from "react" import { render, screen } from "../../utils/testUtils" import userEvent from "@testing-library/user-event" +import ItemAvailabilityModel from "../../models/ItemAvailability" + import ItemAvailability from "./ItemAvailability" import Item from "../../models/Item" import SearchResultsBib from "../../models/SearchResultsBib" @@ -17,6 +19,23 @@ import { searchResultPhysicalItems } from "../../../__test__/fixtures/searchResu const parentBib = new SearchResultsBib(searchResultPhysicalItems) describe("ItemAvailability", () => { + describe("special collections", () => { + it("recap aeon", () => { + // this item's metadata is not being used at all. it is here to satisfy + const item = new Item(itemPhysicallyRequestable, parentBib) + item.availability = new ItemAvailabilityModel({ + location: { endpoint: "abc", prefLabel: "spaghetti" }, + dueDate: "tomorrow", + isAvailable: true, + isReCAP: true, + aeonUrl: "spaghetti.com", + findingAid: null, + itemMetadata: null, + specialCollections: true, + }) + render() + }) + }) it("renders the correct link when item is available, is reCAP, and does not have an aeon url", async () => { const item = new Item(itemNYPLReCAP, parentBib) render() @@ -27,15 +46,6 @@ describe("ItemAvailability", () => { "https://www.nypl.org/help/request-research-materials" ) }) - xit("renders the correct text when item is available, has an aeon url, and has a location endpoint", async () => { - const item = new Item(itemPhysicallyRequestable, parentBib) - - render() - expect(screen.getByText("Available by appointment")).toBeInTheDocument() - expect( - screen.getByText("Schwarzman Building - Main Reading Room 315") - ).toHaveAttribute("href", "https://www.nypl.org/locations/schwarzman") - }) it("renders the correct text for an available onsite item", async () => { const item = new Item(itemAvailableOnsite, parentBib) render() From 13a0c72ed548aa971e6951cc344f5a1d1cdfba65 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Wed, 18 Dec 2024 10:02:36 -0500 Subject: [PATCH 17/44] rm non avail details from itemavailability --- src/components/ItemTable/ItemAvailability.tsx | 11 +++------- .../ItemAvailability/NotAvailable.tsx | 20 ++++++++----------- src/models/ItemAvailability.tsx | 18 +---------------- 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 943334055..72fb2846b 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -40,20 +40,15 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { message = ( <> - + ) break case availabilityKeys.ONSITE_GENERAL_COLLECTIONS: - message = + message = break case availabilityKeys.NOT_AVAILABLE: - message = ( - - ) + message = break } diff --git a/src/components/ItemTable/ItemAvailability/NotAvailable.tsx b/src/components/ItemTable/ItemAvailability/NotAvailable.tsx index 47128548e..0c2057cdd 100644 --- a/src/components/ItemTable/ItemAvailability/NotAvailable.tsx +++ b/src/components/ItemTable/ItemAvailability/NotAvailable.tsx @@ -1,24 +1,20 @@ import { Box } from "@nypl/design-system-react-components" import ContactALibrarian from "./ContactALibrarian" +import type Item from "../../../models/Item" -const NotAvailable = ({ - dueDate, - itemMetadata, -}: { - dueDate: string - itemMetadata: { - id: string - barcode: string - callNumber: string - bibId: string +const NotAvailable = ({ item }: { item: Item }) => { + const itemMetadata = { + id: item.id, + barcode: item.barcode, + callNumber: item.callNumber, + bibId: item.bibId, } -}) => { return ( <> Not available - {dueDate && ` - In use until ${dueDate}`} + {item.dueDate && ` - In use until ${item.dueDate}`} ) diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index 37ba65b56..a7da33981 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -1,41 +1,25 @@ -import type Item from "./Item" import { availabilityKeys } from "../config/constants" class ItemAvailability { key: string - location: { endpoint: string } - dueDate: string isAvailable: boolean isReCAP: boolean aeonUrl: string findingAid: string - needsButton: boolean specialCollections?: boolean isOnsite: boolean - itemMetadata: { - id: string - barcode: string - callNumber: string - bibId: string - } + constructor({ - location, - dueDate, isAvailable, isReCAP, aeonUrl, findingAid, - itemMetadata, specialCollections, }) { this.findingAid = findingAid - this.dueDate = dueDate this.isReCAP = isReCAP this.isAvailable = isAvailable this.aeonUrl = aeonUrl - this.location = location - this.dueDate = dueDate - this.itemMetadata = itemMetadata this.specialCollections = specialCollections this.isOnsite = !this.isReCAP From 2c591bd625ecb21a0058a177d863de5e838af56d Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Wed, 18 Dec 2024 10:34:22 -0500 Subject: [PATCH 18/44] more tests --- .../ItemTable/ItemAvailability.test.tsx | 42 ++++++++++++++++--- src/components/ItemTable/ItemAvailability.tsx | 14 ++++++- .../AvailableByAppointment.tsx | 9 +++- .../modelTests/ItemAvailability.test.ts | 30 ------------- 4 files changed, 57 insertions(+), 38 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.test.tsx b/src/components/ItemTable/ItemAvailability.test.tsx index dd1cbb034..222f4c7e1 100644 --- a/src/components/ItemTable/ItemAvailability.test.tsx +++ b/src/components/ItemTable/ItemAvailability.test.tsx @@ -20,20 +20,52 @@ const parentBib = new SearchResultsBib(searchResultPhysicalItems) describe("ItemAvailability", () => { describe("special collections", () => { + it("onsite aeon finding aid", () => { + const item = new Item(itemPhysicallyRequestable, parentBib) + item.availability = new ItemAvailabilityModel({ + isAvailable: true, + isReCAP: false, + aeonUrl: "spaghetti.com", + findingAid: "meatballs.com", + specialCollections: true, + }) + render() + expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.getByRole("link")).toHaveTextContent( + "Schwarzman Building - Main Reading Room 315" + ) + }) + it("recap aeon finding aid", () => { + const item = new Item(itemPhysicallyRequestable, parentBib) + item.availability = new ItemAvailabilityModel({ + isAvailable: true, + isReCAP: true, + aeonUrl: "spaghetti.com", + findingAid: "meatballs.com", + specialCollections: true, + }) + render() + expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.queryByRole("link")).not.toBeInTheDocument() + expect( + screen.queryByText("Schwarzman Building - Main Reading Room 315") + ).not.toBeInTheDocument() + }) it("recap aeon", () => { - // this item's metadata is not being used at all. it is here to satisfy const item = new Item(itemPhysicallyRequestable, parentBib) item.availability = new ItemAvailabilityModel({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: true, aeonUrl: "spaghetti.com", - findingAid: null, - itemMetadata: null, + findingAid: "meatballs.com", specialCollections: true, }) render() + expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.queryByRole("link")).not.toBeInTheDocument() + expect( + screen.queryByText("Schwarzman Building - Main Reading Room 315") + ).not.toBeInTheDocument() }) }) it("renders the correct link when item is available, is reCAP, and does not have an aeon url", async () => { diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 72fb2846b..09d1be701 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -7,6 +7,7 @@ import { availabilityKeys } from "../../config/constants" import { AvailableByAppointment, AvailableAt, + AvailableAtLink, } from "./ItemAvailability/AvailableByAppointment" import AvailableOnsite from "./ItemAvailability/AvailableOnsite" import NotAvailable from "./ItemAvailability/NotAvailable" @@ -33,7 +34,18 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { switch (item.availability.key) { case availabilityKeys.RECAP_GENERAL_COLLECTIONS: throw "This key doesn't have a message. This component should be returning earlier than this." - case availabilityKeys.RECAP_AEON: + case (availabilityKeys.RECAP_AEON, availabilityKeys.ONSITE_AEON): + message = + break + case availabilityKeys.ONSITE_AEON_FINDING_AID: + message = ( + <> + + + + ) + break + case availabilityKeys.RECAP_AEON_FINDING_AID: message = break case availabilityKeys.ONSITE_AEON: diff --git a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx index e9b658c7a..733450247 100644 --- a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx +++ b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx @@ -12,7 +12,7 @@ const AvailableByAppointment = () => { ) } -const AvailableAt = ({ location }) => { +const AvailableAtLink = ({ location }) => { if (!location?.endpoint) return null return ( <> @@ -24,4 +24,9 @@ const AvailableAt = ({ location }) => { ) } -export { AvailableByAppointment, AvailableAt } +const AvailableAt = ({ location }) => { + if (!location?.endpoint) return null + else return ` at ${location.prefLabel}` +} + +export { AvailableByAppointment, AvailableAtLink, AvailableAt } diff --git a/src/models/modelTests/ItemAvailability.test.ts b/src/models/modelTests/ItemAvailability.test.ts index 6f2adda52..1e8b3f0d0 100644 --- a/src/models/modelTests/ItemAvailability.test.ts +++ b/src/models/modelTests/ItemAvailability.test.ts @@ -4,130 +4,100 @@ import ItemAvailability from "../ItemAvailability" describe("ItemAvailabilityFactory", () => { it("not available", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: false, isReCAP: false, aeonUrl: null, findingAid: null, - itemMetadata: null, specialCollections: false, }) expect(availability.key).toBe(availabilityKeys.NOT_AVAILABLE) }) it("recap not special collections", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: true, aeonUrl: null, findingAid: null, - itemMetadata: null, specialCollections: false, }) expect(availability.key).toBe(availabilityKeys.RECAP_GENERAL_COLLECTIONS) }) it("recap aeon", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: true, aeonUrl: "spaghetti.com", findingAid: null, - itemMetadata: null, specialCollections: true, }) expect(availability.key).toBe(availabilityKeys.RECAP_AEON) }) it("recap aeon finding aid", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: true, aeonUrl: "spaghetti.com", findingAid: "meatballs.com", - itemMetadata: null, specialCollections: true, }) expect(availability.key).toBe(availabilityKeys.RECAP_AEON_FINDING_AID) }) it("onsite aeon", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: false, aeonUrl: "spaghetti.com", findingAid: false, - itemMetadata: null, specialCollections: true, }) expect(availability.key).toBe(availabilityKeys.ONSITE_AEON) }) it("onsite aeon finding aid", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: false, aeonUrl: "spaghetti.com", findingAid: "meatballs.com", - itemMetadata: null, specialCollections: true, }) expect(availability.key).toBe(availabilityKeys.ONSITE_AEON_FINDING_AID) }) it("onsite finding aid - no aeon", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: false, aeonUrl: false, findingAid: "meatballs.com", - itemMetadata: null, specialCollections: true, }) expect(availability.key).toBe(availabilityKeys.ONSITE_FINDING_AID) }) it("recap finding aid - no aeon", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: true, aeonUrl: false, findingAid: "meatballs.com", - itemMetadata: null, specialCollections: true, }) expect(availability.key).toBe(availabilityKeys.RECAP_FINDING_AID) }) it("recap no finding aid no aeon", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: true, aeonUrl: false, findingAid: false, - itemMetadata: null, specialCollections: true, }) expect(availability.key).toBe(availabilityKeys.RECAP_NO_FINDING_AID_NO_AEON) }) it("recap no finding aid no aeon", () => { const availability = new ItemAvailability({ - location: { endpoint: "abc", prefLabel: "spaghetti" }, - dueDate: "tomorrow", isAvailable: true, isReCAP: false, aeonUrl: false, findingAid: false, - itemMetadata: null, specialCollections: true, }) expect(availability.key).toBe( From 3ac3d6fadfca617d1a42cfe2073b2cf7a38bddf5 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Wed, 18 Dec 2024 10:56:52 -0500 Subject: [PATCH 19/44] build out rendering cases and tests --- .../ItemTable/ItemAvailability.test.tsx | 94 +++++++++++++++++++ src/components/ItemTable/ItemAvailability.tsx | 43 ++++++++- .../ItemAvailability/ContactALibrarian.tsx | 12 +-- .../ItemTable/ItemAvailability/FindingAid.tsx | 13 +++ 4 files changed, 148 insertions(+), 14 deletions(-) create mode 100644 src/components/ItemTable/ItemAvailability/FindingAid.tsx diff --git a/src/components/ItemTable/ItemAvailability.test.tsx b/src/components/ItemTable/ItemAvailability.test.tsx index 222f4c7e1..f68019c40 100644 --- a/src/components/ItemTable/ItemAvailability.test.tsx +++ b/src/components/ItemTable/ItemAvailability.test.tsx @@ -15,6 +15,7 @@ import { itemUnavailable, } from "../../../__test__/fixtures/itemFixtures" import { searchResultPhysicalItems } from "../../../__test__/fixtures/searchResultPhysicalItems" +import { notDeepEqual } from "assert" const parentBib = new SearchResultsBib(searchResultPhysicalItems) @@ -67,6 +68,99 @@ describe("ItemAvailability", () => { screen.queryByText("Schwarzman Building - Main Reading Room 315") ).not.toBeInTheDocument() }) + it("onsite aeon NO finding aid", () => { + const item = new Item(itemPhysicallyRequestable, parentBib) + item.availability = new ItemAvailabilityModel({ + isAvailable: true, + isReCAP: false, + aeonUrl: "spaghetti.com", + findingAid: null, + specialCollections: true, + }) + render() + expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.queryByRole("link")).not.toBeInTheDocument() + expect( + screen.getByText("at Schwarzman Building - Main Reading Room 315") + ).toBeInTheDocument() + }) + it("onsite NO aeon YES finding aid", () => { + const item = new Item(itemPhysicallyRequestable, parentBib) + item.availability = new ItemAvailabilityModel({ + isAvailable: true, + isReCAP: false, + aeonUrl: null, + findingAid: "meatballs.com", + specialCollections: true, + }) + render() + expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.queryByRole("link")).toHaveTextContent("Finding aid") + expect( + screen.getByText( + "at Schwarzman Building - Main Reading Room 315. See the ", + { exact: false } + ) + ).toBeInTheDocument() + }) + it("recap NO aeon YES finding aid", () => { + const item = new Item(itemPhysicallyRequestable, parentBib) + item.availability = new ItemAvailabilityModel({ + isAvailable: true, + isReCAP: true, + aeonUrl: null, + findingAid: "meatballs.com", + specialCollections: true, + }) + render() + expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.queryByRole("link")).toHaveTextContent("Finding aid") + expect( + screen.queryByText("Schwarzman Building - Main Reading Room 315", { + exact: false, + }) + ).not.toBeInTheDocument() + }) + it("recap NO aeon NO finding aid", () => { + const item = new Item(itemPhysicallyRequestable, parentBib) + item.availability = new ItemAvailabilityModel({ + isAvailable: true, + isReCAP: true, + aeonUrl: null, + findingAid: null, + specialCollections: true, + }) + render() + expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.queryByRole("link")).not.toBeInTheDocument() + expect( + screen.queryByText("Schwarzman Building - Main Reading Room 315", { + exact: false, + }) + ).not.toBeInTheDocument() + expect(screen.getByText("contact a librarian")).toBeInTheDocument() + }) + it("recap NO aeon NO finding aid", () => { + const item = new Item(itemPhysicallyRequestable, parentBib) + item.availability = new ItemAvailabilityModel({ + isAvailable: true, + isReCAP: false, + aeonUrl: null, + findingAid: null, + specialCollections: true, + }) + render() + expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.getByRole("link")).toHaveTextContent( + "Schwarzman Building - Main Reading Room 315" + ) + expect( + screen.queryByText("Schwarzman Building - Main Reading Room 315", { + exact: false, + }) + ).toBeInTheDocument() + expect(screen.getByText("contact a librarian")).toBeInTheDocument() + }) }) it("renders the correct link when item is available, is reCAP, and does not have an aeon url", async () => { const item = new Item(itemNYPLReCAP, parentBib) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 09d1be701..6d68edd0f 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -11,6 +11,8 @@ import { } from "./ItemAvailability/AvailableByAppointment" import AvailableOnsite from "./ItemAvailability/AvailableOnsite" import NotAvailable from "./ItemAvailability/NotAvailable" +import FindingAid from "./ItemAvailability/FindingAid" +import ContactALibrarian from "./ItemAvailability/ContactALibrarian" interface ItemAvailabilityProps { item: Item @@ -34,7 +36,9 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { switch (item.availability.key) { case availabilityKeys.RECAP_GENERAL_COLLECTIONS: throw "This key doesn't have a message. This component should be returning earlier than this." - case (availabilityKeys.RECAP_AEON, availabilityKeys.ONSITE_AEON): + case (availabilityKeys.RECAP_AEON, + availabilityKeys.ONSITE_AEON, + availabilityKeys.RECAP_AEON_FINDING_AID): message = break case availabilityKeys.ONSITE_AEON_FINDING_AID: @@ -45,9 +49,6 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) break - case availabilityKeys.RECAP_AEON_FINDING_AID: - message = - break case availabilityKeys.ONSITE_AEON: message = ( <> @@ -56,6 +57,40 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) break + case availabilityKeys.ONSITE_FINDING_AID: + message = ( + <> + + + + + ) + break + case availabilityKeys.RECAP_FINDING_AID: + message = ( + <> + + + + ) + break + case availabilityKeys.RECAP_NO_FINDING_AID_NO_AEON: + message = ( + <> + + + + ) + break + case availabilityKeys.ONSITE_NO_FINDING_AID_NO_AEON: + message = ( + <> + + + + + ) + break case availabilityKeys.ONSITE_GENERAL_COLLECTIONS: message = break diff --git a/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx b/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx index 93fb67cd8..f9b87a3ed 100644 --- a/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx +++ b/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx @@ -2,17 +2,9 @@ import { Button } from "@nypl/design-system-react-components" import { useContext } from "react" import { FeedbackContext } from "../../../context/FeedbackContext" import type { ItemMetadata } from "../../../types/itemTypes" +import type Item from "../../../models/Item" -const ContactALibrarian = ({ - item, -}: { - item: { - id: string - barcode: string - callNumber: string - bibId: string - } -}) => { +const ContactALibrarian = ({ item }: { item: Item }) => { const { onOpen, setItemMetadata } = useContext(FeedbackContext) const onContact = (metadata: ItemMetadata) => { setItemMetadata(metadata) diff --git a/src/components/ItemTable/ItemAvailability/FindingAid.tsx b/src/components/ItemTable/ItemAvailability/FindingAid.tsx new file mode 100644 index 000000000..f98c93b26 --- /dev/null +++ b/src/components/ItemTable/ItemAvailability/FindingAid.tsx @@ -0,0 +1,13 @@ +import ExternalLink from "../../Links/ExternalLink/ExternalLink" + +const FindingAid = ({ url }: { url: string }) => { + return ( + <> + {". See the "} + {"Finding aid"} + {" for details"} + + ) +} + +export default FindingAid From 4b5730b8305ae063dbcba543214baac462ee94c9 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Wed, 18 Dec 2024 11:37:58 -0500 Subject: [PATCH 20/44] add provisional special collections designation --- src/components/ItemTable/ItemAvailability.tsx | 3 +++ src/config/constants.ts | 1 + src/models/ItemAvailability.tsx | 26 ++++++++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 6d68edd0f..b218e547e 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -36,6 +36,9 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { switch (item.availability.key) { case availabilityKeys.RECAP_GENERAL_COLLECTIONS: throw "This key doesn't have a message. This component should be returning earlier than this." + case availabilityKeys.EDGE_CASE: + message = + break case (availabilityKeys.RECAP_AEON, availabilityKeys.ONSITE_AEON, availabilityKeys.RECAP_AEON_FINDING_AID): diff --git a/src/config/constants.ts b/src/config/constants.ts index f0a9de9c3..9ed03ac34 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -136,6 +136,7 @@ export const NYPL_LOCATIONS = { } export const availabilityKeys = { + EDGE_CASE: "edgeCase", // there is only one not available case, so availability is assumed as the default RECAP_GENERAL_COLLECTIONS: "Recap", ONSITE_GENERAL_COLLECTIONS: "Onsite", diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.tsx index a7da33981..4df0fd29a 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.tsx @@ -8,6 +8,7 @@ class ItemAvailability { findingAid: string specialCollections?: boolean isOnsite: boolean + definitelyNotSpecialCollections: boolean constructor({ isAvailable, @@ -20,8 +21,11 @@ class ItemAvailability { this.isReCAP = isReCAP this.isAvailable = isAvailable this.aeonUrl = aeonUrl - this.specialCollections = specialCollections this.isOnsite = !this.isReCAP + this.specialCollections = specialCollections + const practicallySpecialCollections = !!(findingAid || aeonUrl) + this.definitelyNotSpecialCollections = + !this.specialCollections && !practicallySpecialCollections this.key = this.buildKey() } @@ -31,10 +35,10 @@ class ItemAvailability { if (!this.isAvailable) { return availabilityKeys.NOT_AVAILABLE } - if (this.isReCAP && !this.specialCollections) { + if (this.isReCAP && this.definitelyNotSpecialCollections) { return availabilityKeys.RECAP_GENERAL_COLLECTIONS } - if (!this.isReCAP && !this.specialCollections) { + if (this.isOnsite && this.definitelyNotSpecialCollections) { return availabilityKeys.ONSITE_GENERAL_COLLECTIONS } // special collections messaging @@ -56,12 +60,22 @@ class ItemAvailability { if (this.isReCAP && this.findingAid && !this.aeonUrl) { return availabilityKeys.RECAP_FINDING_AID } - if (this.isOnsite && !this.findingAid && !this.aeonUrl) { + if ( + this.isOnsite && + !this.findingAid && + !this.aeonUrl && + this.specialCollections + ) { return availabilityKeys.ONSITE_NO_FINDING_AID_NO_AEON } - if (this.isReCAP && !this.findingAid && !this.aeonUrl) { + if ( + this.isReCAP && + !this.findingAid && + !this.aeonUrl && + this.specialCollections + ) { return availabilityKeys.RECAP_NO_FINDING_AID_NO_AEON - } + } else return availabilityKeys.EDGE_CASE } } From caf87315e2ae394334c0e21cd335b56d799da38f Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Thu, 19 Dec 2024 10:44:59 -0500 Subject: [PATCH 21/44] fix bib/item instantiation bug --- src/components/ItemTable/ItemAvailability.tsx | 42 ++++++++++++------- src/config/constants.ts | 3 +- src/models/Bib.ts | 2 +- src/models/Item.ts | 8 ---- ...emAvailability.tsx => ItemAvailability.ts} | 41 ++++++++++++------ 5 files changed, 59 insertions(+), 37 deletions(-) rename src/models/{ItemAvailability.tsx => ItemAvailability.ts} (70%) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index b218e547e..c0267af1b 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -18,13 +18,29 @@ interface ItemAvailabilityProps { item: Item } +const { + EDGE_CASE, + RECAP_GENERAL_COLLECTIONS, + ONSITE_GENERAL_COLLECTIONS, + NOT_AVAILABLE, + // special collections availability keys + RECAP_AEON, + ONSITE_AEON, + ONSITE_AEON_FINDING_AID, + RECAP_AEON_FINDING_AID, + ONSITE_FINDING_AID, + RECAP_FINDING_AID, + ONSITE_NO_FINDING_AID_NO_AEON, + RECAP_NO_FINDING_AID_NO_AEON, +} = availabilityKeys + /** * The ItemAvailability component appears below the Item table and displays * info about an item's availability. * TODO: Add Feedback box, Due date, Available font styles */ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { - if (item.availability.key === availabilityKeys.RECAP_GENERAL_COLLECTIONS) { + if (item.availability.key === RECAP_GENERAL_COLLECTIONS) { return ( How do I pick up this item and when will it be ready? @@ -34,17 +50,15 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { let message switch (item.availability.key) { - case availabilityKeys.RECAP_GENERAL_COLLECTIONS: + case RECAP_GENERAL_COLLECTIONS: throw "This key doesn't have a message. This component should be returning earlier than this." - case availabilityKeys.EDGE_CASE: + case EDGE_CASE: message = break - case (availabilityKeys.RECAP_AEON, - availabilityKeys.ONSITE_AEON, - availabilityKeys.RECAP_AEON_FINDING_AID): + case (RECAP_AEON, ONSITE_AEON, RECAP_AEON_FINDING_AID): message = break - case availabilityKeys.ONSITE_AEON_FINDING_AID: + case ONSITE_AEON_FINDING_AID: message = ( <> @@ -52,7 +66,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) break - case availabilityKeys.ONSITE_AEON: + case ONSITE_AEON: message = ( <> @@ -60,7 +74,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) break - case availabilityKeys.ONSITE_FINDING_AID: + case ONSITE_FINDING_AID: message = ( <> @@ -69,7 +83,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) break - case availabilityKeys.RECAP_FINDING_AID: + case RECAP_FINDING_AID: message = ( <> @@ -77,7 +91,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) break - case availabilityKeys.RECAP_NO_FINDING_AID_NO_AEON: + case RECAP_NO_FINDING_AID_NO_AEON: message = ( <> @@ -85,7 +99,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) break - case availabilityKeys.ONSITE_NO_FINDING_AID_NO_AEON: + case ONSITE_NO_FINDING_AID_NO_AEON: message = ( <> @@ -94,10 +108,10 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) break - case availabilityKeys.ONSITE_GENERAL_COLLECTIONS: + case ONSITE_GENERAL_COLLECTIONS: message = break - case availabilityKeys.NOT_AVAILABLE: + case NOT_AVAILABLE: message = break } diff --git a/src/config/constants.ts b/src/config/constants.ts index 9ed03ac34..2f704b1c8 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -136,11 +136,12 @@ export const NYPL_LOCATIONS = { } export const availabilityKeys = { + // anything not covered by the cases below is EDGE_CASE EDGE_CASE: "edgeCase", // there is only one not available case, so availability is assumed as the default + NOT_AVAILABLE: "notAvailable", RECAP_GENERAL_COLLECTIONS: "Recap", ONSITE_GENERAL_COLLECTIONS: "Onsite", - NOT_AVAILABLE: "notAvailable", // special collections availability keys RECAP_AEON: "RecapAeon", AEON: "Aeon", diff --git a/src/models/Bib.ts b/src/models/Bib.ts index d20fdad61..8f2e846d8 100644 --- a/src/models/Bib.ts +++ b/src/models/Bib.ts @@ -42,13 +42,13 @@ export default class Bib { this.materialType = (result.materialType?.length && result.materialType[0]?.prefLabel) || null this.issuance = (result.issuance?.length && result.issuance) || null - this.items = this.getItemsFromResult(result) this.itemAggregations = result.itemAggregations || null this.hasItemDates = result.hasItemDates || false this.subjectHeadings = result.subjectHeadings || null this.findingAid = result.supplementaryContent?.find((el) => el.label === "Finding aid") ?.url || null + this.items = this.getItemsFromResult(result) } get url() { diff --git a/src/models/Item.ts b/src/models/Item.ts index 121305a84..ebe724ce4 100644 --- a/src/models/Item.ts +++ b/src/models/Item.ts @@ -60,18 +60,10 @@ export default class Item { this.isEDDRequestable = item.eddRequestable this.bibTitle = bib.titleDisplay this.availability = new ItemAvailability({ - location: this.location, - dueDate: this.dueDate, isAvailable: this.isAvailable, isReCAP: this.isReCAP, aeonUrl: this.aeonUrl, findingAid: bib.findingAid, - itemMetadata: { - id: this.id, - barcode: this.barcode, - callNumber: this.callNumber, - bibId: this.bibId, - }, }) } diff --git a/src/models/ItemAvailability.tsx b/src/models/ItemAvailability.ts similarity index 70% rename from src/models/ItemAvailability.tsx rename to src/models/ItemAvailability.ts index 4df0fd29a..5125967e3 100644 --- a/src/models/ItemAvailability.tsx +++ b/src/models/ItemAvailability.ts @@ -1,5 +1,21 @@ import { availabilityKeys } from "../config/constants" +const { + EDGE_CASE, + RECAP_GENERAL_COLLECTIONS, + ONSITE_GENERAL_COLLECTIONS, + NOT_AVAILABLE, + // special collections availability keys + RECAP_AEON, + ONSITE_AEON, + ONSITE_AEON_FINDING_AID, + RECAP_AEON_FINDING_AID, + ONSITE_FINDING_AID, + RECAP_FINDING_AID, + ONSITE_NO_FINDING_AID_NO_AEON, + RECAP_NO_FINDING_AID_NO_AEON, +} = availabilityKeys + class ItemAvailability { key: string isAvailable: boolean @@ -26,39 +42,38 @@ class ItemAvailability { const practicallySpecialCollections = !!(findingAid || aeonUrl) this.definitelyNotSpecialCollections = !this.specialCollections && !practicallySpecialCollections - this.key = this.buildKey() } buildKey() { // All unavailable records have the same messaging. // general collections messages if (!this.isAvailable) { - return availabilityKeys.NOT_AVAILABLE + return NOT_AVAILABLE } if (this.isReCAP && this.definitelyNotSpecialCollections) { - return availabilityKeys.RECAP_GENERAL_COLLECTIONS + return RECAP_GENERAL_COLLECTIONS } if (this.isOnsite && this.definitelyNotSpecialCollections) { - return availabilityKeys.ONSITE_GENERAL_COLLECTIONS + return ONSITE_GENERAL_COLLECTIONS } // special collections messaging if (this.aeonUrl && this.isReCAP && !this.findingAid) { - return availabilityKeys.RECAP_AEON + return RECAP_AEON } if (this.aeonUrl && this.isReCAP && this.findingAid) { - return availabilityKeys.RECAP_AEON_FINDING_AID + return RECAP_AEON_FINDING_AID } if (this.aeonUrl && this.isOnsite && !this.findingAid) { - return availabilityKeys.ONSITE_AEON + return ONSITE_AEON } if (this.isOnsite && this.aeonUrl && this.findingAid) { - return availabilityKeys.ONSITE_AEON_FINDING_AID + return ONSITE_AEON_FINDING_AID } if (this.isOnsite && this.findingAid && !this.aeonUrl) { - return availabilityKeys.ONSITE_FINDING_AID + return ONSITE_FINDING_AID } if (this.isReCAP && this.findingAid && !this.aeonUrl) { - return availabilityKeys.RECAP_FINDING_AID + return RECAP_FINDING_AID } if ( this.isOnsite && @@ -66,7 +81,7 @@ class ItemAvailability { !this.aeonUrl && this.specialCollections ) { - return availabilityKeys.ONSITE_NO_FINDING_AID_NO_AEON + return ONSITE_NO_FINDING_AID_NO_AEON } if ( this.isReCAP && @@ -74,8 +89,8 @@ class ItemAvailability { !this.aeonUrl && this.specialCollections ) { - return availabilityKeys.RECAP_NO_FINDING_AID_NO_AEON - } else return availabilityKeys.EDGE_CASE + return RECAP_NO_FINDING_AID_NO_AEON + } else return EDGE_CASE } } From 17628f4e865eee8a5ad72b48047412b557ff9598 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Thu, 19 Dec 2024 10:53:52 -0500 Subject: [PATCH 22/44] add test for bibs and finding aid --- src/models/modelTests/Bib.test.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/models/modelTests/Bib.test.ts b/src/models/modelTests/Bib.test.ts index 595a3235b..22a752424 100644 --- a/src/models/modelTests/Bib.test.ts +++ b/src/models/modelTests/Bib.test.ts @@ -14,17 +14,17 @@ describe("Bib model", () => { describe("constructor", () => { describe("findingAid", () => { + const findingAidBib = new Bib({ + ...bibWithItems.resource, + supplementaryContent: [ + { + "@type": "nypl:SupplementaryContent", + label: "Finding aid", + url: "http://archives.nypl.org/scm/29990", + }, + ], + }) it("initializes the finding aid when present", () => { - const findingAidBib = new Bib({ - ...bibWithItems.resource, - supplementaryContent: [ - { - "@type": "nypl:SupplementaryContent", - label: "Finding aid", - url: "http://archives.nypl.org/scm/29990", - }, - ], - }) expect(findingAidBib.findingAid).toBe( "http://archives.nypl.org/scm/29990" ) @@ -38,6 +38,11 @@ describe("Bib model", () => { it("can handle no supplementary content", () => { expect(bib.findingAid).toBe(null) }) + it("initializes finding aid in time to populate finding aid on item availability", () => { + expect( + findingAidBib.items.every((item) => item.availability.findingAid) + ).toBe(true) + }) }) it("initializes the Bib ID with the with the Bib's @id field", () => { expect(bib.id).toBe("b15080796") From a9232261c953e3f6a904e1cad16791164c05df72 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Thu, 19 Dec 2024 15:13:47 -0500 Subject: [PATCH 23/44] update to specRequestable and variable casing of finding aid --- .../ItemTable/ItemAvailability/FindingAid.tsx | 2 +- src/models/Bib.ts | 5 +++-- src/models/Item.ts | 1 + src/models/ItemAvailability.ts | 18 +++++++---------- .../modelTests/ItemAvailability.test.ts | 20 +++++++++---------- 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability/FindingAid.tsx b/src/components/ItemTable/ItemAvailability/FindingAid.tsx index f98c93b26..84440b2a4 100644 --- a/src/components/ItemTable/ItemAvailability/FindingAid.tsx +++ b/src/components/ItemTable/ItemAvailability/FindingAid.tsx @@ -4,7 +4,7 @@ const FindingAid = ({ url }: { url: string }) => { return ( <> {". See the "} - {"Finding aid"} + {"finding aid"} {" for details"} ) diff --git a/src/models/Bib.ts b/src/models/Bib.ts index 8f2e846d8..e21644ebf 100644 --- a/src/models/Bib.ts +++ b/src/models/Bib.ts @@ -46,8 +46,9 @@ export default class Bib { this.hasItemDates = result.hasItemDates || false this.subjectHeadings = result.subjectHeadings || null this.findingAid = - result.supplementaryContent?.find((el) => el.label === "Finding aid") - ?.url || null + result.supplementaryContent?.find( + (el) => el.label.toLocaleLowerCase() === "finding aid" + )?.url || null this.items = this.getItemsFromResult(result) } diff --git a/src/models/Item.ts b/src/models/Item.ts index ebe724ce4..209605e2a 100644 --- a/src/models/Item.ts +++ b/src/models/Item.ts @@ -60,6 +60,7 @@ export default class Item { this.isEDDRequestable = item.eddRequestable this.bibTitle = bib.titleDisplay this.availability = new ItemAvailability({ + isSpecRequestable: item.specRequestable, isAvailable: this.isAvailable, isReCAP: this.isReCAP, aeonUrl: this.aeonUrl, diff --git a/src/models/ItemAvailability.ts b/src/models/ItemAvailability.ts index 5125967e3..6c72f8ff4 100644 --- a/src/models/ItemAvailability.ts +++ b/src/models/ItemAvailability.ts @@ -22,26 +22,22 @@ class ItemAvailability { isReCAP: boolean aeonUrl: string findingAid: string - specialCollections?: boolean + isSpecRequestable?: boolean isOnsite: boolean - definitelyNotSpecialCollections: boolean constructor({ isAvailable, isReCAP, aeonUrl, findingAid, - specialCollections, + isSpecRequestable, }) { this.findingAid = findingAid this.isReCAP = isReCAP this.isAvailable = isAvailable this.aeonUrl = aeonUrl this.isOnsite = !this.isReCAP - this.specialCollections = specialCollections - const practicallySpecialCollections = !!(findingAid || aeonUrl) - this.definitelyNotSpecialCollections = - !this.specialCollections && !practicallySpecialCollections + this.isSpecRequestable = isSpecRequestable this.key = this.buildKey() } buildKey() { @@ -50,10 +46,10 @@ class ItemAvailability { if (!this.isAvailable) { return NOT_AVAILABLE } - if (this.isReCAP && this.definitelyNotSpecialCollections) { + if (this.isReCAP && !this.isSpecRequestable) { return RECAP_GENERAL_COLLECTIONS } - if (this.isOnsite && this.definitelyNotSpecialCollections) { + if (this.isOnsite && !this.isSpecRequestable) { return ONSITE_GENERAL_COLLECTIONS } // special collections messaging @@ -79,7 +75,7 @@ class ItemAvailability { this.isOnsite && !this.findingAid && !this.aeonUrl && - this.specialCollections + this.isSpecRequestable ) { return ONSITE_NO_FINDING_AID_NO_AEON } @@ -87,7 +83,7 @@ class ItemAvailability { this.isReCAP && !this.findingAid && !this.aeonUrl && - this.specialCollections + this.isSpecRequestable ) { return RECAP_NO_FINDING_AID_NO_AEON } else return EDGE_CASE diff --git a/src/models/modelTests/ItemAvailability.test.ts b/src/models/modelTests/ItemAvailability.test.ts index 1e8b3f0d0..c0883062e 100644 --- a/src/models/modelTests/ItemAvailability.test.ts +++ b/src/models/modelTests/ItemAvailability.test.ts @@ -8,7 +8,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: false, aeonUrl: null, findingAid: null, - specialCollections: false, + isSpecRequestable: false, }) expect(availability.key).toBe(availabilityKeys.NOT_AVAILABLE) }) @@ -18,7 +18,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: true, aeonUrl: null, findingAid: null, - specialCollections: false, + isSpecRequestable: false, }) expect(availability.key).toBe(availabilityKeys.RECAP_GENERAL_COLLECTIONS) }) @@ -28,7 +28,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: true, aeonUrl: "spaghetti.com", findingAid: null, - specialCollections: true, + isSpecRequestable: true, }) expect(availability.key).toBe(availabilityKeys.RECAP_AEON) }) @@ -38,7 +38,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: true, aeonUrl: "spaghetti.com", findingAid: "meatballs.com", - specialCollections: true, + isSpecRequestable: true, }) expect(availability.key).toBe(availabilityKeys.RECAP_AEON_FINDING_AID) }) @@ -48,7 +48,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: false, aeonUrl: "spaghetti.com", findingAid: false, - specialCollections: true, + isSpecRequestable: true, }) expect(availability.key).toBe(availabilityKeys.ONSITE_AEON) }) @@ -58,7 +58,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: false, aeonUrl: "spaghetti.com", findingAid: "meatballs.com", - specialCollections: true, + isSpecRequestable: true, }) expect(availability.key).toBe(availabilityKeys.ONSITE_AEON_FINDING_AID) }) @@ -68,7 +68,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: false, aeonUrl: false, findingAid: "meatballs.com", - specialCollections: true, + isSpecRequestable: true, }) expect(availability.key).toBe(availabilityKeys.ONSITE_FINDING_AID) }) @@ -78,7 +78,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: true, aeonUrl: false, findingAid: "meatballs.com", - specialCollections: true, + isSpecRequestable: true, }) expect(availability.key).toBe(availabilityKeys.RECAP_FINDING_AID) }) @@ -88,7 +88,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: true, aeonUrl: false, findingAid: false, - specialCollections: true, + isSpecRequestable: true, }) expect(availability.key).toBe(availabilityKeys.RECAP_NO_FINDING_AID_NO_AEON) }) @@ -98,7 +98,7 @@ describe("ItemAvailabilityFactory", () => { isReCAP: false, aeonUrl: false, findingAid: false, - specialCollections: true, + isSpecRequestable: true, }) expect(availability.key).toBe( availabilityKeys.ONSITE_NO_FINDING_AID_NO_AEON From a4cf18d009e4d56b67cc703c1e1c61f808aab3d3 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Thu, 19 Dec 2024 15:42:04 -0500 Subject: [PATCH 24/44] fix recap aeon only case --- src/components/ItemTable/ItemAvailability.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index c0267af1b..b57c361fd 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -55,7 +55,8 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { case EDGE_CASE: message = break - case (RECAP_AEON, ONSITE_AEON, RECAP_AEON_FINDING_AID): + case RECAP_AEON: + case RECAP_AEON_FINDING_AID: message = break case ONSITE_AEON_FINDING_AID: From 115ec562ab9e824591c85615803b9d03d4ef6878 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Thu, 19 Dec 2024 16:20:46 -0500 Subject: [PATCH 25/44] update request buttons to remove ternary --- .../ItemTable/ItemAvailability.test.tsx | 22 ++++---- src/components/ItemTable/RequestButtons.tsx | 54 +++++++++---------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.test.tsx b/src/components/ItemTable/ItemAvailability.test.tsx index f68019c40..80d81d15f 100644 --- a/src/components/ItemTable/ItemAvailability.test.tsx +++ b/src/components/ItemTable/ItemAvailability.test.tsx @@ -28,7 +28,7 @@ describe("ItemAvailability", () => { isReCAP: false, aeonUrl: "spaghetti.com", findingAid: "meatballs.com", - specialCollections: true, + isSpecRequestable: true, }) render() expect(screen.getByText("Available by appointment")).toBeInTheDocument() @@ -43,7 +43,7 @@ describe("ItemAvailability", () => { isReCAP: true, aeonUrl: "spaghetti.com", findingAid: "meatballs.com", - specialCollections: true, + isSpecRequestable: true, }) render() expect(screen.getByText("Available by appointment")).toBeInTheDocument() @@ -59,7 +59,7 @@ describe("ItemAvailability", () => { isReCAP: true, aeonUrl: "spaghetti.com", findingAid: "meatballs.com", - specialCollections: true, + isSpecRequestable: true, }) render() expect(screen.getByText("Available by appointment")).toBeInTheDocument() @@ -75,7 +75,7 @@ describe("ItemAvailability", () => { isReCAP: false, aeonUrl: "spaghetti.com", findingAid: null, - specialCollections: true, + isSpecRequestable: true, }) render() expect(screen.getByText("Available by appointment")).toBeInTheDocument() @@ -91,11 +91,11 @@ describe("ItemAvailability", () => { isReCAP: false, aeonUrl: null, findingAid: "meatballs.com", - specialCollections: true, + isSpecRequestable: true, }) render() expect(screen.getByText("Available by appointment")).toBeInTheDocument() - expect(screen.queryByRole("link")).toHaveTextContent("Finding aid") + expect(screen.queryByRole("link")).toHaveTextContent("finding aid") expect( screen.getByText( "at Schwarzman Building - Main Reading Room 315. See the ", @@ -110,11 +110,11 @@ describe("ItemAvailability", () => { isReCAP: true, aeonUrl: null, findingAid: "meatballs.com", - specialCollections: true, + isSpecRequestable: true, }) render() expect(screen.getByText("Available by appointment")).toBeInTheDocument() - expect(screen.queryByRole("link")).toHaveTextContent("Finding aid") + expect(screen.queryByRole("link")).toHaveTextContent("finding aid") expect( screen.queryByText("Schwarzman Building - Main Reading Room 315", { exact: false, @@ -128,7 +128,7 @@ describe("ItemAvailability", () => { isReCAP: true, aeonUrl: null, findingAid: null, - specialCollections: true, + isSpecRequestable: true, }) render() expect(screen.getByText("Available by appointment")).toBeInTheDocument() @@ -140,14 +140,14 @@ describe("ItemAvailability", () => { ).not.toBeInTheDocument() expect(screen.getByText("contact a librarian")).toBeInTheDocument() }) - it("recap NO aeon NO finding aid", () => { + it("onsite NO aeon NO finding aid", () => { const item = new Item(itemPhysicallyRequestable, parentBib) item.availability = new ItemAvailabilityModel({ isAvailable: true, isReCAP: false, aeonUrl: null, findingAid: null, - specialCollections: true, + isSpecRequestable: true, }) render() expect(screen.getByText("Available by appointment")).toBeInTheDocument() diff --git a/src/components/ItemTable/RequestButtons.tsx b/src/components/ItemTable/RequestButtons.tsx index 164c7b0bd..06f81d36d 100644 --- a/src/components/ItemTable/RequestButtons.tsx +++ b/src/components/ItemTable/RequestButtons.tsx @@ -16,7 +16,7 @@ const RequestButtons = ({ item }: RequestButtonsProps) => { if (item.allLocationsClosed) return null return ( - {item.aeonUrl ? ( + {item.aeonUrl && ( { > Request appointment - ) : ( - <> - {item.isPhysicallyRequestable && ( - - Request for on-site use - - )} - {item.isEDDRequestable && ( - - Request scan - - )} - + )} + + {item.isPhysicallyRequestable && ( + + Request for on-site use + + )} + {item.isEDDRequestable && ( + + Request scan + )} ) From 57beae11698ce550fbdb45267a97a6be37889bab Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Thu, 19 Dec 2024 16:27:48 -0500 Subject: [PATCH 26/44] formatting periods --- .../ItemTable/ItemAvailability/AvailableByAppointment.tsx | 2 +- src/components/ItemTable/ItemAvailability/FindingAid.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx index 733450247..5a5ae9d50 100644 --- a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx +++ b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx @@ -6,7 +6,7 @@ const AvailableByAppointment = () => { return ( <> - Available by appointment + Available by appointment. ) diff --git a/src/components/ItemTable/ItemAvailability/FindingAid.tsx b/src/components/ItemTable/ItemAvailability/FindingAid.tsx index 84440b2a4..b2c8168be 100644 --- a/src/components/ItemTable/ItemAvailability/FindingAid.tsx +++ b/src/components/ItemTable/ItemAvailability/FindingAid.tsx @@ -3,9 +3,9 @@ import ExternalLink from "../../Links/ExternalLink/ExternalLink" const FindingAid = ({ url }: { url: string }) => { return ( <> - {". See the "} + {" See the "} {"finding aid"} - {" for details"} + {" for details."} ) } From 74b8e769c2c293a48d864b43f84e56d3b5c681c7 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Fri, 20 Dec 2024 12:22:43 -0500 Subject: [PATCH 27/44] fix periods in tests --- src/components/ItemTable/ItemAvailability.test.tsx | 12 ++++++------ src/components/ItemTable/ItemAvailability.tsx | 10 +++++++--- .../ItemAvailability/AvailableByAppointment.tsx | 8 ++++---- src/config/config.ts | 6 +++--- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.test.tsx b/src/components/ItemTable/ItemAvailability.test.tsx index 80d81d15f..7458e0a36 100644 --- a/src/components/ItemTable/ItemAvailability.test.tsx +++ b/src/components/ItemTable/ItemAvailability.test.tsx @@ -46,7 +46,7 @@ describe("ItemAvailability", () => { isSpecRequestable: true, }) render() - expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.getByText("Available by appointment.")).toBeInTheDocument() expect(screen.queryByRole("link")).not.toBeInTheDocument() expect( screen.queryByText("Schwarzman Building - Main Reading Room 315") @@ -62,7 +62,7 @@ describe("ItemAvailability", () => { isSpecRequestable: true, }) render() - expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.getByText("Available by appointment.")).toBeInTheDocument() expect(screen.queryByRole("link")).not.toBeInTheDocument() expect( screen.queryByText("Schwarzman Building - Main Reading Room 315") @@ -81,7 +81,7 @@ describe("ItemAvailability", () => { expect(screen.getByText("Available by appointment")).toBeInTheDocument() expect(screen.queryByRole("link")).not.toBeInTheDocument() expect( - screen.getByText("at Schwarzman Building - Main Reading Room 315") + screen.getByText("at Schwarzman Building - Main Reading Room 315.") ).toBeInTheDocument() }) it("onsite NO aeon YES finding aid", () => { @@ -113,7 +113,7 @@ describe("ItemAvailability", () => { isSpecRequestable: true, }) render() - expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.getByText("Available by appointment.")).toBeInTheDocument() expect(screen.queryByRole("link")).toHaveTextContent("finding aid") expect( screen.queryByText("Schwarzman Building - Main Reading Room 315", { @@ -131,7 +131,7 @@ describe("ItemAvailability", () => { isSpecRequestable: true, }) render() - expect(screen.getByText("Available by appointment")).toBeInTheDocument() + expect(screen.getByText("Available by appointment.")).toBeInTheDocument() expect(screen.queryByRole("link")).not.toBeInTheDocument() expect( screen.queryByText("Schwarzman Building - Main Reading Room 315", { @@ -155,7 +155,7 @@ describe("ItemAvailability", () => { "Schwarzman Building - Main Reading Room 315" ) expect( - screen.queryByText("Schwarzman Building - Main Reading Room 315", { + screen.queryByText("Schwarzman Building - Main Reading Room 315.", { exact: false, }) ).toBeInTheDocument() diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index b57c361fd..a16efc1a2 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -57,7 +57,11 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { break case RECAP_AEON: case RECAP_AEON_FINDING_AID: - message = + message = ( + <> + + + ) break case ONSITE_AEON_FINDING_AID: message = ( @@ -87,7 +91,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { case RECAP_FINDING_AID: message = ( <> - + ) @@ -95,7 +99,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { case RECAP_NO_FINDING_AID_NO_AEON: message = ( <> - + ) diff --git a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx index 5a5ae9d50..3e3844e93 100644 --- a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx +++ b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx @@ -2,11 +2,11 @@ import { Box } from "@nypl/design-system-react-components" import { appConfig } from "../../../config/config" import ExternalLink from "../../Links/ExternalLink/ExternalLink" -const AvailableByAppointment = () => { +const AvailableByAppointment = ({ displayPeriod = false }) => { return ( <> - Available by appointment. + {`Available by appointment${displayPeriod ? ". " : ""}`} ) @@ -18,7 +18,7 @@ const AvailableAtLink = ({ location }) => { <> {" at "} - {location.prefLabel} + {location.prefLabel + "."} ) @@ -26,7 +26,7 @@ const AvailableAtLink = ({ location }) => { const AvailableAt = ({ location }) => { if (!location?.endpoint) return null - else return ` at ${location.prefLabel}` + else return ` at ${location.prefLabel}. ` } export { AvailableByAppointment, AvailableAtLink, AvailableAt } diff --git a/src/config/config.ts b/src/config/config.ts index fe46b743e..4a34b5649 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -6,9 +6,9 @@ export const appConfig: AppConfig = { (process.env.NEXT_PUBLIC_APP_ENV as Environment) || "development", apiEndpoints: { platform: { - development: "https://qa-platform.nypl.org/api", - qa: "https://qa-platform.nypl.org/api", - production: "https://platform.nypl.org/api", + development: "http://localhost:8082/api", + qa: "http://localhost:8082/api", + production: "http://localhost:8082/api", }, domain: { development: "local.nypl.org:8080", From a04fe17ed6d040900d16569563c0e4b448ae1e69 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Fri, 20 Dec 2024 15:39:35 -0500 Subject: [PATCH 28/44] return recap general collections message from switch --- src/components/ItemTable/ItemAvailability.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index a16efc1a2..cfe38d945 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -40,18 +40,14 @@ const { * TODO: Add Feedback box, Due date, Available font styles */ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { - if (item.availability.key === RECAP_GENERAL_COLLECTIONS) { - return ( - - How do I pick up this item and when will it be ready? - - ) - } - let message switch (item.availability.key) { case RECAP_GENERAL_COLLECTIONS: - throw "This key doesn't have a message. This component should be returning earlier than this." + return ( + + How do I pick up this item and when will it be ready? + + ) case EDGE_CASE: message = break From 5fb0ea1d068e63045ecddff51be62619d3ede0bc Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Fri, 20 Dec 2024 15:55:42 -0500 Subject: [PATCH 29/44] fix types --- src/components/ItemTable/ItemAvailability.tsx | 14 ++++++++++---- .../ItemAvailability/ContactALibrarian.tsx | 11 ++++++++++- .../ItemTable/ItemAvailability/NotAvailable.tsx | 15 +++++++++++++-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index cfe38d945..5c93dc659 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -41,6 +41,12 @@ const { */ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { let message + const itemMetadata = { + id: item.id, + barcode: item.barcode, + callNumber: item.callNumber, + bibId: item.bibId, + } switch (item.availability.key) { case RECAP_GENERAL_COLLECTIONS: return ( @@ -49,7 +55,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { ) case EDGE_CASE: - message = + message = break case RECAP_AEON: case RECAP_AEON_FINDING_AID: @@ -96,7 +102,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { message = ( <> - + ) break @@ -105,7 +111,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { <> - + ) break @@ -113,7 +119,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { message = break case NOT_AVAILABLE: - message = + message = break } diff --git a/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx b/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx index f9b87a3ed..79cb5565e 100644 --- a/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx +++ b/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx @@ -4,7 +4,16 @@ import { FeedbackContext } from "../../../context/FeedbackContext" import type { ItemMetadata } from "../../../types/itemTypes" import type Item from "../../../models/Item" -const ContactALibrarian = ({ item }: { item: Item }) => { +const ContactALibrarian = ({ + item, +}: { + item: { + id: string + barcode: string + callNumber: string + bibId: string + } +}) => { const { onOpen, setItemMetadata } = useContext(FeedbackContext) const onContact = (metadata: ItemMetadata) => { setItemMetadata(metadata) diff --git a/src/components/ItemTable/ItemAvailability/NotAvailable.tsx b/src/components/ItemTable/ItemAvailability/NotAvailable.tsx index 0c2057cdd..08fbc0471 100644 --- a/src/components/ItemTable/ItemAvailability/NotAvailable.tsx +++ b/src/components/ItemTable/ItemAvailability/NotAvailable.tsx @@ -2,7 +2,18 @@ import { Box } from "@nypl/design-system-react-components" import ContactALibrarian from "./ContactALibrarian" import type Item from "../../../models/Item" -const NotAvailable = ({ item }: { item: Item }) => { +const NotAvailable = ({ + item, + dueDate, +}: { + dueDate: string + item: { + id: string + barcode: string + callNumber: string + bibId: string + } +}) => { const itemMetadata = { id: item.id, barcode: item.barcode, @@ -14,7 +25,7 @@ const NotAvailable = ({ item }: { item: Item }) => { Not available - {item.dueDate && ` - In use until ${item.dueDate}`} + {dueDate && ` - In use until ${dueDate}`} ) From a4be195baff44e81849749b77b58dbb31e9280c0 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Fri, 20 Dec 2024 15:57:15 -0500 Subject: [PATCH 30/44] return component instead of string --- .../ItemTable/ItemAvailability/AvailableByAppointment.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx index 3e3844e93..7510ca440 100644 --- a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx +++ b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx @@ -1,4 +1,4 @@ -import { Box } from "@nypl/design-system-react-components" +import { Box, Text } from "@nypl/design-system-react-components" import { appConfig } from "../../../config/config" import ExternalLink from "../../Links/ExternalLink/ExternalLink" @@ -26,7 +26,7 @@ const AvailableAtLink = ({ location }) => { const AvailableAt = ({ location }) => { if (!location?.endpoint) return null - else return ` at ${location.prefLabel}. ` + else return ` at ${location.prefLabel}. ` } export { AvailableByAppointment, AvailableAtLink, AvailableAt } From e9979565b43aad8f7f6316979768f0aba3898fd8 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Fri, 20 Dec 2024 15:59:24 -0500 Subject: [PATCH 31/44] replace platform urls --- src/config/config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/config.ts b/src/config/config.ts index 4a34b5649..fe46b743e 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -6,9 +6,9 @@ export const appConfig: AppConfig = { (process.env.NEXT_PUBLIC_APP_ENV as Environment) || "development", apiEndpoints: { platform: { - development: "http://localhost:8082/api", - qa: "http://localhost:8082/api", - production: "http://localhost:8082/api", + development: "https://qa-platform.nypl.org/api", + qa: "https://qa-platform.nypl.org/api", + production: "https://platform.nypl.org/api", }, domain: { development: "local.nypl.org:8080", From 70f97b18ada67c90a7bf345372bef55dab2aca25 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Fri, 20 Dec 2024 16:36:23 -0500 Subject: [PATCH 32/44] fix string return --- .../ItemTable/ItemAvailability/AvailableByAppointment.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx index 7510ca440..7e7ce0c2b 100644 --- a/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx +++ b/src/components/ItemTable/ItemAvailability/AvailableByAppointment.tsx @@ -26,7 +26,7 @@ const AvailableAtLink = ({ location }) => { const AvailableAt = ({ location }) => { if (!location?.endpoint) return null - else return ` at ${location.prefLabel}. ` + else return <> {` at ${location.prefLabel}. `} } export { AvailableByAppointment, AvailableAtLink, AvailableAt } From 132661f928bf84ff3049b8e9ffc06f90f07c7d45 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Mon, 23 Dec 2024 11:06:53 -0500 Subject: [PATCH 33/44] rm link from onsite no finding aid no aeon --- src/components/ItemTable/ItemAvailability.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ItemTable/ItemAvailability.tsx b/src/components/ItemTable/ItemAvailability.tsx index 5c93dc659..2d653b0be 100644 --- a/src/components/ItemTable/ItemAvailability.tsx +++ b/src/components/ItemTable/ItemAvailability.tsx @@ -110,7 +110,7 @@ const ItemAvailability = ({ item }: ItemAvailabilityProps) => { message = ( <> - + ) From eb13be4417001f3a2a99dac7b6c5b834f7943735 Mon Sep 17 00:00:00 2001 From: Vera Kahn Date: Mon, 23 Dec 2024 11:08:39 -0500 Subject: [PATCH 34/44] rm dash from contactALibrarian component --- src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx | 2 +- src/components/ItemTable/ItemAvailability/NotAvailable.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx b/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx index 79cb5565e..6e2714002 100644 --- a/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx +++ b/src/components/ItemTable/ItemAvailability/ContactALibrarian.tsx @@ -21,7 +21,7 @@ const ContactALibrarian = ({ } return ( <> - {" - Please "} + {" Please "}