Skip to content

Commit 8db8a60

Browse files
committed
Add confirmation when disassociating collection libraries (PP-2408)
1 parent bbe2c23 commit 8db8a60

File tree

2 files changed

+94
-6
lines changed

2 files changed

+94
-6
lines changed

src/components/Collections.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import {
1212
CollectionsData,
1313
CollectionData,
1414
LibraryData,
15+
LibraryWithSettingsData,
1516
LibraryRegistrationsData,
16-
ServiceData,
1717
} from "../interfaces";
1818
import ServiceWithRegistrationsEditForm from "./ServiceWithRegistrationsEditForm";
1919
import TrashIcon from "./icons/TrashIcon";
@@ -36,7 +36,24 @@ export interface CollectionsProps
3636

3737
export class CollectionEditForm extends ServiceWithRegistrationsEditForm<
3838
CollectionsData
39-
> {}
39+
> {
40+
/**
41+
* Override to display a confirmation message before removing a library
42+
* association. We display the confirmation and, if successful, call the
43+
* superclass method to actually remove the library from our state.
44+
* @param library
45+
*/
46+
removeLibrary(library: LibraryWithSettingsData) {
47+
const libraryData = this.getLibrary(library.short_name);
48+
const libraryName = libraryData ? libraryData.name : library.short_name;
49+
const confirmationMessage =
50+
`Disassociating library "${libraryName}" from this collection will ` +
51+
"remove all loans and holds for its patrons. Do you wish to continue?";
52+
if (window.confirm(confirmationMessage)) {
53+
super.removeLibrary(library);
54+
}
55+
}
56+
}
4057

4158
/**
4259
* Right panel for collections on the system configuration page.

src/components/__tests__/Collections-test.tsx

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { expect } from "chai";
2+
import * as sinon from "sinon";
23
import { stub } from "sinon";
34
import * as React from "react";
4-
import { shallow, mount } from "enzyme";
5+
import { ReactWrapper, mount } from "enzyme";
56
import * as PropTypes from "prop-types";
6-
7+
import { ProtocolData } from "../../interfaces";
78
import Admin from "../../models/Admin";
8-
import { Collections } from "../Collections";
9+
import { Collections, CollectionEditForm } from "../Collections";
10+
import buildStore from "../../store";
911

1012
const collections = [
1113
{
@@ -27,7 +29,7 @@ const collections = [
2729
name: "RBDigital",
2830
},
2931
];
30-
import buildStore from "../../store";
32+
const protocols: ProtocolData[] = [{ name: "test protocol", settings: [] }];
3133

3234
describe("Collections", () => {
3335
let wrapper;
@@ -127,5 +129,74 @@ describe("Collections", () => {
127129
expect(deletedCollection.find("a.edit-item").length).to.equal(0);
128130
expect(deletedCollection.find("button.delete-item").length).to.equal(0);
129131
});
132+
133+
describe("confirm before disassociating libraries", () => {
134+
let wrapper: ReactWrapper;
135+
let confirmStub: sinon.SinonStub;
136+
137+
const initialLibraries = [
138+
{ short_name: "palace", name: "Palace" },
139+
{ short_name: "another-library", name: "Another Library" },
140+
] as const;
141+
const collection = {
142+
id: 7,
143+
name: "An OPDS Collection",
144+
protocol: "OPDS Import",
145+
146+
libraries: [...initialLibraries],
147+
};
148+
149+
beforeEach(() => {
150+
confirmStub = sinon.stub(window, "confirm");
151+
152+
wrapper = mount(
153+
<CollectionEditForm
154+
disabled={false}
155+
data={{
156+
collections: [collection],
157+
protocols: [],
158+
allLibraries: [...initialLibraries],
159+
}}
160+
item={collection}
161+
urlBase="/collections"
162+
listDataKey="collections"
163+
/>
164+
);
165+
});
166+
167+
afterEach(() => {
168+
confirmStub.restore();
169+
});
170+
171+
it("calls window.confirm when delete button is clicked", () => {
172+
confirmStub.returns(false);
173+
174+
// The confirmation dialog should not be invoked before we click.
175+
expect(confirmStub.calledOnce).to.be.false;
176+
177+
wrapper.find("button.remove-btn").at(0).simulate("click");
178+
expect(confirmStub.calledOnce).to.be.true;
179+
expect(confirmStub.firstCall.args.length).to.equal(1);
180+
const message: string = confirmStub.firstCall.args[0];
181+
expect(message).to.equal(
182+
'Disassociating library "Palace" from this collection will ' +
183+
"remove all loans and holds for its patrons. Do you wish to continue?"
184+
);
185+
});
186+
187+
it("does not delete library if confirmation is canceled", () => {
188+
confirmStub.returns(false);
189+
wrapper.find("button.remove-btn").at(0).simulate("click");
190+
// We didn't delete, so we should still have the originals.
191+
expect(wrapper.state("libraries")).to.deep.equal(initialLibraries);
192+
});
193+
194+
it("deletes library if confirmation is accepted", () => {
195+
confirmStub.returns(true);
196+
wrapper.find("button.remove-btn").at(0).simulate("click");
197+
// We deleted the first library, so it should be gone from the state.
198+
expect(wrapper.state("libraries")).to.deep.equal([initialLibraries[1]]);
199+
});
200+
});
130201
});
131202
});

0 commit comments

Comments
 (0)