-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SCC-3776 - Item Table Component #50
Changes from 37 commits
53583a5
494a832
eb90f4b
529ae04
b124ffc
6776e03
7e4dd90
05b2cd1
ee5c1fc
1f4806c
50a7e4a
723fd04
5ed422f
e5046b6
68cbb69
527f32b
c66f51a
20d8bbf
9ecf936
cc19610
e155254
e488321
77d2419
16485d0
02ac042
dc145c0
ee31a18
fd05fe0
d369f98
36d0a09
18ad591
df4ac1a
71cda65
0dd23d2
475c0a0
d8c6fdc
f87badb
d10de6d
a5ae2bb
27b56f4
deaa85f
08ef887
624db28
417f23a
903a570
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
PLATFORM_API_CLIENT_ID=[secret] | ||
PLATFORM_API_CLIENT_SECRET=[secret] | ||
NYPL_HEADER_URL=https://ds-header.nypl.org | ||
NYPL_HEADER_URL=https://ds-header.nypl.org | ||
NEXT_PUBLIC_CLOSED_LOCATIONS="" | ||
NEXT_PUBLIC_RECAP_CLOSED_LOCATIONS="" | ||
NEXT_PUBLIC_NON_RECAP_CLOSED_LOCATIONS="" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
import type { ItemLocationEndpoint } from "../../src/types/itemTypes" | ||
|
||
export const itemPhysicallyRequestable = { | ||
"@id": "res:i10572545", | ||
"@type": ["bf:Item"], | ||
|
@@ -16,6 +18,7 @@ export const itemPhysicallyRequestable = { | |
prefLabel: "book, limited circ, MaRLI", | ||
}, | ||
], | ||
dueDate: ["September 3rd"], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure it makes a difference to the code, but I'm pretty sure this would be formatted |
||
eddRequestable: false, | ||
enumerationChronology: ["no. 4 (2001)"], | ||
formatLiteral: ["Text"], | ||
|
@@ -281,3 +284,57 @@ export const itemNYPLReCAP = { | |
"@value": "10572546", | ||
}, | ||
} | ||
|
||
export const itemAvailableOnsite = { | ||
"@id": "res:i14119377", | ||
"@type": ["bf:Item"], | ||
accessMessage: [ | ||
{ | ||
"@id": "accessMessage:1", | ||
prefLabel: "Use in library", | ||
}, | ||
], | ||
catalogItemType: [ | ||
{ | ||
"@id": "catalogItemType:55", | ||
prefLabel: "book, limited circ, MaRLI", | ||
}, | ||
], | ||
eddRequestable: true, | ||
formatLiteral: ["Text"], | ||
holdingLocation: [ | ||
{ | ||
"@id": "loc:mal92", | ||
prefLabel: "Schwarzman Building M2 - General Research Room 315", | ||
endpoint: "schwarzman" as ItemLocationEndpoint, | ||
}, | ||
], | ||
idBarcode: ["33433048828085"], | ||
identifier: [ | ||
{ | ||
"@type": "bf:ShelfMark", | ||
"@value": "JFE 93-253", | ||
}, | ||
{ | ||
"@type": "bf:Barcode", | ||
"@value": "33433048828085", | ||
}, | ||
], | ||
m2CustomerCode: ["XF"], | ||
physRequestable: true, | ||
physicalLocation: ["JFE 93-253"], | ||
requestable: [true], | ||
shelfMark: ["JFE 93-253"], | ||
specRequestable: false, | ||
status: [ | ||
{ | ||
"@id": "status:a", | ||
prefLabel: "Available", | ||
}, | ||
], | ||
uri: "i14119377", | ||
idNyplSourceId: { | ||
"@type": "SierraNypl", | ||
"@value": "14119377", | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import React from "react" | ||
import { render, screen } from "@testing-library/react" | ||
import ItemAvailability from "./ItemAvailability" | ||
import Item from "../../models/Item" | ||
import SearchResultsBib from "../../models/SearchResultsBib" | ||
import { | ||
itemNYPLReCAP, | ||
itemPhysicallyRequestable, | ||
itemAvailableOnsite, | ||
itemUnavailable, | ||
} from "../../../__test__/fixtures/itemFixtures" | ||
import { searchResultPhysicalItems } from "../../../__test__/fixtures/searchResultPhysicalItems" | ||
|
||
const parentBib = new SearchResultsBib(searchResultPhysicalItems) | ||
|
||
describe("ItemAvailability", () => { | ||
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(<ItemAvailability item={item} />) | ||
expect( | ||
screen.getByRole("link", { | ||
name: "How do I pick up this item and when will it be ready?", | ||
}) | ||
).toHaveAttribute( | ||
"href", | ||
"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 () => { | ||
const item = new Item(itemPhysicallyRequestable, parentBib) | ||
render(<ItemAvailability item={item} />) | ||
screen.getByText(/Available by appointment/) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These would break if they're not in the document, but for completeness I think it should have the |
||
expect( | ||
screen.getByRole("link", { | ||
name: "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(<ItemAvailability item={item} />) | ||
screen.getByText(/Available/) | ||
screen.getByText(/- Can be used on site. Please visit/) | ||
expect( | ||
screen.getByRole("link", { | ||
name: "New York Public Library - Schwarzman Building M2", | ||
}) | ||
).toHaveAttribute("href", "https://www.nypl.org/locations/schwarzman") | ||
screen.getByText(/to submit a request in person./) | ||
}) | ||
it("renders the correct text for unavailable items", async () => { | ||
const item = new Item(itemUnavailable, parentBib) | ||
render(<ItemAvailability item={item} />) | ||
screen.getByText(/Not available/) | ||
screen.getByText(/- Please/) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The above comment applies to all of these. |
||
screen.getByRole("button", { | ||
name: "contact a librarian", | ||
}) | ||
screen.getByText(/for assistance./) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { Text, Link, Button, Box } from "@nypl/design-system-react-components" | ||
|
||
import { appConfig } from "../../config/config" | ||
import type Item from "../../models/Item" | ||
|
||
interface ItemAvailabilityProps { | ||
item: Item | ||
} | ||
|
||
/** | ||
* 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) => { | ||
// TODO: Move this logic into a getter function in the Item class that returns an availability status key | ||
dgcohen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// and replace this nested If with a simple switch statement | ||
if (item.isAvailable) { | ||
if (item.isReCAP && !item.aeonUrl) { | ||
// Available ReCAP item | ||
return ( | ||
<Link | ||
href={appConfig.externalUrls.researchMaterialsHelp} | ||
target="_blank" | ||
fontSize="sm" | ||
> | ||
How do I pick up this item and when will it be ready? | ||
</Link> | ||
) | ||
} else if (item.aeonUrl && item.location?.endpoint) { | ||
return ( | ||
<Text> | ||
<Box as="span" color="ui.success.primary"> | ||
Available by appointment | ||
</Box> | ||
{!item.isReCAP ? ( | ||
<> | ||
{" at "} | ||
<Link | ||
href={`${appConfig.externalUrls.locations}${item.location.endpoint}`} | ||
target="_blank" | ||
> | ||
{item.location.prefLabel} | ||
</Link> | ||
</> | ||
) : null} | ||
</Text> | ||
) | ||
} else { | ||
// Available Onsite item | ||
const locationShort = item.location.prefLabel.split("-")[0] | ||
return ( | ||
<Text> | ||
<Box as="span" color="ui.success.primary"> | ||
Available | ||
</Box> | ||
{" - Can be used on site. Please visit "} | ||
<Link | ||
href={`${appConfig.externalUrls.locations}${item.location.endpoint}`} | ||
target="_blank" | ||
> | ||
{`New York Public Library - ${locationShort}`} | ||
</Link> | ||
{" to submit a request in person."} | ||
</Text> | ||
) | ||
} | ||
} else { | ||
// Not available | ||
return ( | ||
<Text> | ||
<Box as="span" color="ui.warning.primary"> | ||
Not available | ||
</Box> | ||
{item.dueDate && ` - In use until ${item.dueDate}`} | ||
{" - Please "} | ||
<Button | ||
id="contact-librarian" | ||
buttonType="link" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this still need to be addressed? |
||
sx={{ display: "inline", fontWeight: "inherit", fontSize: "inherit" }} | ||
onClick={() => { | ||
console.log("TODO: Trigger Feedback box") | ||
}} | ||
> | ||
contact a librarian | ||
</Button> | ||
{" for assistance."} | ||
</Text> | ||
) | ||
} | ||
} | ||
|
||
export default ItemAvailability |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { Box, Table } from "@nypl/design-system-react-components" | ||
|
||
import type ItemTableData from "../../models/ItemTableData" | ||
import RequestButtons from "./RequestButtons" | ||
import ItemAvailability from "./ItemAvailability" | ||
|
||
interface ItemTableProps { | ||
itemTableData: ItemTableData | ||
} | ||
|
||
/** | ||
* The ItemTable displays item details, the RequestButtons | ||
*/ | ||
const ItemTable = ({ itemTableData }: ItemTableProps) => { | ||
return ( | ||
<> | ||
<Table | ||
columnHeaders={itemTableData.tableHeadings} | ||
tableData={itemTableData.tableData} | ||
mb="s" | ||
// TODO: These styles approximate those of the old app. | ||
// Design will VQA the component with the DS defaults, but leaving this for reference. | ||
// sx={{ | ||
// tableLayout: "fixed", | ||
// width: "full", | ||
// tr: { border: "0 !important", padding: 0 }, | ||
// "th, td, th > span, td > span": { | ||
// paddingTop: "xs", | ||
// paddingBottom: "xs", | ||
// }, | ||
// }} | ||
/> | ||
{!itemTableData.isBibPage && ( | ||
<Box mb="s"> | ||
<RequestButtons item={itemTableData.items[0]} /> | ||
<ItemAvailability item={itemTableData.items[0]} /> | ||
</Box> | ||
)} | ||
</> | ||
) | ||
} | ||
|
||
export default ItemTable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does
NEXT_PUBLIC
indicate?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That prefix allows env variables to be used on the client side.