hof 21.0.20-axios-beta → 22.0.0-timeout-warning-beta.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. package/.nyc_output/39365c14-40b7-4634-b733-940b72a11984.json +1 -0
  2. package/.nyc_output/processinfo/39365c14-40b7-4634-b733-940b72a11984.json +1 -0
  3. package/.nyc_output/processinfo/index.json +1 -1
  4. package/CHANGELOG.md +16 -0
  5. package/codeReviewChecklist.md +22 -0
  6. package/config/hof-defaults.js +11 -2
  7. package/frontend/govuk-template/build/govuk_template.html +3 -4
  8. package/frontend/govuk-template/govuk_template_generated.html +3 -4
  9. package/frontend/template-mixins/mixins/template-mixins.js +1 -0
  10. package/frontend/template-mixins/partials/forms/checkbox.html +5 -0
  11. package/frontend/template-mixins/partials/forms/input-text-group.html +1 -1
  12. package/frontend/template-mixins/partials/forms/select.html +6 -6
  13. package/frontend/template-mixins/partials/forms/textarea-group.html +1 -1
  14. package/frontend/template-partials/views/partials/head.html +8 -10
  15. package/frontend/template-partials/views/partials/page.html +1 -0
  16. package/frontend/template-partials/views/partials/session-timeout-warning.html +17 -0
  17. package/frontend/themes/gov-uk/client-js/index.js +2 -0
  18. package/frontend/themes/gov-uk/client-js/session-timeout-dialog.js +333 -0
  19. package/frontend/themes/gov-uk/styles/_session-timeout-dialog.scss +209 -0
  20. package/frontend/themes/gov-uk/styles/govuk.scss +1 -0
  21. package/index.js +8 -4
  22. package/lib/ga-tag.js +22 -13
  23. package/model/index.js +28 -29
  24. package/package.json +6 -7
  25. package/pull_request.md +16 -0
  26. package/sandbox/apps/sandbox/index.js +1 -0
  27. package/sandbox/package.json +1 -1
  28. package/sandbox/public/css/app.css +251 -6
  29. package/sandbox/public/js/bundle.js +36441 -25219
  30. package/sandbox/yarn.lock +14 -9
  31. package/.nyc_output/9651d42a-59d8-48e6-949c-655d9fa6db21.json +0 -1
  32. package/.nyc_output/processinfo/9651d42a-59d8-48e6-949c-655d9fa6db21.json +0 -1
  33. package/model/apis/axios-settings.js +0 -9
@@ -0,0 +1,333 @@
1
+ /* eslint max-len: 0 */
2
+ 'use strict';
3
+
4
+ const $ = require('jquery');
5
+
6
+ // Modal dialog prototype
7
+ window.GOVUK.sessionDialog = {
8
+ el: document.getElementById('js-modal-dialog'),
9
+ $el: $('#js-modal-dialog'),
10
+ $lastFocusedEl: null,
11
+ $closeButton: $('.modal-dialog .js-dialog-close'),
12
+ dialogIsOpenClass: 'dialog-is-open',
13
+ timers: [],
14
+ warningTextPrefix: 'To protect your information, this page will time out in ',
15
+ warningTextSuffix: '.',
16
+ warningText: $('.dialog-text').text(),
17
+ warningTextExtra: '',
18
+
19
+ // Timer specific markup. If these are not present, timeout and redirection are disabled
20
+ $timer: $('#js-modal-dialog .timer'),
21
+ $accessibleTimer: $('#js-modal-dialog .at-timer'),
22
+
23
+ secondsSessionTimeout: parseInt($('#js-modal-dialog').data('session-timeout'), 10 || 1800),
24
+ secondsTimeoutWarning: parseInt($('#js-modal-dialog').data('session-timeout-warning'), 10 || 300),
25
+ timeoutRedirectUrl: $('#js-modal-dialog').data('url-redirect'),
26
+ timeSessionRefreshed: new Date(),
27
+
28
+ bindUIElements: function () {
29
+ window.GOVUK.sessionDialog.$closeButton.on('click', function (e) {
30
+ e.preventDefault();
31
+ window.GOVUK.sessionDialog.closeDialog();
32
+ });
33
+
34
+ // Close modal when ESC pressed
35
+ $(document).keydown(function (e) {
36
+ if (window.GOVUK.sessionDialog.isDialogOpen() && e.keyCode === 27) {
37
+ window.GOVUK.sessionDialog.closeDialog();
38
+ }
39
+ });
40
+ },
41
+
42
+ isDialogOpen: function () {
43
+ return window.GOVUK.sessionDialog.el.open;
44
+ },
45
+
46
+ isConfigured: function () {
47
+ return window.GOVUK.sessionDialog.$timer.length > 0 &&
48
+ window.GOVUK.sessionDialog.$accessibleTimer.length > 0 &&
49
+ window.GOVUK.sessionDialog.secondsSessionTimeout &&
50
+ window.GOVUK.sessionDialog.secondsTimeoutWarning &&
51
+ window.GOVUK.sessionDialog.timeoutRedirectUrl;
52
+ },
53
+
54
+ openDialog: function () {
55
+ if (!window.GOVUK.sessionDialog.isDialogOpen()) {
56
+ $('html, body').addClass(window.GOVUK.sessionDialog.dialogIsOpenClass);
57
+ window.GOVUK.sessionDialog.saveLastFocusedEl();
58
+ window.GOVUK.sessionDialog.makePageContentInert();
59
+ window.GOVUK.sessionDialog.el.showModal();
60
+ }
61
+ },
62
+
63
+ closeDialog: function () {
64
+ if (window.GOVUK.sessionDialog.isDialogOpen()) {
65
+ $('html, body').removeClass(window.GOVUK.sessionDialog.dialogIsOpenClass);
66
+ window.GOVUK.sessionDialog.el.close();
67
+ window.GOVUK.sessionDialog.setFocusOnLastFocusedEl();
68
+ window.GOVUK.sessionDialog.removeInertFromPageContent();
69
+ window.GOVUK.sessionDialog.refreshSession();
70
+ }
71
+ },
72
+
73
+ saveLastFocusedEl: function () {
74
+ window.GOVUK.sessionDialog.$lastFocusedEl = document.activeElement;
75
+ if (!window.GOVUK.sessionDialog.$lastFocusedEl || window.GOVUK.sessionDialog.$lastFocusedEl === document.body) {
76
+ window.GOVUK.sessionDialog.$lastFocusedEl = null;
77
+ } else if (document.querySelector) {
78
+ window.GOVUK.sessionDialog.$lastFocusedEl = document.querySelector(':focus');
79
+ }
80
+ },
81
+
82
+ // Set focus back on last focused el when modal closed
83
+ setFocusOnLastFocusedEl: function () {
84
+ if (window.GOVUK.sessionDialog.$lastFocusedEl) {
85
+ window.setTimeout(function () {
86
+ window.GOVUK.sessionDialog.$lastFocusedEl.focus();
87
+ }, 0);
88
+ }
89
+ },
90
+
91
+ // Set page content to inert to indicate to screenreaders it's inactive
92
+ // NB: This will look for #content for toggling inert state
93
+ makePageContentInert: function () {
94
+ if (document.querySelector('#content')) {
95
+ document.querySelector('#content').inert = true;
96
+ document.querySelector('#content').setAttribute('aria-hidden', 'true');
97
+ }
98
+ },
99
+
100
+ // Make page content active when modal is not open
101
+ // NB: This will look for #content for toggling inert state
102
+ removeInertFromPageContent: function () {
103
+ if (document.querySelector('#content')) {
104
+ document.querySelector('#content').inert = false;
105
+ document.querySelector('#content').setAttribute('aria-hidden', 'false');
106
+ }
107
+ },
108
+
109
+ numberToWords: function (n) {
110
+ const string = n.toString();
111
+ let start;
112
+ let end;
113
+ let chunk;
114
+ let ints;
115
+ let i;
116
+ let word;
117
+ let words = 'and';
118
+
119
+ if (parseInt(string, 10) === 0) {
120
+ return 'zero';
121
+ }
122
+
123
+ /* Array of units as words */
124
+ const units = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'];
125
+
126
+ /* Array of tens as words */
127
+ const tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
128
+
129
+ /* Array of scales as words */
130
+ const scales = ['', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion', 'quatttuor-decillion', 'quindecillion', 'sexdecillion', 'septen-decillion', 'octodecillion', 'novemdecillion', 'vigintillion', 'centillion'];
131
+
132
+ /* Split user arguemnt into 3 digit chunks from right to left */
133
+ start = string.length;
134
+ const chunks = [];
135
+ while (start > 0) {
136
+ end = start;
137
+ chunks.push(string.slice((start = Math.max(0, start - 3)), end));
138
+ }
139
+
140
+ /* Check if function has enough scale words to be able to stringify the user argument */
141
+ const chunksLen = chunks.length;
142
+ if (chunksLen > scales.length) {
143
+ return '';
144
+ }
145
+
146
+ /* Stringify each integer in each chunk */
147
+ words = [];
148
+ for (i = 0; i < chunksLen; i++) {
149
+ chunk = parseInt(chunks[i], 10);
150
+
151
+ if (chunk) {
152
+ /* Split chunk into array of individual integers */
153
+ ints = chunks[i].split('').reverse().map(parseFloat);
154
+
155
+ /* If tens integer is 1, i.e. 10, then add 10 to units integer */
156
+ if (ints[1] === 1) {
157
+ ints[0] += 10;
158
+ }
159
+
160
+ /* Add scale word if chunk is not zero and array item exists */
161
+ if ((word === scales[i])) {
162
+ words.push(word);
163
+ }
164
+
165
+ /* Add unit word if array item exists */
166
+ if ((word === units[ints[0]])) {
167
+ words.push(word);
168
+ }
169
+
170
+ /* Add tens word if array item exists */
171
+ if ((word === tens[ints[1]])) {
172
+ words.push(word);
173
+ }
174
+
175
+ /* Add hundreds word if array item exists */
176
+ if ((word === units[ints[2]])) {
177
+ words.push(word + ' hundred');
178
+ }
179
+ }
180
+ }
181
+ return words.reverse().join(' ');
182
+ },
183
+
184
+ // Attempt to convert numerics into text as OS VoiceOver
185
+ // occasionally stalled when encountering numbers
186
+ timeToWords: function (t, unit) {
187
+ let words;
188
+ if (t > 0) {
189
+ try {
190
+ words = window.GOVUK.sessionDialog.numberToWords(t);
191
+ } catch (e) {
192
+ words = t;
193
+ }
194
+ words = words + ' ' + window.GOVUK.sessionDialog.pluralise(t, unit);
195
+ } else {
196
+ words = '';
197
+ }
198
+ return words;
199
+ },
200
+
201
+ pluralise: function (n, unit) {
202
+ return n === 1 ? unit : unit + 's';
203
+ },
204
+
205
+ numericSpan: function (n, unit) {
206
+ return '<span class="tabular-numbers">' + n + '</span> ' + window.GOVUK.sessionDialog.pluralise(n, unit);
207
+ },
208
+
209
+ countdownText: function (minutes, seconds) {
210
+ const minutesText = window.GOVUK.sessionDialog.numericSpan(minutes, 'minute');
211
+ const secondsText = window.GOVUK.sessionDialog.numericSpan(seconds, 'second');
212
+ return minutes > 0 ? minutesText : secondsText;
213
+ },
214
+
215
+ countdownAtText: function (minutes, seconds) {
216
+ const minutesText = window.GOVUK.sessionDialog.timeToWords(minutes, 'minute');
217
+ const secondsText = window.GOVUK.sessionDialog.timeToWords(seconds, 'second');
218
+ return minutes > 0 ? minutesText : secondsText;
219
+ },
220
+
221
+ startCountdown: function () {
222
+ const $timer = window.GOVUK.sessionDialog.$timer;
223
+ const $accessibleTimer = window.GOVUK.sessionDialog.$accessibleTimer;
224
+ let timerRunOnce = false;
225
+ const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
226
+
227
+ const seconds = window.GOVUK.sessionDialog.secondsUntilSessionTimeout();
228
+ const minutes = seconds / 60;
229
+
230
+ $timer.text(minutes + ' minute' + (minutes > 1 ? 's' : ''));
231
+
232
+ (function countdown() {
233
+ const secondsUntilSessionTimeout = window.GOVUK.sessionDialog.secondsUntilSessionTimeout();
234
+ const timerExpired = secondsUntilSessionTimeout <= window.GOVUK.sessionDialog.secondsFinalWarning;
235
+
236
+ if (!timerExpired) {
237
+ const minutesLeft = parseInt(secondsUntilSessionTimeout / 60, 10);
238
+ const secondsLeft = parseInt(secondsUntilSessionTimeout % 60, 10);
239
+ const atMinutesText = window.GOVUK.sessionDialog.timeToWords(minutesLeft, 'minute');
240
+ const atSecondsText = window.GOVUK.sessionDialog.timeToWords(secondsLeft, 'second');
241
+
242
+ // Below string will get read out by screen readers every time
243
+ // the timeout refreshes.
244
+ // Add additional information in extraText which will get announced to AT the
245
+ // first time the time out opens
246
+ const countdownText = window.GOVUK.sessionDialog.countdownText(minutesLeft, secondsLeft);
247
+ const text = window.GOVUK.sessionDialog.warningTextPrefix + '<strong>' + countdownText + '</strong>' + window.GOVUK.sessionDialog.warningTextSuffix;
248
+ const countdownAtText = window.GOVUK.sessionDialog.countdownAtText(atMinutesText, atSecondsText);
249
+ const atText = window.GOVUK.sessionDialog.warningTextPrefix + countdownAtText + window.GOVUK.sessionDialog.warningTextSuffix + 'bgbhj ' + window.GOVUK.sessionDialog.warningText;
250
+ const extraText = '\n' + window.GOVUK.sessionDialog.warningTextExtra;
251
+
252
+ $timer.html(text + ' ' + extraText);
253
+
254
+ // Update screen reader friendly content every 20 secs
255
+ if (secondsLeft % 20 === 0) {
256
+ // Read out the extra content only once.
257
+ // Don't read out on iOS VoiceOver which stalls on the longer text
258
+ if (!timerRunOnce && !iOS) {
259
+ $accessibleTimer.text(atText + extraText);
260
+ timerRunOnce = true;
261
+ } else {
262
+ $accessibleTimer.text(atText);
263
+ }
264
+ }
265
+
266
+ window.GOVUK.sessionDialog.addTimer(countdown, 20);
267
+ }
268
+ })();
269
+ },
270
+
271
+ // Clears all timers
272
+ clearTimers: function () {
273
+ for (let i = 0; i < window.GOVUK.sessionDialog.timers.length; i++) {
274
+ clearInterval(window.GOVUK.sessionDialog.timers[i]);
275
+ }
276
+ },
277
+
278
+ refreshSession: function () {
279
+ $.get('');
280
+ window.GOVUK.sessionDialog.timeSessionRefreshed = new Date();
281
+ window.GOVUK.sessionDialog.controller();
282
+ },
283
+
284
+ redirect: function () {
285
+ window.location = window.GOVUK.sessionDialog.timeoutRedirectUrl;
286
+ },
287
+
288
+ // JS doesn't allow resetting timers globally so timers need
289
+ // to be retained for resetting.
290
+ addTimer: function (f, seconds) {
291
+ window.GOVUK.sessionDialog.timers.push(setInterval(f, seconds * 1000));
292
+ },
293
+
294
+ secondsSinceRefresh: function () {
295
+ return Math.round(Math.abs((window.GOVUK.sessionDialog.timeSessionRefreshed - new Date()) / 1000));
296
+ },
297
+
298
+ secondsUntilSessionTimeout: function () {
299
+ return window.GOVUK.sessionDialog.secondsSessionTimeout - window.GOVUK.sessionDialog.secondsSinceRefresh();
300
+ },
301
+
302
+ secondsUntilTimeoutWarning: function () {
303
+ return window.GOVUK.sessionDialog.secondsUntilSessionTimeout() - window.GOVUK.sessionDialog.secondsTimeoutWarning;
304
+ },
305
+
306
+ // countdown controller logic
307
+ controller: function () {
308
+ window.GOVUK.sessionDialog.clearTimers();
309
+
310
+ const secondsUntilSessionTimeout = window.GOVUK.sessionDialog.secondsUntilSessionTimeout();
311
+
312
+ if (secondsUntilSessionTimeout <= 0) {
313
+ // timed out - redirect
314
+ window.GOVUK.sessionDialog.redirect();
315
+ } else if (secondsUntilSessionTimeout <= window.GOVUK.sessionDialog.secondsTimeoutWarning) {
316
+ // timeout warning - show countdown and schedule redirect
317
+ window.GOVUK.sessionDialog.openDialog();
318
+ window.GOVUK.sessionDialog.startCountdown();
319
+ window.GOVUK.sessionDialog.addTimer(window.GOVUK.sessionDialog.controller, window.GOVUK.sessionDialog.secondsUntilSessionTimeout());
320
+ } else {
321
+ // wait for warning
322
+ window.GOVUK.sessionDialog.addTimer(window.GOVUK.sessionDialog.controller, window.GOVUK.sessionDialog.secondsUntilTimeoutWarning());
323
+ }
324
+ },
325
+
326
+ init: function (options) {
327
+ $.extend(window.GOVUK.sessionDialog, options);
328
+ if (window.GOVUK.sessionDialog.el && window.GOVUK.sessionDialog.isConfigured()) {
329
+ window.GOVUK.sessionDialog.bindUIElements();
330
+ window.GOVUK.sessionDialog.controller();
331
+ }
332
+ }
333
+ };
@@ -0,0 +1,209 @@
1
+ .modal-dialog {
2
+ display: none;
3
+ }
4
+
5
+ .modal-dialog--no-js-persistent {
6
+ display: inline-block;
7
+ }
8
+
9
+ .js-enabled {
10
+ .modal-dialog--no-js-persistent {
11
+ display: none;
12
+
13
+ &[open], .dialog-button {
14
+ display: inline-block;
15
+ }
16
+ }
17
+
18
+ .modal-dialog[open] {
19
+ display: inline-block;
20
+ }
21
+ }
22
+
23
+ .modal-dialog[open] {
24
+ overflow-x: hidden;
25
+ overflow-y: auto;
26
+ max-height: 90vh;
27
+ padding: 0;
28
+ margin-bottom: 0;
29
+ margin-top: 0;
30
+ position: fixed;
31
+ top: 50% !important;
32
+ -webkit-transform: translate(0, -50%);
33
+ -ms-transform: translate(0, -50%);
34
+ transform: translate(0, -50%);
35
+ }
36
+
37
+ @media (min-width: 641px) {
38
+ .modal-dialog[open] {
39
+ padding: 0;
40
+ }
41
+ }
42
+
43
+ .modal-dialog__inner {
44
+ padding: 20px;
45
+ }
46
+
47
+ @media (min-width: 641px) {
48
+ .modal-dialog__inner {
49
+ padding: 30px;
50
+ }
51
+ }
52
+
53
+ .modal-dialog__inner__text {
54
+ font-family: "nta", Arial, sans-serif;
55
+ font-weight: 400;
56
+ text-transform: none;
57
+ font-size: 16px;
58
+ line-height: 1.25;
59
+ padding-top: 2px;
60
+ padding-bottom: 8px;
61
+ margin-bottom: 20px;
62
+ }
63
+
64
+ @media (min-width: 641px) {
65
+ .modal-dialog__inner__text {
66
+ font-size: 19px;
67
+ line-height: 1.31579;
68
+ }
69
+ }
70
+
71
+ @media (min-width: 641px) {
72
+ .modal-dialog__inner__text {
73
+ padding-top: 0;
74
+ padding-bottom: 5px;
75
+ }
76
+ }
77
+
78
+ .modal-dialog__inner__button {
79
+ font-size: 19px;
80
+ margin-top: 10px;
81
+ }
82
+
83
+ .modal-dialog__inner__link {
84
+ font-family: "nta", Arial, sans-serif;
85
+ font-weight: 400;
86
+ text-transform: none;
87
+ font-size: 16px;
88
+ line-height: 1.25;
89
+ padding-top: 2px;
90
+ padding-bottom: 8px;
91
+ background: none;
92
+ border: none;
93
+ vertical-align: middle;
94
+ margin-top: 20px;
95
+
96
+ &:hover {
97
+ cursor: pointer;
98
+ }
99
+ }
100
+
101
+ @media (min-width: 641px) {
102
+ .modal-dialog__inner__link {
103
+ font-size: 19px;
104
+ line-height: 1.31579;
105
+ }
106
+ }
107
+
108
+ @media (min-width: 641px) {
109
+ .modal-dialog__inner__link {
110
+ padding-top: 0;
111
+ padding-bottom: 5px;
112
+ }
113
+ }
114
+
115
+ @media (max-width: 640px) {
116
+ .modal-dialog__inner__link {
117
+ text-align: center;
118
+ display: block;
119
+ margin-top: 25px;
120
+ }
121
+ }
122
+
123
+ @media (min-width: 641px) {
124
+ .modal-dialog__inner__link {
125
+ position: absolute;
126
+ top: 50%;
127
+ transform: translateY(-50%);
128
+ padding: 0;
129
+ margin: 0 0 0 30px;
130
+ }
131
+ }
132
+
133
+ .modal-dialog__inner__block {
134
+ position: relative;
135
+ }
136
+
137
+ .modal-dialog #dialog-title {
138
+ margin-top: 0;
139
+ }
140
+
141
+ .dialog-is-open {
142
+ overflow: hidden;
143
+ }
144
+
145
+ dialog {
146
+ left: 0;
147
+ right: 0;
148
+ width: -moz-fit-content;
149
+ width: -webkit-fit-content;
150
+ width: fit-content;
151
+ height: -moz-fit-content;
152
+ height: -webkit-fit-content;
153
+ height: fit-content;
154
+ margin: auto;
155
+ border: solid;
156
+ padding: 1em;
157
+ background: white;
158
+ color: black;
159
+ display: none;
160
+ border: 5px solid black;
161
+
162
+ + .backdrop {
163
+ position: fixed;
164
+ top: 0;
165
+ right: 0;
166
+ bottom: 0;
167
+ left: 0;
168
+ background: rgba(0, 0, 0, 0.8);
169
+ }
170
+
171
+ &[open] {
172
+ display: block;
173
+ box-sizing: border-box;
174
+ margin: 0 auto;
175
+ padding: 15px;
176
+ width: 90%;
177
+
178
+ + .backdrop, &::backdrop {
179
+ background: rgba(0, 0, 0, 0.8);
180
+ }
181
+ }
182
+ }
183
+
184
+ @media (min-width: 641px) {
185
+ dialog[open] {
186
+ padding: 30px;
187
+ margin: 30px auto;
188
+ max-width: 500px;
189
+ }
190
+ }
191
+
192
+ .tabular-numbers {
193
+ font-family: "ntatabularnumbers", "nta", Arial, sans-serif;
194
+ }
195
+
196
+ .dialog-sign-out-link {
197
+ @include govuk-font($size: 24);
198
+ display: inline-block;
199
+ margin: 5px;
200
+
201
+ @include govuk-media-query($from: tablet) {
202
+ @include govuk-font($size: 19);
203
+
204
+ position: relative;
205
+ top: 2px;
206
+ padding: 0.526315em 0.789473em 0.263157em;
207
+ line-height: 1.5;
208
+ }
209
+ }
@@ -26,6 +26,7 @@ $path: "/public/images/" !default;
26
26
  @import "cookie-settings";
27
27
  @import "check_your_answers";
28
28
  @import "pdf";
29
+ @import "session-timeout-dialog";
29
30
 
30
31
  // Modules
31
32
  @import "modules/validation";
package/index.js CHANGED
@@ -84,6 +84,7 @@ const getContentSecurityPolicy = (config, res) => {
84
84
  'www.google.co.uk/ads/ga-audiences'
85
85
  ],
86
86
  connectSrc: [
87
+ "'self'",
87
88
  'https://www.google-analytics.com',
88
89
  'https://region1.google-analytics.com',
89
90
  'https://region1.analytics.google.com'
@@ -147,6 +148,9 @@ function bootstrap(options) {
147
148
  res.locals.appName = config.appName;
148
149
  res.locals.htmlLang = config.htmlLang;
149
150
  res.locals.cookieName = config.session.name;
151
+ // session timeout warning configs
152
+ res.locals.sessionTimeOut = config.session.ttl;
153
+ res.locals.sessionTimeOutWarning = config.sessionTimeOutWarning;
150
154
  next();
151
155
  });
152
156
 
@@ -189,10 +193,10 @@ function bootstrap(options) {
189
193
  app.use(morgan('sessionId=:id ' + morgan.combined, {
190
194
  stream: config.logger.stream,
191
195
  skip: (req, res) => config.loglevel !== 'debug' &&
192
- (
193
- res.statusCode >= 300 || !_.get(req, 'session.id') ||
194
- config.ignoreMiddlewareLogs.some(v => req.originalUrl.includes(v))
195
- )
196
+ (
197
+ res.statusCode >= 300 || !_.get(req, 'session.id') ||
198
+ config.ignoreMiddlewareLogs.some(v => req.originalUrl.includes(v))
199
+ )
196
200
  }));
197
201
 
198
202
  serveStatic(app, config);
package/lib/ga-tag.js CHANGED
@@ -52,26 +52,35 @@ const setupPageMap = routes => {
52
52
  module.exports = (app, config) => {
53
53
  const gaTagId = config.gaTagId;
54
54
  const ga4TagId = config.ga4TagId;
55
- const gtmTagId = config.gtmTagId;
56
- const environmentType = config.environmentType ? config.environmentType : 'dev';
55
+ const gtm = config.gtm;
57
56
  const gaCrossDomainTrackingTagId = config.gaCrossDomainTrackingTagId;
58
57
  const routes = config.routes;
59
58
 
60
- if (gaTagId || ga4TagId) {
59
+ if (gaTagId || ga4TagId || gtm.tagId) {
61
60
  const pageMap = setupPageMap(routes);
62
61
 
63
62
  app.use((req, res, next) => {
64
63
  const page = pageView(req.path, pageMap);
65
- res.locals.gaAllowDebug = config.env === 'development';
66
- res.locals.isETA = config.appName === 'ETA';
67
- res.locals.gaTagId = gaTagId;
68
- res.locals.ga4TagId = ga4TagId;
69
- res.locals.gtmTagId = gtmTagId;
70
- res.locals.environmentType = environmentType;
71
- res.locals.gaCrossDomainTrackingTagId = gaCrossDomainTrackingTagId;
72
- res.locals['ga-id'] = gaTagId;
73
- res.locals['ga-page'] = page;
74
- res.locals['gtm-page'] = convertToGTMPage(page);
64
+
65
+ // Preparing common res.locals properties
66
+ const properties = {
67
+ gaAllowDebug: config.env === 'development',
68
+ gaTagId: gaTagId,
69
+ ga4TagId: ga4TagId,
70
+ gaCrossDomainTrackingTagId: gaCrossDomainTrackingTagId,
71
+ 'ga-id': gaTagId,
72
+ 'ga-page': page
73
+ };
74
+
75
+ // Adding extra properties if a GTM TAG is available
76
+ if (gtm.tagId) {
77
+ gtm.config.pageName = gtm.composePageName(page, convertToGTMPage);
78
+ Object.assign(properties, {
79
+ gtmConfig: JSON.stringify(gtm.config),
80
+ gtmTagId: gtm.tagId
81
+ });
82
+ }
83
+ res.locals = Object.assign(res.locals, properties);
75
84
  next();
76
85
  });
77
86
  }