@financial-times/n-myft-ui 30.4.4 → 31.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.circleci/config.yml +11 -11
- package/.circleci/shared-helpers/helper-setup-heroku-cli +2 -2
- package/Makefile +8 -2
- package/build-state/npm-shrinkwrap.json +884 -903
- package/components/jsx/follow-plus-instant-alerts/index.js +16 -0
- package/components/jsx/preferences-modal/index.js +61 -30
- package/components/jsx/preferences-modal/preferences-modal.jsx +3 -3
- package/dist/preferences-modal/preferences-modal.js +6 -6
- package/package.json +35 -34
@@ -44,7 +44,22 @@ const instantAlertsIconUpdate = ({ event, followPlusInstantAlerts }) => {
|
|
44
44
|
toggleInstantAlertsClass({instantAlertsOn, followPlusInstantAlerts });
|
45
45
|
};
|
46
46
|
|
47
|
+
const instantAlertsIconOff = ({ event, followPlusInstantAlerts }) => {
|
48
|
+
const modalConceptId = followPlusInstantAlerts.dataset.conceptId;
|
49
|
+
if (!event || !modalConceptId) {
|
50
|
+
return;
|
51
|
+
}
|
47
52
|
|
53
|
+
const currentConcept = event.detail.subject === modalConceptId;
|
54
|
+
if (!currentConcept) {
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
|
58
|
+
toggleInstantAlertsClass({
|
59
|
+
instantAlertsOn: false,
|
60
|
+
followPlusInstantAlerts,
|
61
|
+
});
|
62
|
+
};
|
48
63
|
|
49
64
|
|
50
65
|
const sendModalToggleEvent = ({ followPlusInstantAlerts }) => {
|
@@ -73,4 +88,5 @@ export default () => {
|
|
73
88
|
document.body.addEventListener('myft.user.followed.concept.load', (event) => instantAlertsIconLoad({event, followPlusInstantAlerts}));
|
74
89
|
|
75
90
|
document.body.addEventListener('myft.user.followed.concept.update', (event) => instantAlertsIconUpdate({event, followPlusInstantAlerts}));
|
91
|
+
document.body.addEventListener('myft.user.followed.concept.remove', (event) => instantAlertsIconOff({ event, followPlusInstantAlerts }));
|
76
92
|
};
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import myFtClient from 'next-myft-client';
|
2
2
|
import getToken from '../../../myft/ui/lib/get-csrf-token';
|
3
|
-
import oTracking from '@financial-times/o-tracking';
|
4
3
|
|
5
4
|
const csrfToken = getToken();
|
6
5
|
|
@@ -46,25 +45,44 @@ const positionModal = ({ event, preferencesModal } = {}) => {
|
|
46
45
|
}
|
47
46
|
};
|
48
47
|
|
49
|
-
const
|
48
|
+
const toggleCheckboxStatus = ({ instantAlertsCheckbox, isChecked }) => {
|
49
|
+
if (isChecked) {
|
50
|
+
instantAlertsCheckbox.dataset.trackable = 'pop-up-box|set-instant-alert-off';
|
51
|
+
instantAlertsCheckbox.checked = true;
|
52
|
+
} else {
|
53
|
+
instantAlertsCheckbox.dataset.trackable = 'pop-up-box|set-instant-alert-on';
|
54
|
+
instantAlertsCheckbox.checked = false;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
const tracking = (conceptId) => {
|
59
|
+
const trackingData = {
|
60
|
+
category: 'component',
|
61
|
+
action: 'view',
|
62
|
+
concept_id: conceptId,
|
63
|
+
component: {
|
64
|
+
type: 'component',
|
65
|
+
name: 'pop-up-box',
|
66
|
+
id: '72de123e-5082-11ee-be56-0242ac120002',
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
const trackingEvent = new CustomEvent('oTracking.event', {
|
71
|
+
detail: trackingData,
|
72
|
+
bubbles: true
|
73
|
+
});
|
74
|
+
|
75
|
+
document.body.dispatchEvent(trackingEvent);
|
76
|
+
};
|
77
|
+
|
78
|
+
const preferenceModalShowAndHide = ({ event, preferencesModal, conceptId }) => {
|
50
79
|
preferencesModal.classList.toggle('n-myft-ui__preferences-modal--show');
|
51
80
|
|
52
81
|
if (preferencesModal.classList.contains('n-myft-ui__preferences-modal--show')) {
|
53
82
|
positionModal({ event, preferencesModal });
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
getContextData: () => {
|
58
|
-
return {
|
59
|
-
component: {
|
60
|
-
type: 'component',
|
61
|
-
name: 'pop-up-box',
|
62
|
-
id: '72de123e-5082-11ee-be56-0242ac120002',
|
63
|
-
},
|
64
|
-
};
|
65
|
-
},
|
66
|
-
};
|
67
|
-
oTracking.view.init(opts);
|
83
|
+
|
84
|
+
tracking(conceptId);
|
85
|
+
|
68
86
|
} else {
|
69
87
|
// Remove existing errors when hiding the modal
|
70
88
|
renderError({
|
@@ -79,9 +97,7 @@ const removeTopic = async ({ event, conceptId, preferencesModal }) => {
|
|
79
97
|
|
80
98
|
try {
|
81
99
|
await myFtClient.remove('user', null, 'followed', 'concept', conceptId, { token: csrfToken });
|
82
|
-
|
83
100
|
preferenceModalShowAndHide({ preferencesModal });
|
84
|
-
|
85
101
|
} catch (error) {
|
86
102
|
renderError({ message: 'Sorry, we are unable to remove this topic. Please try again later or try from <a href="/myft">myFT</a>', preferencesModal });
|
87
103
|
}
|
@@ -91,8 +107,7 @@ const removeTopic = async ({ event, conceptId, preferencesModal }) => {
|
|
91
107
|
|
92
108
|
const getAlertsPreferenceText = (addedTextBuffer) => {
|
93
109
|
const alertsEnabledText = `Your delivery channels: ${addedTextBuffer.join(', ')}.`;
|
94
|
-
|
95
|
-
return Array.isArray(addedTextBuffer) && addedTextBuffer.length > 0 ? alertsEnabledText : alertsDisabledText;
|
110
|
+
return Array.isArray(addedTextBuffer) && addedTextBuffer.length > 0 ? alertsEnabledText : '';
|
96
111
|
};
|
97
112
|
|
98
113
|
const getAlertsPreferences = async ({ event, preferencesModal }) => {
|
@@ -138,13 +153,11 @@ const setCheckboxForAlertConcept = ({ event, preferencesModal }) => {
|
|
138
153
|
// 2. the said concept has instant alert enabled
|
139
154
|
// if so, check the checkbox within the modal
|
140
155
|
const currentConcept = event.detail.items.find(item => item && item.uuid === conceptId);
|
141
|
-
|
142
|
-
|
143
|
-
instantAlertsCheckbox
|
144
|
-
|
145
|
-
|
146
|
-
instantAlertsCheckbox.checked = false;
|
147
|
-
}
|
156
|
+
const isChecked = currentConcept && currentConcept._rel && currentConcept._rel.instant;
|
157
|
+
toggleCheckboxStatus({
|
158
|
+
instantAlertsCheckbox,
|
159
|
+
isChecked,
|
160
|
+
});
|
148
161
|
};
|
149
162
|
|
150
163
|
const toggleInstantAlertsPreference = async ({ event, conceptId, preferencesModal }) => {
|
@@ -160,11 +173,13 @@ const toggleInstantAlertsPreference = async ({ event, conceptId, preferencesModa
|
|
160
173
|
token: csrfToken
|
161
174
|
};
|
162
175
|
|
176
|
+
toggleCheckboxStatus({
|
177
|
+
instantAlertsCheckbox,
|
178
|
+
isChecked: instantAlertsCheckbox.checked,
|
179
|
+
});
|
163
180
|
if (instantAlertsCheckbox.checked) {
|
164
|
-
instantAlertsCheckbox.dataset.trackable = 'pop-up-box|set-instant-alert-off';
|
165
181
|
data._rel = {instant: 'true'};
|
166
182
|
} else {
|
167
|
-
instantAlertsCheckbox.dataset.trackable = 'pop-up-box|set-instant-alert-on';
|
168
183
|
data._rel = {instant: 'false'};
|
169
184
|
}
|
170
185
|
|
@@ -184,6 +199,21 @@ const toggleInstantAlertsPreference = async ({ event, conceptId, preferencesModa
|
|
184
199
|
instantAlertsCheckbox.removeAttribute('disabled');
|
185
200
|
};
|
186
201
|
|
202
|
+
const setCheckboxForAlertConceptToOff = ({ event, preferencesModal }) => {
|
203
|
+
const conceptId = preferencesModal.dataset.conceptId;
|
204
|
+
const instantAlertsCheckbox = preferencesModal.querySelector('[data-component-id="myft-preferences-modal-checkbox"]');
|
205
|
+
|
206
|
+
const currentConcept = event.detail.subject === conceptId;
|
207
|
+
if (!currentConcept) {
|
208
|
+
return;
|
209
|
+
}
|
210
|
+
|
211
|
+
toggleCheckboxStatus({
|
212
|
+
instantAlertsCheckbox,
|
213
|
+
isChecked: false,
|
214
|
+
});
|
215
|
+
}
|
216
|
+
|
187
217
|
export default () => {
|
188
218
|
/**
|
189
219
|
* This feature is part of a test
|
@@ -213,9 +243,10 @@ export default () => {
|
|
213
243
|
|
214
244
|
instantAlertsCheckbox.addEventListener('change', event => toggleInstantAlertsPreference({ event, conceptId, preferencesModal }));
|
215
245
|
|
216
|
-
document.addEventListener('myft.preference-modal.show-hide.toggle', event => preferenceModalShowAndHide({ event, preferencesModal }));
|
246
|
+
document.addEventListener('myft.preference-modal.show-hide.toggle', event => preferenceModalShowAndHide({ event, preferencesModal, conceptId }));
|
217
247
|
|
218
248
|
document.addEventListener('myft.user.preferred.preference.load', (event) => getAlertsPreferences({ event, preferencesModal }));
|
219
249
|
|
220
250
|
document.body.addEventListener('myft.user.followed.concept.load', (event) => setCheckboxForAlertConcept({ event, preferencesModal }));
|
251
|
+
document.body.addEventListener('myft.user.followed.concept.remove', (event) => setCheckboxForAlertConceptToOff({ event, preferencesModal }));
|
221
252
|
};
|
@@ -26,7 +26,6 @@ export default function InstantAlertsPreferencesModal({ flags, conceptId, visibl
|
|
26
26
|
className={`n-myft-ui__preferences-modal ${visible ? 'n-myft-ui__preferences-modal--show' : ''}`}
|
27
27
|
data-component-id="myft-preferences-modal"
|
28
28
|
data-concept-id={conceptId}
|
29
|
-
data-o-tracking-view="true"
|
30
29
|
>
|
31
30
|
<div className="n-myft-ui__preferences-modal__content">
|
32
31
|
<span className="o-forms-input o-forms-input--checkbox">
|
@@ -37,6 +36,7 @@ export default function InstantAlertsPreferencesModal({ flags, conceptId, visibl
|
|
37
36
|
name="receive-instant-alerts"
|
38
37
|
value="receive-instant-alerts"
|
39
38
|
data-component-id="myft-preferences-modal-checkbox"
|
39
|
+
data-trackable-context-concept_id={conceptId}
|
40
40
|
/>
|
41
41
|
<span className="o-forms-input__label n-myft-ui__preferences-modal__checkbox__message">
|
42
42
|
Get instant alerts for this topic
|
@@ -45,9 +45,9 @@ export default function InstantAlertsPreferencesModal({ flags, conceptId, visibl
|
|
45
45
|
</span>
|
46
46
|
|
47
47
|
<p data-component-id="myft-preferences-modal-list" className="n-myft-ui__preferences-modal__text"></p>
|
48
|
-
<a className="n-myft-ui__preferences-modal__text" href="/myft/alerts" data-trackable="pop-up-box|contact-preference">Manage your
|
48
|
+
<a className="n-myft-ui__preferences-modal__text" href="/myft/alerts" data-trackable="pop-up-box|contact-preference" data-trackable-context-concept_id={conceptId}>Manage your delivery channels here</a>
|
49
49
|
<span className="n-myft-ui__preferences-modal-error" data-component-id="myft-preference-modal-error"></span>
|
50
|
-
<button className="n-myft-ui__preferences-modal__remove-button" data-component-id="myft-preference-modal-remove" data-trackable="pop-up-box|remove-from-myFT">Remove from myFT</button>
|
50
|
+
<button className="n-myft-ui__preferences-modal__remove-button" data-component-id="myft-preference-modal-remove" data-trackable="pop-up-box|remove-from-myFT" data-trackable-context-concept_id={conceptId}>Remove from myFT</button>
|
51
51
|
</div>
|
52
52
|
</div>
|
53
53
|
);
|
@@ -41,8 +41,7 @@ function InstantAlertsPreferencesModal(_ref) {
|
|
41
41
|
{
|
42
42
|
className: 'n-myft-ui__preferences-modal ' + (visible ? 'n-myft-ui__preferences-modal--show' : ''),
|
43
43
|
'data-component-id': 'myft-preferences-modal',
|
44
|
-
'data-concept-id': conceptId
|
45
|
-
'data-o-tracking-view': 'true'
|
44
|
+
'data-concept-id': conceptId
|
46
45
|
},
|
47
46
|
_react2.default.createElement(
|
48
47
|
'div',
|
@@ -58,7 +57,8 @@ function InstantAlertsPreferencesModal(_ref) {
|
|
58
57
|
type: 'checkbox',
|
59
58
|
name: 'receive-instant-alerts',
|
60
59
|
value: 'receive-instant-alerts',
|
61
|
-
'data-component-id': 'myft-preferences-modal-checkbox'
|
60
|
+
'data-component-id': 'myft-preferences-modal-checkbox',
|
61
|
+
'data-trackable-context-concept_id': conceptId
|
62
62
|
}),
|
63
63
|
_react2.default.createElement(
|
64
64
|
'span',
|
@@ -70,13 +70,13 @@ function InstantAlertsPreferencesModal(_ref) {
|
|
70
70
|
_react2.default.createElement('p', { 'data-component-id': 'myft-preferences-modal-list', className: 'n-myft-ui__preferences-modal__text' }),
|
71
71
|
_react2.default.createElement(
|
72
72
|
'a',
|
73
|
-
{ className: 'n-myft-ui__preferences-modal__text', href: '/myft/alerts', 'data-trackable': 'pop-up-box|contact-preference' },
|
74
|
-
'Manage your
|
73
|
+
{ className: 'n-myft-ui__preferences-modal__text', href: '/myft/alerts', 'data-trackable': 'pop-up-box|contact-preference', 'data-trackable-context-concept_id': conceptId },
|
74
|
+
'Manage your delivery channels here'
|
75
75
|
),
|
76
76
|
_react2.default.createElement('span', { className: 'n-myft-ui__preferences-modal-error', 'data-component-id': 'myft-preference-modal-error' }),
|
77
77
|
_react2.default.createElement(
|
78
78
|
'button',
|
79
|
-
{ className: 'n-myft-ui__preferences-modal__remove-button', 'data-component-id': 'myft-preference-modal-remove', 'data-trackable': 'pop-up-box|remove-from-myFT' },
|
79
|
+
{ className: 'n-myft-ui__preferences-modal__remove-button', 'data-component-id': 'myft-preference-modal-remove', 'data-trackable': 'pop-up-box|remove-from-myFT', 'data-trackable-context-concept_id': conceptId },
|
80
80
|
'Remove from myFT'
|
81
81
|
)
|
82
82
|
)
|
package/package.json
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "@financial-times/n-myft-ui",
|
3
|
-
"version": "
|
3
|
+
"version": "31.0.0",
|
4
4
|
"description": "Client side component for interaction with myft",
|
5
5
|
"main": "server.js",
|
6
6
|
"scripts": {
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1",
|
8
8
|
"commit": "commit-wizard",
|
9
|
-
"prepare": "npx snyk protect || npx snyk protect -d || true"
|
10
|
-
"preinstall": "[ \"$INIT_CWD\" != \"$PWD\" ] || npm_config_yes=true npx check-engine"
|
9
|
+
"prepare": "npx snyk protect || npx snyk protect -d || true"
|
11
10
|
},
|
12
11
|
"repository": {
|
13
12
|
"type": "git",
|
@@ -20,48 +19,48 @@
|
|
20
19
|
},
|
21
20
|
"homepage": "https://github.com/Financial-Times/n-myft-ui#readme",
|
22
21
|
"devDependencies": {
|
23
|
-
"@financial-times/dotcom-build-base": "^8.1
|
24
|
-
"@financial-times/dotcom-build-code-splitting": "^8.1
|
25
|
-
"@financial-times/dotcom-build-js": "^8.1
|
26
|
-
"@financial-times/dotcom-build-sass": "^8.1
|
27
|
-
"@financial-times/dotcom-server-handlebars": "^8.1
|
28
|
-
"@financial-times/n-express": "^
|
29
|
-
"@financial-times/n-gage": "^
|
22
|
+
"@financial-times/dotcom-build-base": "^8.2.1",
|
23
|
+
"@financial-times/dotcom-build-code-splitting": "^8.2.1",
|
24
|
+
"@financial-times/dotcom-build-js": "^8.2.1",
|
25
|
+
"@financial-times/dotcom-build-sass": "^8.2.1",
|
26
|
+
"@financial-times/dotcom-server-handlebars": "^8.2.1",
|
27
|
+
"@financial-times/n-express": "^28.0.3",
|
28
|
+
"@financial-times/n-gage": "^9.0.1",
|
30
29
|
"ascii-table": "0.0.9",
|
31
30
|
"autoprefixer": "9.7.0",
|
32
31
|
"aws-sdk-mock": "4.5.0",
|
33
32
|
"babel-cli": "^6.26.0",
|
34
|
-
"babel-core": "^6.
|
33
|
+
"babel-core": "^6.26.3",
|
35
34
|
"babel-loader": "7.1.4",
|
36
35
|
"babel-plugin-add-module-exports": "^0.3.0",
|
37
36
|
"babel-plugin-transform-async-to-generator": "^6.24.1",
|
38
|
-
"babel-plugin-transform-es2015-classes": "^6.
|
39
|
-
"babel-plugin-transform-es2015-modules-commonjs": "^6.
|
37
|
+
"babel-plugin-transform-es2015-classes": "^6.24.1",
|
38
|
+
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
40
39
|
"babel-plugin-transform-runtime": "^6.23.0",
|
41
40
|
"babel-preset-env": "^1.7.0",
|
42
41
|
"babel-preset-es2015": "^6.6.0",
|
43
42
|
"babel-preset-react": "^6.24.1",
|
44
|
-
"babel-runtime": "^6.
|
45
|
-
"brotli": "^1.3.
|
46
|
-
"chai": "4.
|
43
|
+
"babel-runtime": "^6.26.0",
|
44
|
+
"brotli": "^1.3.3",
|
45
|
+
"chai": "4.3.8",
|
47
46
|
"chalk": "2.4.2",
|
48
|
-
"check-engine": "^1.
|
47
|
+
"check-engine": "^1.12.0",
|
49
48
|
"css-loader": "^0.23.1",
|
50
49
|
"denodeify": "^1.2.1",
|
51
50
|
"eslint": "6.5.1",
|
52
|
-
"eslint-plugin-react": "^7.33.
|
51
|
+
"eslint-plugin-react": "^7.33.2",
|
53
52
|
"extract-css-block-webpack-plugin": "^1.3.0",
|
54
53
|
"fetch-mock": "^5.0.3",
|
55
|
-
"handlebars": "^4.
|
56
|
-
"handlebars-loader": "^1.
|
54
|
+
"handlebars": "^4.7.8",
|
55
|
+
"handlebars-loader": "^1.7.3",
|
57
56
|
"http-server": "^0.11.1",
|
58
57
|
"hyperons": "^0.4.1",
|
59
58
|
"imports-loader": "0.8.0",
|
60
59
|
"inject-loader": "^4.0.1",
|
61
60
|
"karma": "4.4.1",
|
62
|
-
"karma-browserstack-launcher": "1.
|
61
|
+
"karma-browserstack-launcher": "1.6.0",
|
63
62
|
"karma-chai": "^0.1.0",
|
64
|
-
"karma-chrome-launcher": "3.
|
63
|
+
"karma-chrome-launcher": "3.2.0",
|
65
64
|
"karma-firefox-launcher": "^1.0.0",
|
66
65
|
"karma-html-reporter": "^0.2.6",
|
67
66
|
"karma-mocha": "^1.3.0",
|
@@ -71,22 +70,23 @@
|
|
71
70
|
"karma-viewport": "^1.0.9",
|
72
71
|
"karma-webpack": "^4.0.2",
|
73
72
|
"lintspaces-cli": "^0.7.0",
|
74
|
-
"lolex": "5.1.
|
73
|
+
"lolex": "5.1.2",
|
75
74
|
"mocha": "6.2.2",
|
76
75
|
"mockery": "2.1.0",
|
77
76
|
"node-fetch": "2.6.0",
|
78
77
|
"nodemon": "^1.9.2",
|
79
|
-
"npm-prepublish": "^1.2.
|
80
|
-
"pa11y-ci": "^
|
78
|
+
"npm-prepublish": "^1.2.3",
|
79
|
+
"pa11y-ci": "^3.0.1",
|
81
80
|
"postcss-loader": "^0.9.1",
|
81
|
+
"puppeteer": "^18.2.1",
|
82
82
|
"regenerator-runtime": "^0.13.3",
|
83
|
-
"sass": "^1.
|
83
|
+
"sass": "^1.68.0",
|
84
84
|
"semver": "6.3.0",
|
85
85
|
"sinon": "^7.1.0",
|
86
|
-
"sinon-chai": "^3.
|
87
|
-
"snyk": "^1.
|
86
|
+
"sinon-chai": "^3.7.0",
|
87
|
+
"snyk": "^1.1227.0",
|
88
88
|
"sucrase": "^3.34.0",
|
89
|
-
"webpack": "^4.
|
89
|
+
"webpack": "^4.47.0",
|
90
90
|
"webpack-cli": "^4.9.2"
|
91
91
|
},
|
92
92
|
"peerDependencies": {
|
@@ -104,8 +104,7 @@
|
|
104
104
|
"react": "^16.14.0"
|
105
105
|
},
|
106
106
|
"dependencies": {
|
107
|
-
"
|
108
|
-
"date-fns": "2.16.1",
|
107
|
+
"date-fns": "2.30.0",
|
109
108
|
"fetchres": "^1.7.2",
|
110
109
|
"form-serialize": "^0.7.2",
|
111
110
|
"ftdomdelegate": "^4.0.6",
|
@@ -115,12 +114,14 @@
|
|
115
114
|
"ready-state": "^2.0.5",
|
116
115
|
"superstore-sync": "^2.1.1"
|
117
116
|
},
|
117
|
+
"overrides": {
|
118
|
+
"puppeteer": "$puppeteer"
|
119
|
+
},
|
118
120
|
"volta": {
|
119
|
-
"node": "
|
120
|
-
"npm": "7.24.2"
|
121
|
+
"node": "18.18.0"
|
121
122
|
},
|
122
123
|
"engines": {
|
123
|
-
"node": "16.x",
|
124
|
+
"node": "16.x || 18.x",
|
124
125
|
"npm": "7.x || 8.x || 9.x"
|
125
126
|
},
|
126
127
|
"x-dash": {
|