Skip to content

Commit ac59c73

Browse files
authored
refactor poll controller to component (#1091)
* refactor poll controller to component * test expectation date handling in acceptance test only * outlet must be declared in route templates only
1 parent d7cc949 commit ac59c73

File tree

6 files changed

+206
-194
lines changed

6 files changed

+206
-194
lines changed

app/components/poll.hbs

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
{{page-title @poll.title}}
2+
3+
<div id="poll">
4+
<div class="row">
5+
<div class="col-sm-6 col-lg-5">
6+
<div class="box meta-data">
7+
<h2 class="title">{{@poll.title}}</h2>
8+
<p class="description">{{@poll.description}}</p>
9+
<p class="dates">
10+
<span class="creationDate">
11+
{{t
12+
"poll.created-date"
13+
date=(format-date
14+
@poll.creationDate dateStyle="full" timeStyle="short"
15+
)
16+
}}
17+
</span>
18+
{{#if @poll.expirationDate}}
19+
<br />
20+
<span class="expirationDate">
21+
{{t
22+
"poll.expiration-date"
23+
date=(format-date
24+
@poll.expirationDate dateStyle="full" timeStyle="short"
25+
)
26+
}}
27+
</span>
28+
{{/if}}
29+
</p>
30+
</div>
31+
</div>
32+
<div class="col-sm-6 col-lg-6 offset-lg-1">
33+
<SharePollUrl />
34+
</div>
35+
</div>
36+
37+
{{#if this.showExpirationWarning}}
38+
<div class="row">
39+
<div class="col-xs-12">
40+
<BsAlert @type="warning" class="expiration-warning">
41+
{{t
42+
"poll.expiration-date-warning"
43+
timeToNow=(format-date-relative @poll.expirationDate)
44+
}}
45+
</BsAlert>
46+
</div>
47+
</div>
48+
{{/if}}
49+
50+
<div class="box">
51+
<ul class="nav nav-tabs" role="tablist">
52+
<li class="nav-item">
53+
<LinkTo
54+
@route="poll.participation"
55+
@model={{@poll.id}}
56+
class="nav-link"
57+
data-test-link="participation"
58+
>
59+
{{t "poll.tab-title.participation"}}
60+
</LinkTo>
61+
</li>
62+
<li class="nav-item">
63+
<LinkTo
64+
@route="poll.evaluation"
65+
@model={{@poll.id}}
66+
class="nav-link"
67+
data-test-link="evaluation"
68+
>
69+
{{t "poll.tab-title.evaluation"}}
70+
</LinkTo>
71+
</li>
72+
</ul>
73+
74+
<div class="tab-content">
75+
<div role="tabpanel" class="tab-pane active">
76+
{{yield}}
77+
</div>
78+
</div>
79+
</div>
80+
</div>
81+
82+
<BsModal
83+
@title={{t "poll.modal.timezoneDiffers.title"}}
84+
@open={{this.pollSettings.mustChooseTimeZone}}
85+
@footer={{false}}
86+
@closeButton={{false}}
87+
@keyboard={{false}}
88+
@autoClose={{false}}
89+
data-test-modal="choose-timezone"
90+
as |modal|
91+
>
92+
<modal.body>
93+
<p>
94+
{{t "poll.modal.timezoneDiffers.body"}}
95+
</p>
96+
</modal.body>
97+
<modal.footer>
98+
<BsButton
99+
@onClick={{this.useLocalTimezone}}
100+
data-test-button="use-local-timezone"
101+
>
102+
{{t "poll.modal.timezoneDiffers.button.useLocalTimezone"}}
103+
</BsButton>
104+
<BsButton
105+
@onClick={{this.usePollTimezone}}
106+
data-test-button="use-poll-timezone"
107+
>
108+
{{t "poll.modal.timezoneDiffers.button.usePollTimezone"}}
109+
</BsButton>
110+
</modal.footer>
111+
</BsModal>

app/components/poll.ts

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import Component from '@glimmer/component';
2+
import { action } from '@ember/object';
3+
import { service } from '@ember/service';
4+
import { DateTime } from 'luxon';
5+
import type RouterService from '@ember/routing/router-service';
6+
import type { PollRouteModel } from 'croodle/routes/poll';
7+
import type PollSettingsService from 'croodle/services/poll-settings';
8+
import type IntlService from 'ember-intl/services/intl';
9+
10+
export interface PollSignature {
11+
// The arguments accepted by the component
12+
Args: {
13+
poll: PollRouteModel;
14+
};
15+
// Any blocks yielded by the component
16+
Blocks: {
17+
default: [];
18+
};
19+
// The element to which `...attributes` is applied in the component template
20+
Element: null;
21+
}
22+
23+
export default class Poll extends Component<PollSignature> {
24+
@service declare intl: IntlService;
25+
@service('poll-settings') declare pollSettingsService: PollSettingsService;
26+
@service declare router: RouterService;
27+
28+
get pollSettings() {
29+
const { poll } = this.args;
30+
31+
return this.pollSettingsService.getSettings(poll);
32+
}
33+
34+
get showExpirationWarning() {
35+
const { poll } = this.args;
36+
const { expirationDate } = poll;
37+
38+
if (!expirationDate) {
39+
return false;
40+
}
41+
return (
42+
DateTime.local().plus({ weeks: 2 }) >= DateTime.fromISO(expirationDate)
43+
);
44+
}
45+
46+
@action
47+
useLocalTimezone() {
48+
this.pollSettings.shouldUseLocalTimeZone = true;
49+
}
50+
51+
@action
52+
usePollTimezone() {
53+
this.pollSettings.shouldUseLocalTimeZone = false;
54+
}
55+
}
56+
57+
declare module '@glint/environment-ember-loose/registry' {
58+
export default interface Registry {
59+
Poll: typeof Poll;
60+
}
61+
}

app/controllers/poll.ts

-37
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,9 @@
11
import Controller from '@ember/controller';
2-
import { inject as service } from '@ember/service';
3-
import { isEmpty } from '@ember/utils';
4-
import { action } from '@ember/object';
5-
import { DateTime } from 'luxon';
6-
import type IntlService from 'ember-intl/services/intl';
7-
import type RouterService from '@ember/routing/router-service';
82
import type { PollRouteModel } from 'croodle/routes/poll';
9-
import type PollSettingsService from 'croodle/services/poll-settings';
103

114
export default class PollController extends Controller {
12-
@service declare intl: IntlService;
13-
@service('poll-settings') declare pollSettingsService: PollSettingsService;
14-
@service declare router: RouterService;
15-
165
declare model: PollRouteModel;
176

187
queryParams = ['encryptionKey'];
198
encryptionKey = '';
20-
21-
get pollSettings() {
22-
return this.pollSettingsService.getSettings(this.model);
23-
}
24-
25-
get showExpirationWarning() {
26-
const { model: poll } = this;
27-
const { expirationDate } = poll;
28-
29-
if (isEmpty(expirationDate)) {
30-
return false;
31-
}
32-
return (
33-
DateTime.local().plus({ weeks: 2 }) >= DateTime.fromISO(expirationDate)
34-
);
35-
}
36-
37-
@action
38-
useLocalTimezone() {
39-
this.pollSettings.shouldUseLocalTimeZone = true;
40-
}
41-
42-
@action
43-
usePollTimezone() {
44-
this.pollSettings.shouldUseLocalTimeZone = false;
45-
}
469
}

app/templates/poll.hbs

+3-113
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,3 @@
1-
{{#let @model as |poll|}}
2-
{{page-title poll.title}}
3-
4-
<div id="poll">
5-
<div class="row">
6-
<div class="col-sm-6 col-lg-5">
7-
<div class="box meta-data">
8-
<h2 class="title">{{poll.title}}</h2>
9-
<p class="description">{{poll.description}}</p>
10-
<p class="dates">
11-
<span class="creationDate">
12-
{{t
13-
"poll.created-date"
14-
date=(format-date
15-
poll.creationDate dateStyle="full" timeStyle="short"
16-
)
17-
}}
18-
</span>
19-
{{#if poll.expirationDate}}
20-
<br />
21-
<span class="expirationDate">
22-
{{t
23-
"poll.expiration-date"
24-
date=(format-date
25-
poll.expirationDate dateStyle="full" timeStyle="short"
26-
)
27-
}}
28-
</span>
29-
{{/if}}
30-
</p>
31-
</div>
32-
</div>
33-
<div class="col-sm-6 col-lg-6 offset-lg-1">
34-
<SharePollUrl />
35-
</div>
36-
</div>
37-
38-
{{#if this.showExpirationWarning}}
39-
<div class="row">
40-
<div class="col-xs-12">
41-
<BsAlert @type="warning" class="expiration-warning">
42-
{{t
43-
"poll.expiration-date-warning"
44-
timeToNow=(format-date-relative poll.expirationDate)
45-
}}
46-
</BsAlert>
47-
</div>
48-
</div>
49-
{{/if}}
50-
51-
<div class="box">
52-
<ul class="nav nav-tabs" role="tablist">
53-
<li class="nav-item">
54-
<LinkTo
55-
@route="poll.participation"
56-
@model={{poll.id}}
57-
class="nav-link"
58-
data-test-link="participation"
59-
>
60-
{{t "poll.tab-title.participation"}}
61-
</LinkTo>
62-
</li>
63-
<li class="nav-item">
64-
<LinkTo
65-
@route="poll.evaluation"
66-
@model={{poll.id}}
67-
class="nav-link"
68-
data-test-link="evaluation"
69-
>
70-
{{t "poll.tab-title.evaluation"}}
71-
</LinkTo>
72-
</li>
73-
</ul>
74-
75-
<div class="tab-content">
76-
<div role="tabpanel" class="tab-pane active">
77-
{{outlet}}
78-
</div>
79-
</div>
80-
</div>
81-
</div>
82-
{{/let}}
83-
84-
<BsModal
85-
@title={{t "poll.modal.timezoneDiffers.title"}}
86-
@open={{this.pollSettings.mustChooseTimeZone}}
87-
@footer={{false}}
88-
@closeButton={{false}}
89-
@keyboard={{false}}
90-
@autoClose={{false}}
91-
data-test-modal="choose-timezone"
92-
as |modal|
93-
>
94-
<modal.body>
95-
<p>
96-
{{t "poll.modal.timezoneDiffers.body"}}
97-
</p>
98-
</modal.body>
99-
<modal.footer>
100-
<BsButton
101-
@onClick={{this.useLocalTimezone}}
102-
data-test-button="use-local-timezone"
103-
>
104-
{{t "poll.modal.timezoneDiffers.button.useLocalTimezone"}}
105-
</BsButton>
106-
<BsButton
107-
@onClick={{this.usePollTimezone}}
108-
data-test-button="use-poll-timezone"
109-
>
110-
{{t "poll.modal.timezoneDiffers.button.usePollTimezone"}}
111-
</BsButton>
112-
</modal.footer>
113-
</BsModal>
1+
<Poll @poll={{@model}}>
2+
{{outlet}}
3+
</Poll>

tests/acceptance/view-poll-test.js

+31-7
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,39 @@ module('Acceptance | view poll', function (hooks) {
3737
.isVisible('shows success message that URL has been copied');
3838
});
3939

40-
test('shows a warning if poll is about to be expired', async function (assert) {
41-
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
42-
let poll = this.server.create('poll', {
43-
encryptionKey,
44-
expirationDate: DateTime.local().plus({ weeks: 1 }).toISO(),
40+
module('expiration warning', function () {
41+
test('shows a warning if poll expires in the next weeks', async function (assert) {
42+
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
43+
let poll = this.server.create('poll', {
44+
encryptionKey,
45+
expirationDate: DateTime.local().plus({ weeks: 1 }).toISO(),
46+
});
47+
48+
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
49+
assert.ok(pageParticipation.showsExpirationWarning);
4550
});
4651

47-
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
48-
assert.ok(pageParticipation.showsExpirationWarning);
52+
test('does not show a warning if expiration date is more than two weeks in the future', async function (assert) {
53+
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
54+
let poll = this.server.create('poll', {
55+
encryptionKey,
56+
expirationDate: DateTime.local().plus({ weeks: 3 }).toISO(),
57+
});
58+
59+
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
60+
assert.notOk(pageParticipation.showsExpirationWarning);
61+
});
62+
63+
test('does not show a warning if expiration date is not set', async function (assert) {
64+
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
65+
let poll = this.server.create('poll', {
66+
encryptionKey,
67+
expirationDate: null,
68+
});
69+
70+
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
71+
assert.notOk(pageParticipation.showsExpirationWarning);
72+
});
4973
});
5074

5175
test('view a poll with dates', async function (assert) {

0 commit comments

Comments
 (0)