Skip to content

Commit 2093aa0

Browse files
authored
tenants rights groups modal a11y fixes (#167)
* made modal dialog template a hbs partial * moved modal dialog partial to top of template * added separate ModalDialog instance for tr groups modal * updated hbs partial & styles for tr groups modal * cleaned up TenantsRightsModal component * added code comment to modal dialog template * fixed failing tests for TenantsRightsModal * updated doc string on TenantsRightsModal * give ModalDialog a max-height * updated failing test * increased padding in modal body * rm old tr-modal div from index.html * made tr-modal trigger an html button * set max-width on .button class * renamed modal trigger class names * renamed component TenantsRightsModal to TenantsRightsGroups * renamed scss partial for tr modal content
1 parent 06ec1cb commit 2093aa0

File tree

15 files changed

+223
-345
lines changed

15 files changed

+223
-345
lines changed

app/public/index.html

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@
2222
<!-- handlebars templates are appended to "#wrapper" -->
2323
<div id="wrapper"></div>
2424

25-
<!-- modal for listing local tenants rights groups -->
26-
<div id="open-modal" class="tr-modal"></div>
27-
2825
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-57236362-1"></script>
2926
<script>
3027
window.dataLayer = window.dataLayer || [];

app/setupJest.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ function registerHbsPartials() {
4343
const partials = [
4444
"navigation",
4545
"navigation_info",
46+
"modal_dialog",
4647
"language_toggle",
4748
"progress_indicator",
4849
"address_search_form",
Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ Handlebars.registerPartial("trGroups", template);
1010
export const ERROR_MISSING_COORDS =
1111
"Missing coordinates from address search result";
1212

13-
export class TenantsRightsModal extends Component {
13+
/** Handles
14+
* - If tenants rights groups exists, this component handles rendering the tenants rights group content in the corresponding dialog.modal--tenants-rights
15+
* - toggling whether slide 8 says there are tenants rights groups in the search result area
16+
* NOTE: modal dialog functionality handled by ModalDialog component
17+
*/
18+
export class TenantsRightsGroups extends Component {
1419
constructor(props) {
1520
super(props);
1621
}
@@ -25,7 +30,6 @@ export class TenantsRightsModal extends Component {
2530
this.handleSearchResultChange = this.handleSearchResultChange.bind(this);
2631
this.renderModalContents = this.renderModalContents.bind(this);
2732
this.getSearchCoords = this.getSearchCoords.bind(this);
28-
this.handleKeyDown = this.handleKeyDown.bind(this);
2933

3034
this.unsubscribeSearchResult = observeStore(
3135
this.store,
@@ -38,23 +42,6 @@ export class TenantsRightsModal extends Component {
3842
(state) => state.tenantsRights,
3943
this.handleTenantsRightsChange
4044
);
41-
42-
this.bindEvents();
43-
this.maybeClearWindowHash();
44-
}
45-
46-
bindEvents() {
47-
document.addEventListener("keydown", this.handleKeyDown);
48-
}
49-
50-
removeEvents() {
51-
document.removeEventListener("keydown", this.handleKeyDown);
52-
}
53-
54-
handleKeyDown(event) {
55-
if (event.code === "Escape") {
56-
this.maybeClearWindowHash();
57-
}
5845
}
5946

6047
handleSearchResultChange(result) {
@@ -100,16 +87,9 @@ export class TenantsRightsModal extends Component {
10087
throw new Error(ERROR_MISSING_COORDS);
10188
}
10289

103-
maybeClearWindowHash() {
104-
if (/open-modal/.exec(window.location.hash)) {
105-
window.location.hash = "";
106-
}
107-
}
108-
10990
cleanUp() {
11091
this.unsubscribeTenantsRights();
11192
this.unsubscribeSearchResult();
112-
this.removeEvents();
11393
this.element = null;
11494
}
11595
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import {
2+
TenantsRightsGroups,
3+
ERROR_MISSING_COORDS,
4+
} from "./tenantsRightsGroups";
5+
import { store } from "../store";
6+
7+
jest.mock("../store");
8+
9+
describe("TenantsRightsGroups", () => {
10+
let element;
11+
let tenantsRightsGroups;
12+
let spyRenderModalContents;
13+
14+
beforeAll(() => {
15+
setDocumentHtml(getMainHtml()); // eslint-disable-line no-undef
16+
element = document.querySelector(
17+
"dialog.modal--tenants-rights .modal--content"
18+
);
19+
spyRenderModalContents = jest.spyOn(
20+
TenantsRightsGroups.prototype,
21+
"renderModalContents"
22+
);
23+
});
24+
25+
beforeEach(() => {
26+
tenantsRightsGroups = new TenantsRightsGroups({ store, element });
27+
});
28+
29+
afterEach(() => {
30+
jest.clearAllMocks();
31+
});
32+
33+
test("The component's HTML exists", () => {
34+
expect(element).not.toBeNull();
35+
});
36+
37+
test("The consumer should be able to call new on TenantsRightsGroups", () => {
38+
expect(tenantsRightsGroups).toBeTruthy();
39+
});
40+
41+
test("getSearchCoords", () => {
42+
const feature = {
43+
geometry: {
44+
coordinates: [-79, 41],
45+
},
46+
};
47+
const result = tenantsRightsGroups.getSearchCoords(feature);
48+
expect(result).toEqual({ lon: -79, lat: 41 });
49+
expect(() =>
50+
tenantsRightsGroups.getSearchCoords({ geometry: { coordinates: [] } })
51+
).toThrow(new Error(ERROR_MISSING_COORDS));
52+
});
53+
54+
test("renderModalContents", () => {
55+
const data = [{}, {}];
56+
tenantsRightsGroups.renderModalContents(data);
57+
expect(element.innerHTML).toBeTruthy();
58+
});
59+
60+
test("handleSearchResultChange", () => {
61+
const data = {
62+
features: [
63+
{
64+
geometry: {
65+
coordinates: [0, 0],
66+
},
67+
},
68+
],
69+
};
70+
tenantsRightsGroups.handleSearchResultChange(data);
71+
expect(store.dispatch).toHaveBeenCalledWith(expect.any(Function));
72+
});
73+
74+
test("handleTenantsRightsChange with results", () => {
75+
const params = {
76+
results: { rows: [{}, {}] },
77+
status: "idle",
78+
};
79+
tenantsRightsGroups.handleTenantsRightsChange(params);
80+
expect(tenantsRightsGroups.containerYes.classList.contains("hidden")).toBe(
81+
false
82+
);
83+
expect(tenantsRightsGroups.containerNo.classList.contains("hidden")).toBe(
84+
true
85+
);
86+
expect(spyRenderModalContents).toHaveBeenCalledWith([{}, {}]);
87+
});
88+
89+
test("handleTenantsRightsChange without results", () => {
90+
const params = {
91+
results: { rows: [] },
92+
status: "idle",
93+
};
94+
tenantsRightsGroups.handleTenantsRightsChange(params);
95+
expect(tenantsRightsGroups.containerYes.classList.contains("hidden")).toBe(
96+
true
97+
);
98+
expect(tenantsRightsGroups.containerNo.classList.contains("hidden")).toBe(
99+
false
100+
);
101+
expect(spyRenderModalContents).not.toHaveBeenCalled();
102+
});
103+
});

app/src/components/tenantsRightsModal.spec.js

Lines changed: 0 additions & 149 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{{!-- template for the ModalDialog component. Only meant to be a shell, content must be provided separately --}}
2+
<dialog class="modal {{className}}">
3+
<div class="modal--body">
4+
<button class="button modal--close" aria-label="close">
5+
<svg
6+
viewBox="0 0 24 24"
7+
xmlns="http://www.w3.org/2000/svg"
8+
fill="none"
9+
stroke-width="4"
10+
stroke-linecap="round"
11+
aria-hidden="true"
12+
>
13+
<line x1="2" y1="2" x2="22" y2="22" stroke="currentColor" />
14+
<line x1="2" y1="22" x2="22" y2="2" stroke="currentColor" />
15+
</svg>
16+
</button>
17+
<div class="modal--content">
18+
{{> @partial-block }}
19+
</div>
20+
</div>
21+
</dialog>

0 commit comments

Comments
 (0)