Skip to content

Commit

Permalink
Merge pull request #87 from reload/order-material-multiple-ids
Browse files Browse the repository at this point in the history
Support multiple material ids when ordering
  • Loading branch information
kasperg authored Mar 2, 2020
2 parents 4ea1452 + 50ea8ba commit b7876e6
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 45 deletions.
11 changes: 10 additions & 1 deletion src/apps/order-material/order-material.dev.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ export function Entry() {
"Success message",
"Materialet er bestilt, dit bibliotek vil give besked når det er klar til afhentning."
)}
id={text("Material ID", "870970-basis:54172613")}
// Prefer text instead of array knob here to simulate a naive mount using
// data attributes (text) as props.
ids={text(
"Material IDs (separate by ,)",
[
"870970-basis:47092183",
"870970-basis:51980190",
"870970-basis:23154382"
].join(",")
)}
loginUrl={text(
"Login URL",
"https://lollandbib.dk/adgangsplatformen/login?destination=ting/object/:id"
Expand Down
28 changes: 22 additions & 6 deletions src/apps/order-material/order-material.entry.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ import OpenPlatform from "../../core/OpenPlatform";

const client = new OpenPlatform();

/**
* Transform a set of ids to an array of ids.
*
* This supports transforming a single string with multiple ids separated by ,
* (used in naive app mounts using data attributes as props) to an array of ids.
*
* @param {string|string[]} One or more ids.
* @returns {string[]} Array of ids.
*/
function idsArray(ids) {
return typeof ids === "string" ? ids.split(",") : ids;
}

function OrderMaterialEntry({
text,
successText,
Expand All @@ -16,7 +29,7 @@ function OrderMaterialEntry({
progressText,
unavailableText,
invalidPickupBranchText,
id,
ids,
loginUrl,
pickupBranch,
expires
Expand All @@ -26,7 +39,7 @@ function OrderMaterialEntry({
function orderMaterial() {
setStatus("processing");
client
.orderMaterial({ pids: [id], pickupBranch, expires })
.orderMaterial({ pids: idsArray(ids), pickupBranch, expires })
.then(function materialOrdered() {
setStatus("finished");
})
Expand All @@ -47,7 +60,7 @@ function OrderMaterialEntry({
} else {
// Check that the material is available for ILL.
client
.canBeOrdered(id)
.canBeOrdered(idsArray(ids))
.then(function onAvailabilityResult(available) {
setStatus(available ? "ready" : "unavailable");
})
Expand All @@ -60,7 +73,7 @@ function OrderMaterialEntry({
setStatus("failed");
});
},
[id, pickupBranch]
[ids, pickupBranch]
);

return (
Expand All @@ -76,7 +89,7 @@ function OrderMaterialEntry({
status={status}
onClick={orderMaterial}
loginUrl={loginUrl}
materialId={id}
materialIds={idsArray(ids)}
/>
);
}
Expand All @@ -90,7 +103,10 @@ OrderMaterialEntry.propTypes = {
invalidPickupBranchText: PropTypes.string,
successText: PropTypes.string,
successMessage: PropTypes.string,
id: PropTypes.string.isRequired,
ids: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string)
]).isRequired,
loginUrl: urlPropType.isRequired,
pickupBranch: PropTypes.string.isRequired,
expires: PropTypes.string.isRequired
Expand Down
8 changes: 5 additions & 3 deletions src/apps/order-material/order-material.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function OrderMaterial({
successText,
successMessage,
loginUrl,
materialId
materialIds
}) {
const [open, setOpen] = useState(true);
const closeDialog = () => setOpen(false);
Expand Down Expand Up @@ -79,7 +79,9 @@ function OrderMaterial({
? replacePlaceholders({
text: loginUrl,
tags: {
id: encodeURIComponent(materialId)
// Urls only support a single material id so assume we
// want to use the first.
id: encodeURIComponent(materialIds.first)
}
})
: undefined
Expand Down Expand Up @@ -116,7 +118,7 @@ OrderMaterial.propTypes = {
"failed",
"finished"
]),
materialId: PropTypes.string.isRequired
materialIds: PropTypes.arrayOf(PropTypes.string).isRequired
};

OrderMaterial.defaultProps = {
Expand Down
75 changes: 51 additions & 24 deletions src/apps/order-material/order-material.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,59 @@ describe("Order material", () => {
cy.contains("Dit afhentningsbibliotek modtager ikke fjernlån");
});

it("Should display message if material can't be ordered", () => {
cy.server();
cy.route({
method: "GET",
url: "https://openplatform.dbc.dk/v3/libraries*",
status: 200,
response: {
statusCode: 200,
data: [{ willReceiveIll: "1" }]
}
});
[
{
title: "Should display message if a single material can't be ordered",
availability: [{ orderPossible: false }],
orderable: false
},
{
title: "Should display message if a set of materials can't be ordered",
availability: [{ orderPossible: false }, { orderPossible: false }],
orderable: false
},
{
title: "Should display button if a single material can be ordered",
availability: [{ orderPossible: true }],
orderable: true
},
{
title: "Should display button if a set of materials can be ordered",
availability: [{ orderPossible: true }, { orderPossible: false }],
orderable: true
}
].forEach(scenario => {
it(scenario.title, () => {
cy.server();
cy.route({
method: "GET",
url: "https://openplatform.dbc.dk/v3/libraries*",
status: 200,
response: {
statusCode: 200,
data: [{ willReceiveIll: "1" }]
}
});

cy.route({
method: "GET",
url: "https://openplatform.dbc.dk/v3/availability*",
status: 200,
response: {
statusCode: 200,
data: [{ orderPossible: false }]
}
});
cy.route({
method: "GET",
url: "https://openplatform.dbc.dk/v3/availability*",
status: 200,
response: {
statusCode: 200,
data: scenario.availability
}
});

cy.visit("/iframe.html?id=apps-order-material--entry");
cy.visit("/iframe.html?id=apps-order-material--entry");

cy.contains("Bestil materiale").should("not.exist");
cy.contains("Kan ikke fjernlånes");
if (scenario.orderable) {
cy.contains("Bestil materiale");
} else {
cy.contains("Bestil materiale").should("not.exist");
cy.contains("Kan ikke fjernlånes");
}
});
});

it("Should send order request to OpenPlatform when clicked", () => {
Expand Down Expand Up @@ -84,7 +111,7 @@ describe("Order material", () => {
status: 200,
response: {
statusCode: 200,
data: [{ orderPossible: true }]
data: [{ orderPossible: true }, { orderPossible: false }]
}
});

Expand Down
21 changes: 10 additions & 11 deletions src/core/OpenPlatform.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,19 @@ class OpenPlatform {
}

/**
* Check if a material can be ordered.
* Check if at least one material in a set of materials can be ordered.
*
* @param {string} pid - id of work
* The materials represented by the ids are supposed to be equivalent and thus
* we only care if at least one of the materials can be ordered.
*
* @param {string[]} pids - ids of work(s) to check.
* @returns {Promise<boolean>}
*/
async canBeOrdered(pid) {
return this.getAvailability({ pids: [pid] }).then(function getResult(
response
) {
// The API says there can be more than one reply, but nobody
// defines what that means. So if case there's more than one
// reply, only return true if all items are order-able.

return response.every(function orderIsPossible(orderStat) {
async canBeOrdered(pids) {
return this.getAvailability({ pids }).then(function getResult(response) {
// The API returns availability information for each pid. Reduce these to
// a single value by checking if at least one material can be ordered.
return response.some(function orderIsPossible(orderStat) {
return orderStat.orderPossible;
});
});
Expand Down

0 comments on commit b7876e6

Please sign in to comment.