Skip to content

Commit

Permalink
Add prop to control rendering of book circulation links. (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
ray-lee authored Nov 18, 2022
1 parent c69f7cf commit 0220aa0
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 85 deletions.
5 changes: 5 additions & 0 deletions packages/web-opds-client/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## Changelog

### v1.0.0

- In the Book component, the circulation links (e.g. Borrow, Download) are no longer rendered by default. There is now a showCirculationLinks prop that must be set to true to render the circulation links.
- The Collection component now has a showCirculationLinks prop that controls the rendering of circulation links on the Books in the Collection.

### v0.6.4

- Initial Palace release.
Expand Down
5 changes: 4 additions & 1 deletion packages/web-opds-client/src/components/Book.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface BookProps {
updateBook: (url: string | undefined) => Promise<BookData>;
isSignedIn?: boolean;
epubReaderUrlTemplate?: (epubUrl: string) => string;
showCirculationLinks?: boolean;
}

/** Displays a single book for use in a lane, list, or grid view. */
Expand Down Expand Up @@ -89,7 +90,9 @@ export default class Book<P extends BookProps> extends React.Component<P, {}> {
</div>
)}
</div>
<div className="circulation-links">{this.circulationLinks()}</div>
{this.props.showCirculationLinks && (
<div className="circulation-links">{this.circulationLinks()}</div>
)}
</div>
<div className="details">
<div className="fields" lang="en">
Expand Down
2 changes: 2 additions & 0 deletions packages/web-opds-client/src/components/Collection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface CollectionProps extends React.HTMLProps<Collection> {
isFetchingCollection?: boolean;
isFetchingBook?: boolean;
isFetchingPage?: boolean;
showCirculationLinks?: boolean;
error?: FetchErrorData;
fetchPage?: (url: string) => Promise<any>;
updateBook: (url: string) => Promise<BookData>;
Expand Down Expand Up @@ -111,6 +112,7 @@ export default class Collection extends React.Component<CollectionProps, {}> {
updateBook={this.props.updateBook}
isSignedIn={this.props.isSignedIn}
epubReaderUrlTemplate={this.props.epubReaderUrlTemplate}
showCirculationLinks={this.props.showCirculationLinks}
/>
</li>
))}
Expand Down
223 changes: 139 additions & 84 deletions packages/web-opds-client/src/components/__tests__/Book-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ describe("Book", () => {
book={book}
updateBook={updateBook}
epubReaderUrlTemplate={epubReaderUrlTemplate}
showCirculationLinks={true}
/>
);
});
Expand Down Expand Up @@ -227,104 +228,158 @@ describe("Book", () => {
expect(moreLink.html()).to.contain("More");
});

it("shows download button for open access urls", () => {
let buttons = wrapper.find(DownloadButton);
expect(buttons.length).to.equal(2);
let epubButton = buttons.at(0);
let mobiButton = buttons.at(1);

expect(epubButton.props().link.url).to.equal("secrets.epub");
expect(epubButton.props().link.type).to.equal("application/epub+zip");
expect(epubButton.props().isPlainLink).to.equal(true);

expect(mobiButton.props().link.url).to.equal("secrets.mobi");
expect(mobiButton.props().link.type).to.equal(
"application/x-mobipocket-ebook"
);
expect(mobiButton.props().isPlainLink).to.equal(true);
});
context("when showCirculationLinks is true", () => {
it("shows download button for open access urls", () => {
let buttons = wrapper.find(DownloadButton);
expect(buttons.length).to.equal(2);
let epubButton = buttons.at(0);
let mobiButton = buttons.at(1);

expect(epubButton.props().link.url).to.equal("secrets.epub");
expect(epubButton.props().link.type).to.equal("application/epub+zip");
expect(epubButton.props().isPlainLink).to.equal(true);

expect(mobiButton.props().link.url).to.equal("secrets.mobi");
expect(mobiButton.props().link.type).to.equal(
"application/x-mobipocket-ebook"
);
expect(mobiButton.props().isPlainLink).to.equal(true);
});

it("shows read button for open access epub urls", () => {
let buttons = wrapper.find(".read-button");
expect(buttons.length).to.equal(1);
expect(buttons.props().href).to.equal("test reader url");
});
it("shows read button for open access epub urls", () => {
let buttons = wrapper.find(".read-button");
expect(buttons.length).to.equal(1);
expect(buttons.props().href).to.equal("test reader url");
});

it("shows borrow/hold button", () => {
let bookCopy = Object.assign({}, book, {
borrowUrl: "borrow url"
it("shows borrow/hold button", () => {
let bookCopy = Object.assign({}, book, {
borrowUrl: "borrow url"
});
let updateBook = stub();
wrapper = shallow(
<Book
book={bookCopy}
updateBook={updateBook}
showCirculationLinks={true}
/>
);

let button = wrapper.find(BorrowButton);
expect(button.children().text()).to.equal("Borrow");
button.props().borrow();
expect(updateBook.callCount).to.equal(1);
expect(updateBook.args[0][0]).to.equal(bookCopy.borrowUrl);
wrapper.setProps({
book: Object.assign({}, bookCopy, {
copies: { total: 2, available: 0 }
})
});
button = wrapper.find(BorrowButton);
expect(button.children().text()).to.equal("Reserve");
});
let updateBook = stub();
wrapper = shallow(<Book book={bookCopy} updateBook={updateBook} />);

let button = wrapper.find(BorrowButton);
expect(button.children().text()).to.equal("Borrow");
button.props().borrow();
expect(updateBook.callCount).to.equal(1);
expect(updateBook.args[0][0]).to.equal(bookCopy.borrowUrl);
wrapper.setProps({
book: Object.assign({}, bookCopy, {
copies: { total: 2, available: 0 }
})
it("shows fulfill button if there's no download button", () => {
let link = {
url: "fulfillment url",
type: "application/vnd.adobe.adept+xml"
};
let bookCopy = Object.assign({}, book, {
openAccessLinks: [],
fulfillmentLinks: [link]
});
wrapper = shallow(
<Book
book={bookCopy}
updateBook={stub()}
isSignedIn={false}
showCirculationLinks={true}
/>
);
let button = wrapper.find(DownloadButton);
expect(button.props().link.url).to.equal(link.url);
expect(button.props().title).to.equal(bookCopy.title);
expect(button.props().link.type).to.equal(link.type);
expect(button.props().isPlainLink).to.equal(true);
});
button = wrapper.find(BorrowButton);
expect(button.children().text()).to.equal("Reserve");
});

it("shows fulfill button if there's no download button", () => {
let link = {
url: "fulfillment url",
type: "application/vnd.adobe.adept+xml"
};
let bookCopy = Object.assign({}, book, {
openAccessLinks: [],
fulfillmentLinks: [link]
it("shows 'borrowed'", () => {
let link = {
url: "fulfillment url",
type: "application/vnd.adobe.adept+xml"
};
let bookCopy = Object.assign({}, book, {
openAccessLinks: [],
fulfillmentLinks: [link]
});
wrapper = shallow(
<Book
book={bookCopy}
updateBook={stub()}
showCirculationLinks={true}
/>
);
let button = wrapper.find(BorrowButton);
expect(button.props().children).to.equal("Borrowed");
expect(button.props().disabled).to.equal(true);
});
wrapper = shallow(
<Book book={bookCopy} updateBook={stub()} isSignedIn={false} />
);
let button = wrapper.find(DownloadButton);
expect(button.props().link.url).to.equal(link.url);
expect(button.props().title).to.equal(bookCopy.title);
expect(button.props().link.type).to.equal(link.type);
expect(button.props().isPlainLink).to.equal(true);
});

it("shows 'borrowed'", () => {
let link = {
url: "fulfillment url",
type: "application/vnd.adobe.adept+xml"
};
let bookCopy = Object.assign({}, book, {
openAccessLinks: [],
fulfillmentLinks: [link]
it("shows 'reserved'", () => {
let bookCopy = Object.assign({}, book, {
openAccessLinks: [],
availability: { status: "reserved" }
});
wrapper = shallow(
<Book
book={bookCopy}
updateBook={stub()}
showCirculationLinks={true}
/>
);
let button = wrapper.find("button");
expect(button.text()).to.equal("Reserved");
expect(button.props().className).to.contain("disabled");
});
wrapper = shallow(<Book book={bookCopy} updateBook={stub()} />);
let button = wrapper.find(BorrowButton);
expect(button.props().children).to.equal("Borrowed");
expect(button.props().disabled).to.equal(true);
});

it("shows 'reserved'", () => {
let bookCopy = Object.assign({}, book, {
openAccessLinks: [],
availability: { status: "reserved" }
it("shows 'borrow' when a reserved book becomes available", () => {
let bookCopy = Object.assign({}, book, {
openAccessLinks: [],
availability: { status: "ready" }
});
wrapper = shallow(
<Book
book={bookCopy}
updateBook={stub()}
showCirculationLinks={true}
/>
);
let button = wrapper.find(BorrowButton);
expect(button.length).to.equal(1);
expect(button.html()).to.contain("Borrow");
});
wrapper = shallow(<Book book={bookCopy} updateBook={stub()} />);
let button = wrapper.find("button");
expect(button.text()).to.equal("Reserved");
expect(button.props().className).to.contain("disabled");
});

it("shows 'borrow' when a reserved book becomes available", () => {
let bookCopy = Object.assign({}, book, {
openAccessLinks: [],
availability: { status: "ready" }
context("when showCirculationLinks is false", () => {
it("does not show borrow/hold button", () => {
const bookCopy = {
...book,
borrowUrl: "borrow url"
};

const updateBook = stub();

wrapper = shallow(
<Book
book={bookCopy}
updateBook={updateBook}
showCirculationLinks={false}
/>
);

const button = wrapper.find(BorrowButton);

expect(button.length).to.equal(0);
});
wrapper = shallow(<Book book={bookCopy} updateBook={stub()} />);
let button = wrapper.find(BorrowButton);
expect(button.length).to.equal(1);
expect(button.html()).to.contain("Borrow");
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ describe("Collection", () => {
fulfillBook={fulfillBook}
indirectFulfillBook={indirectFulfillBook}
setPreference={setPreference}
showCirculationLinks={false}
/>,
{
context,
Expand Down Expand Up @@ -131,6 +132,14 @@ describe("Collection", () => {
expect(uniqueCollectionUrls).to.deep.equal([collectionData.url]);
});

it("passes showCirculationLinks prop to books", () => {
const books = wrapper.find(Book);

books.forEach(book =>
expect(book.props().showCirculationLinks).to.equal(false)
);
});

it("shows grid or list view", () => {
let context = mockRouterContext();
wrapper = mount(
Expand Down

0 comments on commit 0220aa0

Please sign in to comment.