Skip to content

Commit 4c36fb2

Browse files
authored
refactor from controller injection to service (#1051)
1 parent 4f598a9 commit 4c36fb2

File tree

8 files changed

+225
-43
lines changed

8 files changed

+225
-43
lines changed

app/controllers/poll.ts

+8-30
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
import Controller from '@ember/controller';
22
import { inject as service } from '@ember/service';
3-
import { isPresent, isEmpty } from '@ember/utils';
3+
import { isEmpty } from '@ember/utils';
44
import { action } from '@ember/object';
55
import { DateTime } from 'luxon';
6-
import { tracked } from '@glimmer/tracking';
76
import type IntlService from 'ember-intl/services/intl';
87
import type RouterService from '@ember/routing/router-service';
98
import type { PollRouteModel } from 'croodle/routes/poll';
9+
import type PollSettingsService from 'croodle/services/poll-settings';
1010

1111
export default class PollController extends Controller {
1212
@service declare intl: IntlService;
13+
@service('poll-settings') declare pollSettingsService: PollSettingsService;
1314
@service declare router: RouterService;
1415

1516
declare model: PollRouteModel;
1617

1718
queryParams = ['encryptionKey'];
1819
encryptionKey = '';
1920

20-
@tracked timezoneChoosen = false;
21-
@tracked shouldUseLocalTimezone = false;
21+
get pollSettings() {
22+
return this.pollSettingsService.getSettings(this.model);
23+
}
2224

2325
get showExpirationWarning() {
2426
const { model: poll } = this;
@@ -32,37 +34,13 @@ export default class PollController extends Controller {
3234
);
3335
}
3436

35-
/*
36-
* return true if current timezone differs from timezone poll got created with
37-
*/
38-
get timezoneDiffers() {
39-
const { model: poll } = this;
40-
const { timezone: pollTimezone } = poll;
41-
42-
return (
43-
isPresent(pollTimezone) &&
44-
Intl.DateTimeFormat().resolvedOptions().timeZone !== pollTimezone
45-
);
46-
}
47-
48-
get mustChooseTimezone() {
49-
return this.timezoneDiffers && !this.timezoneChoosen;
50-
}
51-
52-
get timezone() {
53-
const { model: poll, shouldUseLocalTimezone } = this;
54-
55-
return shouldUseLocalTimezone || !poll.timezone ? undefined : poll.timezone;
56-
}
57-
5837
@action
5938
useLocalTimezone() {
60-
this.shouldUseLocalTimezone = true;
61-
this.timezoneChoosen = true;
39+
this.pollSettings.shouldUseLocalTimeZone = true;
6240
}
6341

6442
@action
6543
usePollTimezone() {
66-
this.timezoneChoosen = true;
44+
this.pollSettings.shouldUseLocalTimeZone = false;
6745
}
6846
}

app/controllers/poll/evaluation.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import Controller, { inject as controller } from '@ember/controller';
1+
import Controller from '@ember/controller';
22
import { inject as service } from '@ember/service';
33
import type IntlService from 'ember-intl/services/intl';
4-
import type PollController from '../poll';
54
import type { PollEvaluationRouteModel } from 'croodle/routes/poll/evaluation';
5+
import type PollSettingsService from 'croodle/services/poll-settings';
66

77
export default class PollEvaluationController extends Controller {
88
@service declare intl: IntlService;
9-
10-
@controller('poll') declare pollController: PollController;
9+
@service('poll-settings') declare pollSettingsService: PollSettingsService;
1110

1211
declare model: PollEvaluationRouteModel;
1312

@@ -18,4 +17,8 @@ export default class PollEvaluationController extends Controller {
1817

1918
return hasUsers && !isFreeText;
2019
}
20+
21+
get pollSettings() {
22+
return this.pollSettingsService.getSettings(this.model);
23+
}
2124
}

app/controllers/poll/participation.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import Controller, { inject as controller } from '@ember/controller';
1+
import Controller from '@ember/controller';
22
import User from '../../models/user';
33
import { inject as service } from '@ember/service';
44
import { action } from '@ember/object';
55
import { tracked } from '@glimmer/tracking';
66
import type RouterService from '@ember/routing/router-service';
7-
import type PollController from '../poll';
87
import type { PollParticipationRouteModel } from 'croodle/routes/poll/participation';
98
import type Poll from 'croodle/models/poll';
109
import type { SelectionInput } from 'croodle/models/selection';
10+
import type PollSettingsService from 'croodle/services/poll-settings';
1111

1212
export default class PollParticipationController extends Controller {
13+
@service('poll-settings') declare pollSettingsService: PollSettingsService;
1314
@service declare router: RouterService;
1415

15-
@controller('poll') declare pollController: PollController;
16-
1716
declare model: PollParticipationRouteModel;
1817

1918
@tracked name = '';
@@ -25,6 +24,10 @@ export default class PollParticipationController extends Controller {
2524
selections: SelectionInput[];
2625
} | null = null;
2726

27+
get pollSettings() {
28+
return this.pollSettingsService.getSettings(this.model.poll);
29+
}
30+
2831
@action
2932
async submit() {
3033
const { formData, poll } = this.model;

app/services/poll-settings.ts

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { tracked } from '@glimmer/tracking';
2+
import Service from '@ember/service';
3+
import type Poll from 'croodle/models/poll';
4+
5+
class PollSettings {
6+
#poll: Poll;
7+
8+
// time zone the user has chosen for displaying the poll in
9+
@tracked
10+
shouldUseLocalTimeZone: boolean | null = null;
11+
12+
get mustChooseTimeZone(): boolean {
13+
return (
14+
this.#usersTimeZoneAndPollsTimeZoneDiffers &&
15+
this.shouldUseLocalTimeZone === null
16+
);
17+
}
18+
19+
// time zone the poll should be shown in
20+
// undefined if user's time zone should be used
21+
get timeZone(): string | undefined {
22+
const { shouldUseLocalTimeZone } = this;
23+
const poll = this.#poll;
24+
25+
if (shouldUseLocalTimeZone || !poll.timezone) {
26+
return undefined;
27+
}
28+
29+
return poll.timezone;
30+
}
31+
32+
get #usersTimeZoneAndPollsTimeZoneDiffers(): boolean {
33+
const { timezone: pollTimeZone } = this.#poll;
34+
35+
return (
36+
!!pollTimeZone &&
37+
Intl.DateTimeFormat().resolvedOptions().timeZone !== pollTimeZone
38+
);
39+
}
40+
41+
constructor(poll: Poll) {
42+
this.#poll = poll;
43+
}
44+
}
45+
46+
export default class PollSettingsService extends Service {
47+
#settings = new WeakMap<Poll, PollSettings>();
48+
49+
getSettings(poll: Poll): PollSettings {
50+
let settings = this.#settings.get(poll);
51+
52+
// initialize settings if needed
53+
if (!settings) {
54+
settings = new PollSettings(poll);
55+
56+
this.#settings.set(poll, settings);
57+
}
58+
59+
return settings;
60+
}
61+
}
62+
63+
// Don't remove this declaration: this is what enables TypeScript to resolve
64+
// this service using `Owner.lookup('service:poll-settings')`, as well
65+
// as to check when you pass the service name as an argument to the decorator,
66+
// like `@service('poll-settings') declare altName: PollSettingsService;`.
67+
declare module '@ember/service' {
68+
interface Registry {
69+
'poll-settings': PollSettingsService;
70+
}
71+
}

app/templates/poll.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383

8484
<BsModal
8585
@title={{t "poll.modal.timezoneDiffers.title"}}
86-
@open={{this.mustChooseTimezone}}
86+
@open={{this.pollSettings.mustChooseTimeZone}}
8787
@footer={{false}}
8888
@closeButton={{false}}
8989
@keyboard={{false}}

app/templates/poll/evaluation.hbs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
{{#if this.isEvaluable}}
33
<PollEvaluationSummary
44
@poll={{poll}}
5-
@timeZone={{this.pollController.timezone}}
5+
@timeZone={{this.pollSettings.timeZone}}
66
/>
77
{{/if}}
88

99
<h3>{{t "poll.evaluation.participantTable"}}</h3>
1010
<PollEvaluationParticipantsTable
1111
@poll={{poll}}
12-
@timeZone={{this.pollController.timezone}}
12+
@timeZone={{this.pollSettings.timeZone}}
1313
/>
1414
{{/let}}

app/templates/poll/participation.hbs

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
@label={{if @model.poll.isFindADate (format-date option.jsDate
4343
dateStyle=(if shouldShowDate "full" undefined)
4444
timeStyle=(if option.hasTime "short" undefined)
45-
timeZone=this.pollController.timezone
45+
timeZone=this.pollSettings.timeZone
4646
)
4747
option.title
4848
}}
@@ -61,7 +61,7 @@
6161
@label={{if @model.poll.isFindADate (format-date option.jsDate
6262
dateStyle=(if shouldShowDate "full" undefined)
6363
timeStyle=(if option.hasTime "short" undefined)
64-
timeZone=this.pollController.timezone
64+
timeZone=this.pollSettings.timeZone
6565
)
6666
option.title
6767
}}
+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { module, test } from 'qunit';
2+
import { setupTest } from 'croodle/tests/helpers';
3+
import Poll from 'croodle/models/poll';
4+
5+
function generateMockPoll(overwrites?: Partial<Poll>): Poll {
6+
return new Poll({
7+
anonymousUser: false,
8+
answerType: 'YesNo',
9+
creationDate: '2024-12-31T00:00:00Z',
10+
description: 'dummy data',
11+
expirationDate: '2025-05-01T00:00:00Z',
12+
forceAnswer: true,
13+
id: 'abc',
14+
options: [{ title: 'foo' }],
15+
pollType: 'FindADate',
16+
timezone: null,
17+
title: 'Dummy',
18+
users: [],
19+
version: '1',
20+
...overwrites,
21+
});
22+
}
23+
24+
module('Unit | Service | poll-settings', function (hooks) {
25+
setupTest(hooks);
26+
27+
module('PollsettingsService', function () {
28+
module('getSettings', function () {
29+
test('returns same settings for the same poll', function (assert) {
30+
const service = this.owner.lookup('service:poll-settings');
31+
const poll = generateMockPoll();
32+
33+
assert.strictEqual(
34+
service.getSettings(poll),
35+
service.getSettings(poll),
36+
);
37+
});
38+
39+
test('returns different settings for different poll', function (assert) {
40+
const service = this.owner.lookup('service:poll-settings');
41+
const pollA = generateMockPoll();
42+
const pollB = generateMockPoll();
43+
44+
assert.notStrictEqual(
45+
service.getSettings(pollA),
46+
service.getSettings(pollB),
47+
);
48+
});
49+
});
50+
});
51+
52+
module('PollSettings', function () {
53+
module('mustChooseTimeZone', function () {
54+
test('false if poll time zone is not set', function (assert) {
55+
const service = this.owner.lookup('service:poll-settings');
56+
const poll = generateMockPoll();
57+
const settings = service.getSettings(poll);
58+
59+
assert.false(settings.mustChooseTimeZone);
60+
});
61+
62+
test("false if poll's time zone equals user's time zone", function (assert) {
63+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
64+
65+
const service = this.owner.lookup('service:poll-settings');
66+
const poll = generateMockPoll({ timezone });
67+
const settings = service.getSettings(poll);
68+
69+
assert.false(settings.mustChooseTimeZone);
70+
});
71+
72+
test("true if poll's time zone differs user's time zone", function (assert) {
73+
const timezone =
74+
Intl.DateTimeFormat().resolvedOptions().timeZone === 'America/Caracas'
75+
? 'Europe/Berlin'
76+
: 'America/Caracas';
77+
78+
const service = this.owner.lookup('service:poll-settings');
79+
const poll = generateMockPoll({ timezone });
80+
const settings = service.getSettings(poll);
81+
82+
assert.true(settings.mustChooseTimeZone);
83+
});
84+
});
85+
86+
module('shouldUseLocalTimeZone', function () {
87+
test('defaults to null', function (assert) {
88+
const service = this.owner.lookup('service:poll-settings');
89+
const poll = generateMockPoll();
90+
const settings = service.getSettings(poll);
91+
92+
assert.strictEqual(settings.shouldUseLocalTimeZone, null);
93+
});
94+
});
95+
96+
module('timeZone', function () {
97+
test('is undefined if local time zone should be used', function (assert) {
98+
const service = this.owner.lookup('service:poll-settings');
99+
const poll = generateMockPoll();
100+
const settings = service.getSettings(poll);
101+
settings.shouldUseLocalTimeZone = true;
102+
103+
assert.strictEqual(settings.timeZone, undefined);
104+
});
105+
106+
test("is undefined if poll's time zone is null", function (assert) {
107+
const service = this.owner.lookup('service:poll-settings');
108+
const poll = generateMockPoll({ timezone: null });
109+
const settings = service.getSettings(poll);
110+
111+
assert.strictEqual(settings.timeZone, undefined);
112+
113+
settings.shouldUseLocalTimeZone = false;
114+
assert.strictEqual(settings.timeZone, undefined);
115+
});
116+
117+
test("is poll's time zone if shouldn't use local time zone", function (assert) {
118+
const service = this.owner.lookup('service:poll-settings');
119+
const poll = generateMockPoll({ timezone: 'Europe/Berlin' });
120+
const settings = service.getSettings(poll);
121+
settings.shouldUseLocalTimeZone = false;
122+
123+
assert.strictEqual(settings.timeZone, 'Europe/Berlin');
124+
});
125+
});
126+
});
127+
});

0 commit comments

Comments
 (0)