@financial-times/qanda-ui 0.0.1-beta.24 → 0.0.1-beta.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/components/Calendar/Apps.js +5 -2
- package/dist/cjs/components/Calendar/index.js +2 -1
- package/dist/cjs/components/ErrorMessage/index.js +0 -3
- package/dist/cjs/components/Expander/index.js +2 -1
- package/dist/cjs/components/FloatingActionBar/index.js +4 -3
- package/dist/cjs/components/QandaBlock/index.js +3 -2
- package/dist/cjs/components/QandaContainer.js +3 -11
- package/dist/cjs/components/QuestionForm/index.js +5 -4
- package/dist/cjs/components/QuestionForm/messagesByUserType.js +5 -4
- package/dist/cjs/components/Survey/index.js +2 -30
- package/dist/cjs/utils/tracking.js +25 -2
- package/dist/esm/components/Calendar/Apps.js +5 -2
- package/dist/esm/components/Calendar/index.js +2 -1
- package/dist/esm/components/ErrorMessage/index.js +0 -3
- package/dist/esm/components/Expander/index.js +2 -1
- package/dist/esm/components/FloatingActionBar/index.js +4 -3
- package/dist/esm/components/QandaBlock/index.js +3 -2
- package/dist/esm/components/QandaContainer.js +3 -11
- package/dist/esm/components/QuestionForm/index.js +6 -5
- package/dist/esm/components/QuestionForm/messagesByUserType.js +5 -4
- package/dist/esm/components/Survey/index.js +2 -30
- package/dist/esm/utils/tracking.js +23 -1
- package/dist/qanda.scss +14 -16
- package/dist/types/components/QandaBlock/index.d.ts +1 -1
- package/dist/types/components/Survey/index.d.ts +2 -1
- package/dist/types/utils/tracking.d.ts +4 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
4
4
|
const qanda_1 = require("../../config/qanda");
|
|
5
|
+
const tracking_1 = require("../../utils/tracking");
|
|
5
6
|
function formatDateForIcs(date) {
|
|
6
7
|
return date.replace(/-|:|\.\d+/g, '');
|
|
7
8
|
}
|
|
@@ -11,7 +12,9 @@ function createIcsFile(title, startDateTime, endDateTime, url) {
|
|
|
11
12
|
`.trim();
|
|
12
13
|
return URL.createObjectURL(new Blob([icsContent], { type: 'title/calendar' }));
|
|
13
14
|
}
|
|
14
|
-
const CalendarLink = ({ href, children, }) =>
|
|
15
|
+
const CalendarLink = ({ href, children, }) => {
|
|
16
|
+
return ((0, jsx_runtime_1.jsx)("a", { href: href, target: "_blank", rel: "noopener noreferrer", role: "menuitem", "data-trackable": (0, tracking_1.trackingNS)('calendar-link'), className: "live-qa-calendar-list__item__link", children: children }));
|
|
17
|
+
};
|
|
15
18
|
function itemChildren(name, icon) {
|
|
16
19
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "live-qa-calendar-list__item__icon", children: icon }), (0, jsx_runtime_1.jsx)("span", { className: "live-qa-calendar-list__item__text", children: name })] }));
|
|
17
20
|
}
|
|
@@ -44,6 +47,6 @@ exports.default = apps.map(({ name, icon, getLink, isDownload }) => ({
|
|
|
44
47
|
icon,
|
|
45
48
|
link: ({ title, startDateTime, endDateTime, url, }) => {
|
|
46
49
|
const href = getLink({ title, startDateTime, endDateTime, url });
|
|
47
|
-
return isDownload ? ((0, jsx_runtime_1.jsx)("a", { href: href, download: "event.ics", role: "menuitem", "data-trackable":
|
|
50
|
+
return isDownload ? ((0, jsx_runtime_1.jsx)("a", { href: href, download: "event.ics", role: "menuitem", "data-trackable": (0, tracking_1.trackingNS)('calendar-link-download'), className: "live-qa-calendar-list__item__link", children: itemChildren(name, icon) })) : ((0, jsx_runtime_1.jsx)(CalendarLink, { href: href, children: itemChildren(name, icon) }));
|
|
48
51
|
},
|
|
49
52
|
}));
|
|
@@ -9,6 +9,7 @@ const react_1 = require("react");
|
|
|
9
9
|
const CalendarList_1 = __importDefault(require("./CalendarList"));
|
|
10
10
|
const comments_api_1 = require("../../services/comments-api");
|
|
11
11
|
const QandaProvider_1 = require("../QandaProvider");
|
|
12
|
+
const tracking_1 = require("../../utils/tracking");
|
|
12
13
|
function Calendar() {
|
|
13
14
|
const [dropDownVisible, setDropDownVisible] = (0, react_1.useState)(false);
|
|
14
15
|
const containerRef = (0, react_1.useRef)(null);
|
|
@@ -41,7 +42,7 @@ function Calendar() {
|
|
|
41
42
|
'aria-controls': 'menu',
|
|
42
43
|
id: 'live-qa-calendar-button-menu',
|
|
43
44
|
'data-testid': 'live-qa-calendar-button',
|
|
44
|
-
'data-trackable': '
|
|
45
|
+
'data-trackable': (0, tracking_1.trackingNS)('add-to-calendar-button'),
|
|
45
46
|
}, onClick: () => setDropDownVisible(!dropDownVisible) }), dropDownVisible && (0, jsx_runtime_1.jsx)(CalendarList_1.default, {})] })) }));
|
|
46
47
|
}
|
|
47
48
|
exports.default = Calendar;
|
|
@@ -42,10 +42,7 @@ function ErrorMessage({ error, storyId, errorMapping = {}, operation = 'not-spec
|
|
|
42
42
|
// Critical operation are tracked by the reliability service using AWS RUM
|
|
43
43
|
// We still log this to monitor untracked messages to the users.
|
|
44
44
|
(0, tracking_1.trackEvent)({
|
|
45
|
-
category: 'component',
|
|
46
|
-
action: 'act',
|
|
47
45
|
content: {
|
|
48
|
-
asset_type: 'article',
|
|
49
46
|
uuid: storyId,
|
|
50
47
|
},
|
|
51
48
|
trigger_action: operation,
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const o3_button_1 = require("@financial-times/o3-button");
|
|
6
|
+
const tracking_1 = require("../../utils/tracking");
|
|
6
7
|
// Generic debounce function
|
|
7
8
|
function debounce(func, delay) {
|
|
8
9
|
let timerId;
|
|
@@ -59,7 +60,7 @@ function Expander({ className = '', children = [], expandLabel = 'Expand', colla
|
|
|
59
60
|
const componentClassName = `${expandCollapseClass} ${className}`;
|
|
60
61
|
return ((0, jsx_runtime_1.jsxs)("div", { className: `${componentClassName}`, children: [(0, jsx_runtime_1.jsx)("div", { className: `expander__text ${requiresExpander ? 'expander__text--multiline' : ''}`, id: expanderContentID, ref: textRef, children: (0, jsx_runtime_1.jsx)(EnsureParagraph, { children: children }) }), requiresExpander && ((0, jsx_runtime_1.jsx)(o3_button_1.Button, { label: label, type: "ghost", theme: "neutral", icon: state === 'expanded' ? 'chevron-up' : 'chevron-down', iconOnly: false, iconPosition: "end", attributes: {
|
|
61
62
|
className: 'expander__link',
|
|
62
|
-
'data-trackable':
|
|
63
|
+
'data-trackable': (0, tracking_1.trackingNS)('expander'),
|
|
63
64
|
'data-trackable-context-action': label,
|
|
64
65
|
'aria-expanded': state === 'expanded' ? true : false,
|
|
65
66
|
'aria-controls': expanderContentID,
|
|
@@ -10,6 +10,7 @@ const comments_api_1 = require("../../services/comments-api");
|
|
|
10
10
|
const updateComments_1 = require("../../store/updateComments");
|
|
11
11
|
const react_1 = require("react");
|
|
12
12
|
const QandaProvider_1 = require("../QandaProvider");
|
|
13
|
+
const tracking_1 = require("../../utils/tracking");
|
|
13
14
|
function LiveIndicator() {
|
|
14
15
|
return ((0, jsx_runtime_1.jsx)("div", { className: "o-labels-indicator--live o3-type-label floating-action-bar__live-container", children: (0, jsx_runtime_1.jsx)("span", { className: "o-labels-indicator__status floating-action-bar__live-label", children: "Live" }) }));
|
|
15
16
|
}
|
|
@@ -44,14 +45,14 @@ function FloatingActionBar({ showLiveIndicator = true, }) {
|
|
|
44
45
|
dataTrackable: 'open_expert_drawer',
|
|
45
46
|
};
|
|
46
47
|
const view = showExpertView ? expertConfig : userConfig;
|
|
47
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "floating-action-bar__container", "data-trackable":
|
|
48
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "floating-action-bar__container", "data-trackable": (0, tracking_1.trackingNS)('floating-action-bar'), children: [(0, jsx_runtime_1.jsx)("div", { className: "floating-action-bar__fade-overlay" }), (0, jsx_runtime_1.jsxs)("div", { className: "floating-action-bar", "data-testid": "floating-action-bar", children: [showLiveIndicator && (0, jsx_runtime_1.jsx)(LiveIndicator, {}), (0, jsx_runtime_1.jsxs)("div", { className: "floating-action-bar__buttons", children: [(0, jsx_runtime_1.jsx)(o3_button_1.Button, { attributes: {
|
|
48
49
|
ariaLabel: view.descripton,
|
|
49
|
-
'data-trackable': view.dataTrackable,
|
|
50
|
+
'data-trackable': (0, tracking_1.trackingNS)(view.dataTrackable),
|
|
50
51
|
'data-trackable-context-action': view.descripton,
|
|
51
52
|
'data-testid': `floating-action-bar__${view.testIdSuffix}`,
|
|
52
53
|
}, label: view.descripton, type: "ghost", theme: "mono", icon: "edit", iconOnly: isMobile, onClick: view.onClick }), (0, jsx_runtime_1.jsx)(o3_button_1.Button, { attributes: {
|
|
53
54
|
ariaLabel: 'Back to top',
|
|
54
|
-
'data-trackable': 'back_to_top',
|
|
55
|
+
'data-trackable': (0, tracking_1.trackingNS)('back_to_top'),
|
|
55
56
|
'data-trackable-context-action': 'Back to top',
|
|
56
57
|
'data-testid': 'floating-action-bar__back-to-top-button',
|
|
57
58
|
}, label: "Back to top", type: "ghost", theme: "mono", icon: "scroll-to", iconOnly: isMobile, onClick: handleShowUpdates })] }), updatedComments?.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "floating-action-bar__updates-counter o3-type-detail", children: updatedComments.length }))] })] }));
|
|
@@ -10,6 +10,7 @@ require("../Expander/index");
|
|
|
10
10
|
const index_1 = __importDefault(require("../Expander/index"));
|
|
11
11
|
const Author_1 = __importDefault(require("../Author"));
|
|
12
12
|
const react_1 = require("react");
|
|
13
|
+
const tracking_1 = require("../../utils/tracking");
|
|
13
14
|
function renderTime(publishedDate) {
|
|
14
15
|
const date = new Date(publishedDate);
|
|
15
16
|
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
|
|
@@ -23,7 +24,7 @@ function interpolateColor(factor, colorStart = 'ccc1b7', colorEnd = '4d4845', al
|
|
|
23
24
|
const alpha = alphaStart + factor * (alphaEnd - alphaStart);
|
|
24
25
|
return `rgba(${rgb.join(', ')}, ${alpha})`;
|
|
25
26
|
}
|
|
26
|
-
function QandaBlock({ id, body, children, byline,
|
|
27
|
+
function QandaBlock({ id, body, children, byline, summary, showAnswerTime = false, }) {
|
|
27
28
|
(0, react_1.useEffect)(() => {
|
|
28
29
|
let currentBubble = null;
|
|
29
30
|
const factorRef = { current: 0 };
|
|
@@ -73,6 +74,6 @@ function QandaBlock({ id, body, children, byline, subtitle, showAnswerTime = fal
|
|
|
73
74
|
observer.disconnect();
|
|
74
75
|
};
|
|
75
76
|
}, []);
|
|
76
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "qanda-block", children: [(0, jsx_runtime_1.jsxs)("div", { className: "qanda-block__comment qanda-block__question", id: id, "data-testid": `qanda-block__question-${id}`, "data-trackable":
|
|
77
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "qanda-block", children: [(0, jsx_runtime_1.jsxs)("div", { className: "qanda-block__comment qanda-block__question", id: id, "data-testid": `qanda-block__question-${id}`, "data-trackable": (0, tracking_1.trackingNS)('question'), children: [summary && ((0, jsx_runtime_1.jsx)("div", { className: "o3-type-headline-sm qanda-block__question-summary", children: summary })), (0, jsx_runtime_1.jsx)("div", { className: "o3-type-body-highlight qanda-block__comment-byline", children: (0, jsx_runtime_1.jsx)(Byline_1.default, { structuredContent: byline, showEditedBy: false }) }), (0, jsx_runtime_1.jsx)("div", { className: "o3-type-body-base qanda-block__comment-text", children: (0, jsx_runtime_1.jsx)(index_1.default, { className: "qanda-block__text", expandLabel: "Expand question", collapseLabel: "Collapse question", id: id, children: (0, jsx_runtime_1.jsx)(RichText_1.default, { structuredContent: body.structured }) }) })] }, id), children?.map((child) => child.body && ((0, jsx_runtime_1.jsxs)("div", { className: "qanda-block__comment qanda-block__answer", "data-testid": `qanda-block__answer-${child.id}`, "data-trackable": (0, tracking_1.trackingNS)('answer'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "qanda-block__answer-header", children: [(0, jsx_runtime_1.jsx)("div", { className: "o3-type-body-highlight qanda-block__comment-byline", children: child.author ? ((0, jsx_runtime_1.jsx)(Author_1.default, { byline: child.byline, headshot: child.author.headshot, prefLabel: child.author.prefLabel, role: child.author.role, streamPage: child.author.streamPage })) : ((0, jsx_runtime_1.jsx)(Byline_1.default, { structuredContent: child.byline, showEditedBy: false })) }), showAnswerTime && ((0, jsx_runtime_1.jsx)("span", { className: "o3-type-detail", children: renderTime(child.publishedDate) }))] }), (0, jsx_runtime_1.jsx)("div", { className: "o3-type-body-base qanda-block__comment-text", children: (0, jsx_runtime_1.jsx)(index_1.default, { className: "qanda-block__text", expandLabel: "Expand answer", collapseLabel: "Collapse answer", id: id, children: (0, jsx_runtime_1.jsx)(RichText_1.default, { structuredContent: child.body.structured }) }) })] }, child.id)))] }));
|
|
77
78
|
}
|
|
78
79
|
exports.default = QandaBlock;
|
|
@@ -20,10 +20,10 @@ const QandaProvider_1 = require("./QandaProvider");
|
|
|
20
20
|
const o_tracking_1 = __importDefault(require("@financial-times/o-tracking"));
|
|
21
21
|
const comments_api_1 = require("../services/comments-api");
|
|
22
22
|
const qanda_1 = require("../config/qanda");
|
|
23
|
+
const tracking_1 = require("../utils/tracking");
|
|
23
24
|
function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
24
25
|
const { storyId, useStaging, commentsAPIUrl } = (0, react_1.useContext)(QandaProvider_1.QandaContext);
|
|
25
26
|
const dispatch = (0, react_redux_1.useDispatch)();
|
|
26
|
-
const [liveMessage, setLiveMessage] = (0, react_1.useState)('');
|
|
27
27
|
const { data, error, isLoading } = (0, comments_api_1.useGetQandAStreamQuery)({
|
|
28
28
|
storyId,
|
|
29
29
|
useStaging,
|
|
@@ -76,15 +76,7 @@ function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
|
76
76
|
selector: '.qanda-container',
|
|
77
77
|
getContextData: () => {
|
|
78
78
|
return {
|
|
79
|
-
|
|
80
|
-
name: 'liveqa',
|
|
81
|
-
type: 'container',
|
|
82
|
-
id: '663ab2ca-77ca-4b50-873d-1fd2ff21ff08',
|
|
83
|
-
},
|
|
84
|
-
content: {
|
|
85
|
-
asset_type: 'article',
|
|
86
|
-
uuid: storyId,
|
|
87
|
-
},
|
|
79
|
+
...tracking_1.baseTrackingData,
|
|
88
80
|
custom: [
|
|
89
81
|
{
|
|
90
82
|
name: 'status',
|
|
@@ -95,6 +87,6 @@ function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
|
95
87
|
},
|
|
96
88
|
});
|
|
97
89
|
}, [data, status]);
|
|
98
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "qanda-container",
|
|
90
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "qanda-container", children: [error && ((0, jsx_runtime_1.jsxs)("p", { children: ["We are not able to load ", qanda_1.PRODUCT_NAME, " at the moment. Please try again later. Error:", error] })), !isLoading && !error && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [status !== 'close' && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [showExpertView ? (0, jsx_runtime_1.jsx)(ExpertDrawer_1.default, {}) : (0, jsx_runtime_1.jsx)(QuestionForm_1.default, {}), (0, jsx_runtime_1.jsx)(CountdownTimer_1.default, { container: countdownTimerContainer })] })), status === 'pre-live' && (0, jsx_runtime_1.jsx)(Calendar_1.default, {}), (0, jsx_runtime_1.jsx)(Stream_1.default, { status: status }), (0, jsx_runtime_1.jsx)(Survey_1.default, { storyId: storyId, status: status }), (status === 'live' || (status === 'pre-live' && showExpertView)) && ((0, jsx_runtime_1.jsx)(FloatingActionBar_1.default, { showLiveIndicator: status === 'live' })), status !== 'close' && !showExpertView && ((0, jsx_runtime_1.jsx)(EmbedFormField_1.default, { container: embedFormFieldContainer }))] })), (0, jsx_runtime_1.jsx)("div", { "aria-live": "polite", "aria-atomic": "true", className: "o3-visually-hidden", children: ariaMessage })] }));
|
|
99
91
|
}
|
|
100
92
|
exports.default = QandaContainer;
|
|
@@ -78,8 +78,9 @@ function QuestionForm() {
|
|
|
78
78
|
if (updatedProfile?.displayName) {
|
|
79
79
|
// NB: we are using a component act event as analytics team can only support existing categories and actions at this time
|
|
80
80
|
(0, tracking_1.trackEvent)({
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
content: {
|
|
82
|
+
uuid: storyId,
|
|
83
|
+
},
|
|
83
84
|
trigger_action: 'success_set_displayname',
|
|
84
85
|
});
|
|
85
86
|
}
|
|
@@ -113,13 +114,13 @@ function QuestionForm() {
|
|
|
113
114
|
(0, jsx_runtime_1.jsxs)(Overlay_1.default, { title: "Ask a question", closeCallback: () => {
|
|
114
115
|
setNewDisplayName(null);
|
|
115
116
|
dispatch((0, questionSlice_1.closeForm)());
|
|
116
|
-
}, children: [profile.isSubscribed && ((0, jsx_runtime_1.jsx)("div", { className: "overlay__content-box overlay__form-box", "data-testid": "question-form-overlay", children: (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, "data-trackable": `
|
|
117
|
+
}, children: [profile.isSubscribed && ((0, jsx_runtime_1.jsx)("div", { className: "overlay__content-box overlay__form-box", "data-testid": "question-form-overlay", children: (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, "data-trackable": (0, tracking_1.trackingNS)(`submit_question_form_${postAnonymously ? 'anonymous' : 'displayname'}`), children: [(0, jsx_runtime_1.jsxs)("div", { className: "overlay__user-container", children: [!postAnonymously && profile?.displayName && ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)("span", { className: "overlay__user-container-display-name o3-type-body-highlight", children: [(0, jsx_runtime_1.jsx)("i", { className: "overlay__message-icon", style: { maskImage: 'var(--o3-icon-user)' } }), profile.displayName] }) })), !profile?.displayName && ((0, jsx_runtime_1.jsxs)("label", { for: "display-name", className: "question-form__displayname-input o-forms-field", children: [(0, jsx_runtime_1.jsx)("span", { className: "o-forms-title", children: (0, jsx_runtime_1.jsx)("span", { className: "o3-type-body-highlight", children: "Choose a display name" }) }), (0, jsx_runtime_1.jsxs)("span", { className: (0, classnames_1.default)([
|
|
117
118
|
'question-form__displayname__input',
|
|
118
119
|
'o-forms-input',
|
|
119
120
|
'o-forms-input--text',
|
|
120
121
|
{ 'o-forms-input--invalid': !!displayNameError },
|
|
121
122
|
]), children: [(0, jsx_runtime_1.jsx)("input", { className: "question-form__displayname__input__field o3-type-body-lg", id: "display-name", value: newDisplayName || '', onChange: (e) => setNewDisplayName(e.currentTarget.value), type: postAnonymously ? 'password' : 'text', "aria-invalid": displayNameError ? 'true' : 'false', "aria-errormessage": displayNameError ??
|
|
122
|
-
'question_form__displayname-error-message' }), displayNameError && ((0, jsx_runtime_1.jsx)("span", { className: "question-form__displayname__input__error o3-type-detail", id: "question_form__displayname-error-message", children: (0, jsx_runtime_1.jsx)("span", { children: displayNameError }) }))] })] }))] }), (0, jsx_runtime_1.jsx)("div", { className: "o-forms-field", children: (0, jsx_runtime_1.jsxs)("label", { className: "o-forms-input o-forms-input--checkbox", htmlFor: "post-anonymously", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", name: "post-anonymously", id: "post-anonymously", value: "true", onChange: handleHideDisplayName, "data-trackable-context-action": `Post anonymously ${postAnonymously ? 'off' : 'on'}`, "data-trackable": `question-form__post_anonymously-${postAnonymously ? 'off' : 'on'}` }), (0, jsx_runtime_1.jsx)("span", { className: "o-forms-input__label", children: "Post anonymously (optional)" })] }) }), (0, jsx_runtime_1.jsxs)("label", { for: "question-text", class: "o-forms-field question-form__question__input", children: [(0, jsx_runtime_1.jsx)("span", { class: "o-forms-title", children: (0, jsx_runtime_1.jsx)("span", { class: "o3-type-body-highlight", children: "Enter your question" }) }), (0, jsx_runtime_1.jsx)("span", { class: "o-forms-input o-forms-input--textarea", children: (0, jsx_runtime_1.jsx)("textarea", { id: "question-text", name: "question", value: question, onChange: (e) => dispatch((0, questionSlice_1.updateQuestion)(e.currentTarget.value)), "aria-label": "Your question", placeholder: "Type your question", maxLength: maxQuestionLength, "aria-invalid": error ? 'true' : undefined, "aria-errormessage": "question-form-error-message" }) })] }), (0, jsx_runtime_1.jsx)("span", { className: "o3-type-detail", children: "Questions must be at least 20 characters long." }), (0, jsx_runtime_1.jsx)(o3_button_1.Button, { attributes: {
|
|
123
|
+
'question_form__displayname-error-message' }), displayNameError && ((0, jsx_runtime_1.jsx)("span", { className: "question-form__displayname__input__error o3-type-detail", id: "question_form__displayname-error-message", children: (0, jsx_runtime_1.jsx)("span", { children: displayNameError }) }))] })] }))] }), (0, jsx_runtime_1.jsx)("div", { className: "o-forms-field", children: (0, jsx_runtime_1.jsxs)("label", { className: "o-forms-input o-forms-input--checkbox", htmlFor: "post-anonymously", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", name: "post-anonymously", id: "post-anonymously", value: "true", onChange: handleHideDisplayName, "data-trackable-context-action": `Post anonymously ${postAnonymously ? 'off' : 'on'}`, "data-trackable": (0, tracking_1.trackingNS)(`question-form__post_anonymously-${postAnonymously ? 'off' : 'on'}`) }), (0, jsx_runtime_1.jsx)("span", { className: "o-forms-input__label", children: "Post anonymously (optional)" })] }) }), (0, jsx_runtime_1.jsxs)("label", { for: "question-text", class: "o-forms-field question-form__question__input", children: [(0, jsx_runtime_1.jsx)("span", { class: "o-forms-title", children: (0, jsx_runtime_1.jsx)("span", { class: "o3-type-body-highlight", children: "Enter your question" }) }), (0, jsx_runtime_1.jsx)("span", { class: "o-forms-input o-forms-input--textarea", children: (0, jsx_runtime_1.jsx)("textarea", { id: "question-text", name: "question", value: question, onChange: (e) => dispatch((0, questionSlice_1.updateQuestion)(e.currentTarget.value)), "aria-label": "Your question", placeholder: "Type your question", maxLength: maxQuestionLength, "aria-invalid": error ? 'true' : undefined, "aria-errormessage": "question-form-error-message" }) })] }), (0, jsx_runtime_1.jsx)("span", { className: "o3-type-detail", children: "Questions must be at least 20 characters long." }), (0, jsx_runtime_1.jsx)(o3_button_1.Button, { attributes: {
|
|
123
124
|
className: 'overlay__submit-button',
|
|
124
125
|
type: 'submit',
|
|
125
126
|
disabled: !submitEnabled,
|
|
@@ -5,6 +5,7 @@ exports.getTitleByUser = getTitleByUser;
|
|
|
5
5
|
exports.getTextByUser = getTextByUser;
|
|
6
6
|
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
7
7
|
const qanda_1 = require("../../config/qanda");
|
|
8
|
+
const tracking_1 = require("../../utils/tracking");
|
|
8
9
|
exports.SIGN_IN_URL = 'https://www.ft.com/login';
|
|
9
10
|
exports.SUBSCRIBE_URL = 'https://subs.ft.com/products';
|
|
10
11
|
exports.COMMUNITY_GUIDELINES_URL = 'https://help.ft.com/help/article-queries/commenting-on-an-article/commenting-guidelines';
|
|
@@ -21,14 +22,14 @@ function getTitleByUser(profile) {
|
|
|
21
22
|
}
|
|
22
23
|
function getTextByUser(profile) {
|
|
23
24
|
if (profile.isSubscribed) {
|
|
24
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Keep your comments respectful and easy to understand for our global audience. By submitting, you agree to follow our", ' ', (0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable":
|
|
25
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Keep your comments respectful and easy to understand for our global audience. By submitting, you agree to follow our", ' ', (0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable": (0, tracking_1.trackingNS)('question-form__community-guidelines'), "data-trackable-context-action": "Community guidelines", href: exports.COMMUNITY_GUIDELINES_URL, target: "_parent", children: "community guidelines" }), ' ', "and", ' ', (0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable": (0, tracking_1.trackingNS)('question-form__terms-and-conditions'), "data-trackable-context-action": "Terms and conditions", href: exports.TERMS_AND_CONDITIONS_URL, target: "_parent", children: "terms" }), "."] }));
|
|
25
26
|
}
|
|
26
27
|
if (profile.isTrialist) {
|
|
27
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["View our full", ' ', (0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable":
|
|
28
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["View our full", ' ', (0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable": (0, tracking_1.trackingNS)('question-form__subscribe-trialist'), "data-trackable-context-action": "Subscribe", href: exports.SUBSCRIBE_URL, target: "_parent", children: "subscription packages" }), ' ', "to join the conversation."] }));
|
|
28
29
|
}
|
|
29
30
|
if (profile.isRegistered) {
|
|
30
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable":
|
|
31
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable": (0, tracking_1.trackingNS)('question-form__subscribe-registered'), "data-trackable-context-action": "Subscribe", href: exports.SUBSCRIBE_URL, target: "_parent", children: "Subscribe" }), ' ', "to join the conversation."] }));
|
|
31
32
|
}
|
|
32
33
|
// Anonymous users
|
|
33
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Please", ' ', (0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable":
|
|
34
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Please", ' ', (0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable": (0, tracking_1.trackingNS)('question-form__sign-in-anonymous'), "data-trackable-context-action": "Sign in", href: exports.SIGN_IN_URL, target: "_parent", children: "sign in" }), ' ', "or", ' ', (0, jsx_runtime_1.jsx)("a", { className: "message-box__content-link", "data-trackable": (0, tracking_1.trackingNS)('question-form__subscribe-anonymous'), "data-trackable-context-action": "Subscribe", href: exports.SUBSCRIBE_URL, target: "_parent", children: "subscribe" }), ' ', "to join the conversation."] }));
|
|
34
35
|
}
|
|
@@ -1,36 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
4
|
+
const tracking_1 = require("../../utils/tracking");
|
|
4
5
|
function Survey({ storyId, status }) {
|
|
5
|
-
|
|
6
|
-
const event = new CustomEvent('oTracking.event', {
|
|
7
|
-
detail: trackingData,
|
|
8
|
-
bubbles: true,
|
|
9
|
-
});
|
|
10
|
-
document.body.dispatchEvent(event);
|
|
11
|
-
};
|
|
12
|
-
const handleClick = () => {
|
|
13
|
-
trackEvent({
|
|
14
|
-
category: 'component',
|
|
15
|
-
component: {
|
|
16
|
-
name: 'liveqa',
|
|
17
|
-
type: 'container',
|
|
18
|
-
id: '663ab2ca-77ca-4b50-873d-1fd2ff21ff08',
|
|
19
|
-
},
|
|
20
|
-
action: 'act',
|
|
21
|
-
trigger_action: 'liveqa_survey_open',
|
|
22
|
-
content: {
|
|
23
|
-
asset_type: 'article',
|
|
24
|
-
uuid: storyId,
|
|
25
|
-
},
|
|
26
|
-
custom: [
|
|
27
|
-
{
|
|
28
|
-
name: 'status',
|
|
29
|
-
value: status,
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
return ((0, jsx_runtime_1.jsx)("div", { className: "o-message o-message--action o-message--inform o-message--survey", style: { marginBottom: 'var(--o3-spacing-l)' }, "data-o-message-close": "false", "data-o-component": "o-message", children: (0, jsx_runtime_1.jsx)("div", { className: "o-message__container", children: (0, jsx_runtime_1.jsxs)("div", { className: "o-message__content", children: [(0, jsx_runtime_1.jsx)("p", { className: "o-message__content-main", style: { fontSize: 'var(--o3-type-body-base-font-size)' }, children: "How was your experience?" }), (0, jsx_runtime_1.jsx)("div", { className: "o-message__actions", children: (0, jsx_runtime_1.jsx)("a", { href: `https://www.feedback.ft.com/c/a/6HTDVvrHSyaKLZ5281McAo?content_id=${storyId}&qa_status=${status}`, onClick: handleClick, className: "o-message__actions__primary", "data-trackable": "liveqa_survey_link", children: "Share your feedback" }) })] }) }) }));
|
|
6
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "o-message o-message--action o-message--inform o-message--survey", style: { marginBottom: 'var(--o3-spacing-l)' }, "data-o-message-close": "false", "data-o-component": "o-message", children: (0, jsx_runtime_1.jsx)("div", { className: "o-message__container", children: (0, jsx_runtime_1.jsxs)("div", { className: "o-message__content", children: [(0, jsx_runtime_1.jsx)("p", { className: "o-message__content-main", style: { fontSize: 'var(--o3-type-body-base-font-size)' }, children: "How was your experience?" }), (0, jsx_runtime_1.jsx)("div", { className: "o-message__actions", children: (0, jsx_runtime_1.jsx)("a", { href: `https://www.feedback.ft.com/c/a/6HTDVvrHSyaKLZ5281McAo?content_id=${storyId}&qa_status=${status}`, className: "o-message__actions__primary", "data-trackable": (0, tracking_1.trackingNS)('survey_link'), children: "Share your feedback" }) })] }) }) }));
|
|
35
7
|
}
|
|
36
8
|
exports.default = Survey;
|
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.trackEvent = void 0;
|
|
4
|
-
|
|
3
|
+
exports.trackEvent = exports.baseTrackingData = void 0;
|
|
4
|
+
exports.trackingNS = trackingNS;
|
|
5
|
+
const trackingNamespace = 'askanexpert_';
|
|
6
|
+
function trackingNS(string) {
|
|
7
|
+
return trackingNamespace + string;
|
|
8
|
+
}
|
|
9
|
+
exports.baseTrackingData = {
|
|
10
|
+
category: 'component',
|
|
11
|
+
action: 'act',
|
|
12
|
+
component: {
|
|
13
|
+
name: 'askanexpert',
|
|
14
|
+
type: 'container',
|
|
15
|
+
id: '663ab2ca-77ca-4b50-873d-1fd2ff21ff08',
|
|
16
|
+
},
|
|
17
|
+
content: {
|
|
18
|
+
asset_type: 'article',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
const trackEvent = (customTrackingData) => {
|
|
22
|
+
// Merge the base tracking data with the provided tracking data
|
|
23
|
+
const trackingData = {
|
|
24
|
+
...exports.baseTrackingData,
|
|
25
|
+
...customTrackingData,
|
|
26
|
+
trigger_action: trackingNamespace + customTrackingData.trigger_action,
|
|
27
|
+
};
|
|
5
28
|
const event = new CustomEvent('oTracking.event', {
|
|
6
29
|
detail: trackingData,
|
|
7
30
|
bubbles: true,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { PRODUCT_NAME } from '../../config/qanda';
|
|
3
|
+
import { trackingNS } from '../../utils/tracking';
|
|
3
4
|
function formatDateForIcs(date) {
|
|
4
5
|
return date.replace(/-|:|\.\d+/g, '');
|
|
5
6
|
}
|
|
@@ -9,7 +10,9 @@ function createIcsFile(title, startDateTime, endDateTime, url) {
|
|
|
9
10
|
`.trim();
|
|
10
11
|
return URL.createObjectURL(new Blob([icsContent], { type: 'title/calendar' }));
|
|
11
12
|
}
|
|
12
|
-
const CalendarLink = ({ href, children, }) =>
|
|
13
|
+
const CalendarLink = ({ href, children, }) => {
|
|
14
|
+
return (_jsx("a", { href: href, target: "_blank", rel: "noopener noreferrer", role: "menuitem", "data-trackable": trackingNS('calendar-link'), className: "live-qa-calendar-list__item__link", children: children }));
|
|
15
|
+
};
|
|
13
16
|
function itemChildren(name, icon) {
|
|
14
17
|
return (_jsxs(_Fragment, { children: [_jsx("span", { className: "live-qa-calendar-list__item__icon", children: icon }), _jsx("span", { className: "live-qa-calendar-list__item__text", children: name })] }));
|
|
15
18
|
}
|
|
@@ -42,6 +45,6 @@ export default apps.map(({ name, icon, getLink, isDownload }) => ({
|
|
|
42
45
|
icon,
|
|
43
46
|
link: ({ title, startDateTime, endDateTime, url, }) => {
|
|
44
47
|
const href = getLink({ title, startDateTime, endDateTime, url });
|
|
45
|
-
return isDownload ? (_jsx("a", { href: href, download: "event.ics", role: "menuitem", "data-trackable":
|
|
48
|
+
return isDownload ? (_jsx("a", { href: href, download: "event.ics", role: "menuitem", "data-trackable": trackingNS('calendar-link-download'), className: "live-qa-calendar-list__item__link", children: itemChildren(name, icon) })) : (_jsx(CalendarLink, { href: href, children: itemChildren(name, icon) }));
|
|
46
49
|
},
|
|
47
50
|
}));
|
|
@@ -4,6 +4,7 @@ import { useState, useRef, useEffect, useContext } from 'react';
|
|
|
4
4
|
import CalendarList from './CalendarList';
|
|
5
5
|
import { useGetQandAStreamQuery } from '../../services/comments-api';
|
|
6
6
|
import { QandaContext } from '../QandaProvider';
|
|
7
|
+
import { trackingNS } from '../../utils/tracking';
|
|
7
8
|
function Calendar() {
|
|
8
9
|
const [dropDownVisible, setDropDownVisible] = useState(false);
|
|
9
10
|
const containerRef = useRef(null);
|
|
@@ -36,7 +37,7 @@ function Calendar() {
|
|
|
36
37
|
'aria-controls': 'menu',
|
|
37
38
|
id: 'live-qa-calendar-button-menu',
|
|
38
39
|
'data-testid': 'live-qa-calendar-button',
|
|
39
|
-
'data-trackable': '
|
|
40
|
+
'data-trackable': trackingNS('add-to-calendar-button'),
|
|
40
41
|
}, onClick: () => setDropDownVisible(!dropDownVisible) }), dropDownVisible && _jsx(CalendarList, {})] })) }));
|
|
41
42
|
}
|
|
42
43
|
export default Calendar;
|
|
@@ -36,10 +36,7 @@ export default function ErrorMessage({ error, storyId, errorMapping = {}, operat
|
|
|
36
36
|
// Critical operation are tracked by the reliability service using AWS RUM
|
|
37
37
|
// We still log this to monitor untracked messages to the users.
|
|
38
38
|
trackEvent({
|
|
39
|
-
category: 'component',
|
|
40
|
-
action: 'act',
|
|
41
39
|
content: {
|
|
42
|
-
asset_type: 'article',
|
|
43
40
|
uuid: storyId,
|
|
44
41
|
},
|
|
45
42
|
trigger_action: operation,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { useState, useRef, useEffect } from 'react';
|
|
3
3
|
import { Button } from '@financial-times/o3-button';
|
|
4
|
+
import { trackingNS } from '../../utils/tracking';
|
|
4
5
|
// Generic debounce function
|
|
5
6
|
function debounce(func, delay) {
|
|
6
7
|
let timerId;
|
|
@@ -57,7 +58,7 @@ function Expander({ className = '', children = [], expandLabel = 'Expand', colla
|
|
|
57
58
|
const componentClassName = `${expandCollapseClass} ${className}`;
|
|
58
59
|
return (_jsxs("div", { className: `${componentClassName}`, children: [_jsx("div", { className: `expander__text ${requiresExpander ? 'expander__text--multiline' : ''}`, id: expanderContentID, ref: textRef, children: _jsx(EnsureParagraph, { children: children }) }), requiresExpander && (_jsx(Button, { label: label, type: "ghost", theme: "neutral", icon: state === 'expanded' ? 'chevron-up' : 'chevron-down', iconOnly: false, iconPosition: "end", attributes: {
|
|
59
60
|
className: 'expander__link',
|
|
60
|
-
'data-trackable':
|
|
61
|
+
'data-trackable': trackingNS('expander'),
|
|
61
62
|
'data-trackable-context-action': label,
|
|
62
63
|
'aria-expanded': state === 'expanded' ? true : false,
|
|
63
64
|
'aria-controls': expanderContentID,
|
|
@@ -8,6 +8,7 @@ import { useUpdatedComments } from '../../services/comments-api';
|
|
|
8
8
|
import { updateComments } from '../../store/updateComments';
|
|
9
9
|
import { useContext } from 'react';
|
|
10
10
|
import { QandaContext } from '../QandaProvider';
|
|
11
|
+
import { trackingNS } from '../../utils/tracking';
|
|
11
12
|
function LiveIndicator() {
|
|
12
13
|
return (_jsx("div", { className: "o-labels-indicator--live o3-type-label floating-action-bar__live-container", children: _jsx("span", { className: "o-labels-indicator__status floating-action-bar__live-label", children: "Live" }) }));
|
|
13
14
|
}
|
|
@@ -42,14 +43,14 @@ function FloatingActionBar({ showLiveIndicator = true, }) {
|
|
|
42
43
|
dataTrackable: 'open_expert_drawer',
|
|
43
44
|
};
|
|
44
45
|
const view = showExpertView ? expertConfig : userConfig;
|
|
45
|
-
return (_jsxs("div", { className: "floating-action-bar__container", "data-trackable":
|
|
46
|
+
return (_jsxs("div", { className: "floating-action-bar__container", "data-trackable": trackingNS('floating-action-bar'), children: [_jsx("div", { className: "floating-action-bar__fade-overlay" }), _jsxs("div", { className: "floating-action-bar", "data-testid": "floating-action-bar", children: [showLiveIndicator && _jsx(LiveIndicator, {}), _jsxs("div", { className: "floating-action-bar__buttons", children: [_jsx(Button, { attributes: {
|
|
46
47
|
ariaLabel: view.descripton,
|
|
47
|
-
'data-trackable': view.dataTrackable,
|
|
48
|
+
'data-trackable': trackingNS(view.dataTrackable),
|
|
48
49
|
'data-trackable-context-action': view.descripton,
|
|
49
50
|
'data-testid': `floating-action-bar__${view.testIdSuffix}`,
|
|
50
51
|
}, label: view.descripton, type: "ghost", theme: "mono", icon: "edit", iconOnly: isMobile, onClick: view.onClick }), _jsx(Button, { attributes: {
|
|
51
52
|
ariaLabel: 'Back to top',
|
|
52
|
-
'data-trackable': 'back_to_top',
|
|
53
|
+
'data-trackable': trackingNS('back_to_top'),
|
|
53
54
|
'data-trackable-context-action': 'Back to top',
|
|
54
55
|
'data-testid': 'floating-action-bar__back-to-top-button',
|
|
55
56
|
}, label: "Back to top", type: "ghost", theme: "mono", icon: "scroll-to", iconOnly: isMobile, onClick: handleShowUpdates })] }), updatedComments?.length > 0 && (_jsx("div", { className: "floating-action-bar__updates-counter o3-type-detail", children: updatedComments.length }))] })] }));
|
|
@@ -5,6 +5,7 @@ import '../Expander/index';
|
|
|
5
5
|
import Expander from '../Expander/index';
|
|
6
6
|
import Author from '../Author';
|
|
7
7
|
import { useEffect } from 'react';
|
|
8
|
+
import { trackingNS } from '../../utils/tracking';
|
|
8
9
|
function renderTime(publishedDate) {
|
|
9
10
|
const date = new Date(publishedDate);
|
|
10
11
|
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
|
|
@@ -18,7 +19,7 @@ function interpolateColor(factor, colorStart = 'ccc1b7', colorEnd = '4d4845', al
|
|
|
18
19
|
const alpha = alphaStart + factor * (alphaEnd - alphaStart);
|
|
19
20
|
return `rgba(${rgb.join(', ')}, ${alpha})`;
|
|
20
21
|
}
|
|
21
|
-
function QandaBlock({ id, body, children, byline,
|
|
22
|
+
function QandaBlock({ id, body, children, byline, summary, showAnswerTime = false, }) {
|
|
22
23
|
useEffect(() => {
|
|
23
24
|
let currentBubble = null;
|
|
24
25
|
const factorRef = { current: 0 };
|
|
@@ -68,6 +69,6 @@ function QandaBlock({ id, body, children, byline, subtitle, showAnswerTime = fal
|
|
|
68
69
|
observer.disconnect();
|
|
69
70
|
};
|
|
70
71
|
}, []);
|
|
71
|
-
return (_jsxs("div", { className: "qanda-block", children: [_jsxs("div", { className: "qanda-block__comment qanda-block__question", id: id, "data-testid": `qanda-block__question-${id}`, "data-trackable":
|
|
72
|
+
return (_jsxs("div", { className: "qanda-block", children: [_jsxs("div", { className: "qanda-block__comment qanda-block__question", id: id, "data-testid": `qanda-block__question-${id}`, "data-trackable": trackingNS('question'), children: [summary && (_jsx("div", { className: "o3-type-headline-sm qanda-block__question-summary", children: summary })), _jsx("div", { className: "o3-type-body-highlight qanda-block__comment-byline", children: _jsx(Byline, { structuredContent: byline, showEditedBy: false }) }), _jsx("div", { className: "o3-type-body-base qanda-block__comment-text", children: _jsx(Expander, { className: "qanda-block__text", expandLabel: "Expand question", collapseLabel: "Collapse question", id: id, children: _jsx(RichText, { structuredContent: body.structured }) }) })] }, id), children?.map((child) => child.body && (_jsxs("div", { className: "qanda-block__comment qanda-block__answer", "data-testid": `qanda-block__answer-${child.id}`, "data-trackable": trackingNS('answer'), children: [_jsxs("div", { className: "qanda-block__answer-header", children: [_jsx("div", { className: "o3-type-body-highlight qanda-block__comment-byline", children: child.author ? (_jsx(Author, { byline: child.byline, headshot: child.author.headshot, prefLabel: child.author.prefLabel, role: child.author.role, streamPage: child.author.streamPage })) : (_jsx(Byline, { structuredContent: child.byline, showEditedBy: false })) }), showAnswerTime && (_jsx("span", { className: "o3-type-detail", children: renderTime(child.publishedDate) }))] }), _jsx("div", { className: "o3-type-body-base qanda-block__comment-text", children: _jsx(Expander, { className: "qanda-block__text", expandLabel: "Expand answer", collapseLabel: "Collapse answer", id: id, children: _jsx(RichText, { structuredContent: child.body.structured }) }) })] }, child.id)))] }));
|
|
72
73
|
}
|
|
73
74
|
export default QandaBlock;
|
|
@@ -15,10 +15,10 @@ import { QandaContext } from './QandaProvider';
|
|
|
15
15
|
import oTracking from '@financial-times/o-tracking';
|
|
16
16
|
import { useGetQandAStreamQuery, useUpdatedQA, useGetUserRolesQuery, nextCommentsApi, } from '../services/comments-api';
|
|
17
17
|
import { PRODUCT_NAME } from '../config/qanda';
|
|
18
|
+
import { baseTrackingData } from '../utils/tracking';
|
|
18
19
|
function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
19
20
|
const { storyId, useStaging, commentsAPIUrl } = useContext(QandaContext);
|
|
20
21
|
const dispatch = useDispatch();
|
|
21
|
-
const [liveMessage, setLiveMessage] = useState('');
|
|
22
22
|
const { data, error, isLoading } = useGetQandAStreamQuery({
|
|
23
23
|
storyId,
|
|
24
24
|
useStaging,
|
|
@@ -71,15 +71,7 @@ function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
|
71
71
|
selector: '.qanda-container',
|
|
72
72
|
getContextData: () => {
|
|
73
73
|
return {
|
|
74
|
-
|
|
75
|
-
name: 'liveqa',
|
|
76
|
-
type: 'container',
|
|
77
|
-
id: '663ab2ca-77ca-4b50-873d-1fd2ff21ff08',
|
|
78
|
-
},
|
|
79
|
-
content: {
|
|
80
|
-
asset_type: 'article',
|
|
81
|
-
uuid: storyId,
|
|
82
|
-
},
|
|
74
|
+
...baseTrackingData,
|
|
83
75
|
custom: [
|
|
84
76
|
{
|
|
85
77
|
name: 'status',
|
|
@@ -90,6 +82,6 @@ function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
|
90
82
|
},
|
|
91
83
|
});
|
|
92
84
|
}, [data, status]);
|
|
93
|
-
return (_jsxs("div", { className: "qanda-container",
|
|
85
|
+
return (_jsxs("div", { className: "qanda-container", children: [error && (_jsxs("p", { children: ["We are not able to load ", PRODUCT_NAME, " at the moment. Please try again later. Error:", error] })), !isLoading && !error && (_jsxs(_Fragment, { children: [status !== 'close' && (_jsxs(_Fragment, { children: [showExpertView ? _jsx(ExpertDrawer, {}) : _jsx(QuestionForm, {}), _jsx(CountdownTimer, { container: countdownTimerContainer })] })), status === 'pre-live' && _jsx(Calendar, {}), _jsx(Stream, { status: status }), _jsx(Survey, { storyId: storyId, status: status }), (status === 'live' || (status === 'pre-live' && showExpertView)) && (_jsx(FloatingActionBar, { showLiveIndicator: status === 'live' })), status !== 'close' && !showExpertView && (_jsx(EmbedFormField, { container: embedFormFieldContainer }))] })), _jsx("div", { "aria-live": "polite", "aria-atomic": "true", className: "o3-visually-hidden", children: ariaMessage })] }));
|
|
94
86
|
}
|
|
95
87
|
export default QandaContainer;
|
|
@@ -13,7 +13,7 @@ import ErrorMessage from '../ErrorMessage';
|
|
|
13
13
|
import { getUserProfile } from '../../store/user';
|
|
14
14
|
import validateDisplayName from '../../utils/validate-display-name';
|
|
15
15
|
import { getTitleByUser, getTextByUser } from './messagesByUserType';
|
|
16
|
-
import { trackEvent } from '../../utils/tracking';
|
|
16
|
+
import { trackEvent, trackingNS } from '../../utils/tracking';
|
|
17
17
|
export default function QuestionForm() {
|
|
18
18
|
const dispatch = useDispatch();
|
|
19
19
|
const { storyId, useStaging, commentsAPIUrl, maxQuestionLength } = useContext(QandaContext);
|
|
@@ -72,8 +72,9 @@ export default function QuestionForm() {
|
|
|
72
72
|
if (updatedProfile?.displayName) {
|
|
73
73
|
// NB: we are using a component act event as analytics team can only support existing categories and actions at this time
|
|
74
74
|
trackEvent({
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
content: {
|
|
76
|
+
uuid: storyId,
|
|
77
|
+
},
|
|
77
78
|
trigger_action: 'success_set_displayname',
|
|
78
79
|
});
|
|
79
80
|
}
|
|
@@ -107,13 +108,13 @@ export default function QuestionForm() {
|
|
|
107
108
|
_jsxs(Overlay, { title: "Ask a question", closeCallback: () => {
|
|
108
109
|
setNewDisplayName(null);
|
|
109
110
|
dispatch(closeForm());
|
|
110
|
-
}, children: [profile.isSubscribed && (_jsx("div", { className: "overlay__content-box overlay__form-box", "data-testid": "question-form-overlay", children: _jsxs("form", { onSubmit: handleSubmit, "data-trackable": `
|
|
111
|
+
}, children: [profile.isSubscribed && (_jsx("div", { className: "overlay__content-box overlay__form-box", "data-testid": "question-form-overlay", children: _jsxs("form", { onSubmit: handleSubmit, "data-trackable": trackingNS(`submit_question_form_${postAnonymously ? 'anonymous' : 'displayname'}`), children: [_jsxs("div", { className: "overlay__user-container", children: [!postAnonymously && profile?.displayName && (_jsx(_Fragment, { children: _jsxs("span", { className: "overlay__user-container-display-name o3-type-body-highlight", children: [_jsx("i", { className: "overlay__message-icon", style: { maskImage: 'var(--o3-icon-user)' } }), profile.displayName] }) })), !profile?.displayName && (_jsxs("label", { for: "display-name", className: "question-form__displayname-input o-forms-field", children: [_jsx("span", { className: "o-forms-title", children: _jsx("span", { className: "o3-type-body-highlight", children: "Choose a display name" }) }), _jsxs("span", { className: classNames([
|
|
111
112
|
'question-form__displayname__input',
|
|
112
113
|
'o-forms-input',
|
|
113
114
|
'o-forms-input--text',
|
|
114
115
|
{ 'o-forms-input--invalid': !!displayNameError },
|
|
115
116
|
]), children: [_jsx("input", { className: "question-form__displayname__input__field o3-type-body-lg", id: "display-name", value: newDisplayName || '', onChange: (e) => setNewDisplayName(e.currentTarget.value), type: postAnonymously ? 'password' : 'text', "aria-invalid": displayNameError ? 'true' : 'false', "aria-errormessage": displayNameError ??
|
|
116
|
-
'question_form__displayname-error-message' }), displayNameError && (_jsx("span", { className: "question-form__displayname__input__error o3-type-detail", id: "question_form__displayname-error-message", children: _jsx("span", { children: displayNameError }) }))] })] }))] }), _jsx("div", { className: "o-forms-field", children: _jsxs("label", { className: "o-forms-input o-forms-input--checkbox", htmlFor: "post-anonymously", children: [_jsx("input", { type: "checkbox", name: "post-anonymously", id: "post-anonymously", value: "true", onChange: handleHideDisplayName, "data-trackable-context-action": `Post anonymously ${postAnonymously ? 'off' : 'on'}`, "data-trackable": `question-form__post_anonymously-${postAnonymously ? 'off' : 'on'}` }), _jsx("span", { className: "o-forms-input__label", children: "Post anonymously (optional)" })] }) }), _jsxs("label", { for: "question-text", class: "o-forms-field question-form__question__input", children: [_jsx("span", { class: "o-forms-title", children: _jsx("span", { class: "o3-type-body-highlight", children: "Enter your question" }) }), _jsx("span", { class: "o-forms-input o-forms-input--textarea", children: _jsx("textarea", { id: "question-text", name: "question", value: question, onChange: (e) => dispatch(updateQuestion(e.currentTarget.value)), "aria-label": "Your question", placeholder: "Type your question", maxLength: maxQuestionLength, "aria-invalid": error ? 'true' : undefined, "aria-errormessage": "question-form-error-message" }) })] }), _jsx("span", { className: "o3-type-detail", children: "Questions must be at least 20 characters long." }), _jsx(Button, { attributes: {
|
|
117
|
+
'question_form__displayname-error-message' }), displayNameError && (_jsx("span", { className: "question-form__displayname__input__error o3-type-detail", id: "question_form__displayname-error-message", children: _jsx("span", { children: displayNameError }) }))] })] }))] }), _jsx("div", { className: "o-forms-field", children: _jsxs("label", { className: "o-forms-input o-forms-input--checkbox", htmlFor: "post-anonymously", children: [_jsx("input", { type: "checkbox", name: "post-anonymously", id: "post-anonymously", value: "true", onChange: handleHideDisplayName, "data-trackable-context-action": `Post anonymously ${postAnonymously ? 'off' : 'on'}`, "data-trackable": trackingNS(`question-form__post_anonymously-${postAnonymously ? 'off' : 'on'}`) }), _jsx("span", { className: "o-forms-input__label", children: "Post anonymously (optional)" })] }) }), _jsxs("label", { for: "question-text", class: "o-forms-field question-form__question__input", children: [_jsx("span", { class: "o-forms-title", children: _jsx("span", { class: "o3-type-body-highlight", children: "Enter your question" }) }), _jsx("span", { class: "o-forms-input o-forms-input--textarea", children: _jsx("textarea", { id: "question-text", name: "question", value: question, onChange: (e) => dispatch(updateQuestion(e.currentTarget.value)), "aria-label": "Your question", placeholder: "Type your question", maxLength: maxQuestionLength, "aria-invalid": error ? 'true' : undefined, "aria-errormessage": "question-form-error-message" }) })] }), _jsx("span", { className: "o3-type-detail", children: "Questions must be at least 20 characters long." }), _jsx(Button, { attributes: {
|
|
117
118
|
className: 'overlay__submit-button',
|
|
118
119
|
type: 'submit',
|
|
119
120
|
disabled: !submitEnabled,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { PRODUCT_NAME } from '../../config/qanda';
|
|
3
|
+
import { trackingNS } from '../../utils/tracking';
|
|
3
4
|
export const SIGN_IN_URL = 'https://www.ft.com/login';
|
|
4
5
|
export const SUBSCRIBE_URL = 'https://subs.ft.com/products';
|
|
5
6
|
export const COMMUNITY_GUIDELINES_URL = 'https://help.ft.com/help/article-queries/commenting-on-an-article/commenting-guidelines';
|
|
@@ -16,14 +17,14 @@ export function getTitleByUser(profile) {
|
|
|
16
17
|
}
|
|
17
18
|
export function getTextByUser(profile) {
|
|
18
19
|
if (profile.isSubscribed) {
|
|
19
|
-
return (_jsxs(_Fragment, { children: ["Keep your comments respectful and easy to understand for our global audience. By submitting, you agree to follow our", ' ', _jsx("a", { className: "message-box__content-link", "data-trackable":
|
|
20
|
+
return (_jsxs(_Fragment, { children: ["Keep your comments respectful and easy to understand for our global audience. By submitting, you agree to follow our", ' ', _jsx("a", { className: "message-box__content-link", "data-trackable": trackingNS('question-form__community-guidelines'), "data-trackable-context-action": "Community guidelines", href: COMMUNITY_GUIDELINES_URL, target: "_parent", children: "community guidelines" }), ' ', "and", ' ', _jsx("a", { className: "message-box__content-link", "data-trackable": trackingNS('question-form__terms-and-conditions'), "data-trackable-context-action": "Terms and conditions", href: TERMS_AND_CONDITIONS_URL, target: "_parent", children: "terms" }), "."] }));
|
|
20
21
|
}
|
|
21
22
|
if (profile.isTrialist) {
|
|
22
|
-
return (_jsxs(_Fragment, { children: ["View our full", ' ', _jsx("a", { className: "message-box__content-link", "data-trackable":
|
|
23
|
+
return (_jsxs(_Fragment, { children: ["View our full", ' ', _jsx("a", { className: "message-box__content-link", "data-trackable": trackingNS('question-form__subscribe-trialist'), "data-trackable-context-action": "Subscribe", href: SUBSCRIBE_URL, target: "_parent", children: "subscription packages" }), ' ', "to join the conversation."] }));
|
|
23
24
|
}
|
|
24
25
|
if (profile.isRegistered) {
|
|
25
|
-
return (_jsxs(_Fragment, { children: [_jsx("a", { className: "message-box__content-link", "data-trackable":
|
|
26
|
+
return (_jsxs(_Fragment, { children: [_jsx("a", { className: "message-box__content-link", "data-trackable": trackingNS('question-form__subscribe-registered'), "data-trackable-context-action": "Subscribe", href: SUBSCRIBE_URL, target: "_parent", children: "Subscribe" }), ' ', "to join the conversation."] }));
|
|
26
27
|
}
|
|
27
28
|
// Anonymous users
|
|
28
|
-
return (_jsxs(_Fragment, { children: ["Please", ' ', _jsx("a", { className: "message-box__content-link", "data-trackable":
|
|
29
|
+
return (_jsxs(_Fragment, { children: ["Please", ' ', _jsx("a", { className: "message-box__content-link", "data-trackable": trackingNS('question-form__sign-in-anonymous'), "data-trackable-context-action": "Sign in", href: SIGN_IN_URL, target: "_parent", children: "sign in" }), ' ', "or", ' ', _jsx("a", { className: "message-box__content-link", "data-trackable": trackingNS('question-form__subscribe-anonymous'), "data-trackable-context-action": "Subscribe", href: SUBSCRIBE_URL, target: "_parent", children: "subscribe" }), ' ', "to join the conversation."] }));
|
|
29
30
|
}
|
|
@@ -1,34 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { trackingNS } from '../../utils/tracking';
|
|
2
3
|
function Survey({ storyId, status }) {
|
|
3
|
-
|
|
4
|
-
const event = new CustomEvent('oTracking.event', {
|
|
5
|
-
detail: trackingData,
|
|
6
|
-
bubbles: true,
|
|
7
|
-
});
|
|
8
|
-
document.body.dispatchEvent(event);
|
|
9
|
-
};
|
|
10
|
-
const handleClick = () => {
|
|
11
|
-
trackEvent({
|
|
12
|
-
category: 'component',
|
|
13
|
-
component: {
|
|
14
|
-
name: 'liveqa',
|
|
15
|
-
type: 'container',
|
|
16
|
-
id: '663ab2ca-77ca-4b50-873d-1fd2ff21ff08',
|
|
17
|
-
},
|
|
18
|
-
action: 'act',
|
|
19
|
-
trigger_action: 'liveqa_survey_open',
|
|
20
|
-
content: {
|
|
21
|
-
asset_type: 'article',
|
|
22
|
-
uuid: storyId,
|
|
23
|
-
},
|
|
24
|
-
custom: [
|
|
25
|
-
{
|
|
26
|
-
name: 'status',
|
|
27
|
-
value: status,
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
|
-
return (_jsx("div", { className: "o-message o-message--action o-message--inform o-message--survey", style: { marginBottom: 'var(--o3-spacing-l)' }, "data-o-message-close": "false", "data-o-component": "o-message", children: _jsx("div", { className: "o-message__container", children: _jsxs("div", { className: "o-message__content", children: [_jsx("p", { className: "o-message__content-main", style: { fontSize: 'var(--o3-type-body-base-font-size)' }, children: "How was your experience?" }), _jsx("div", { className: "o-message__actions", children: _jsx("a", { href: `https://www.feedback.ft.com/c/a/6HTDVvrHSyaKLZ5281McAo?content_id=${storyId}&qa_status=${status}`, onClick: handleClick, className: "o-message__actions__primary", "data-trackable": "liveqa_survey_link", children: "Share your feedback" }) })] }) }) }));
|
|
4
|
+
return (_jsx("div", { className: "o-message o-message--action o-message--inform o-message--survey", style: { marginBottom: 'var(--o3-spacing-l)' }, "data-o-message-close": "false", "data-o-component": "o-message", children: _jsx("div", { className: "o-message__container", children: _jsxs("div", { className: "o-message__content", children: [_jsx("p", { className: "o-message__content-main", style: { fontSize: 'var(--o3-type-body-base-font-size)' }, children: "How was your experience?" }), _jsx("div", { className: "o-message__actions", children: _jsx("a", { href: `https://www.feedback.ft.com/c/a/6HTDVvrHSyaKLZ5281McAo?content_id=${storyId}&qa_status=${status}`, className: "o-message__actions__primary", "data-trackable": trackingNS('survey_link'), children: "Share your feedback" }) })] }) }) }));
|
|
33
5
|
}
|
|
34
6
|
export default Survey;
|
|
@@ -1,4 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
const trackingNamespace = 'askanexpert_';
|
|
2
|
+
export function trackingNS(string) {
|
|
3
|
+
return trackingNamespace + string;
|
|
4
|
+
}
|
|
5
|
+
export const baseTrackingData = {
|
|
6
|
+
category: 'component',
|
|
7
|
+
action: 'act',
|
|
8
|
+
component: {
|
|
9
|
+
name: 'askanexpert',
|
|
10
|
+
type: 'container',
|
|
11
|
+
id: '663ab2ca-77ca-4b50-873d-1fd2ff21ff08',
|
|
12
|
+
},
|
|
13
|
+
content: {
|
|
14
|
+
asset_type: 'article',
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
export const trackEvent = (customTrackingData) => {
|
|
18
|
+
// Merge the base tracking data with the provided tracking data
|
|
19
|
+
const trackingData = {
|
|
20
|
+
...baseTrackingData,
|
|
21
|
+
...customTrackingData,
|
|
22
|
+
trigger_action: trackingNamespace + customTrackingData.trigger_action,
|
|
23
|
+
};
|
|
2
24
|
const event = new CustomEvent('oTracking.event', {
|
|
3
25
|
detail: trackingData,
|
|
4
26
|
bubbles: true,
|
package/dist/qanda.scss
CHANGED
|
@@ -308,14 +308,12 @@ $app-header-color: #007acc;
|
|
|
308
308
|
color: var(--o3-color-, #33302e);
|
|
309
309
|
float: right;
|
|
310
310
|
margin-top: var(--o3-spacing-2xs);
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
border: unset;
|
|
318
|
-
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.expander__link:hover {
|
|
314
|
+
/* Override some o-button styles */
|
|
315
|
+
background-color: unset !important;
|
|
316
|
+
border: unset !important;
|
|
319
317
|
}
|
|
320
318
|
|
|
321
319
|
/* Inlined from ../components/Loader/styles.scss */
|
|
@@ -343,7 +341,7 @@ $app-header-color: #007acc;
|
|
|
343
341
|
--overlay__header-icon-size: 48px;
|
|
344
342
|
}
|
|
345
343
|
|
|
346
|
-
@keyframes
|
|
344
|
+
@keyframes QandaOverlaySlideUp {
|
|
347
345
|
from {
|
|
348
346
|
transform: translateY(100%);
|
|
349
347
|
}
|
|
@@ -353,7 +351,7 @@ $app-header-color: #007acc;
|
|
|
353
351
|
}
|
|
354
352
|
}
|
|
355
353
|
|
|
356
|
-
@keyframes
|
|
354
|
+
@keyframes QandaOverlaySlideIn {
|
|
357
355
|
from {
|
|
358
356
|
transform: translateX(100%);
|
|
359
357
|
}
|
|
@@ -363,7 +361,7 @@ $app-header-color: #007acc;
|
|
|
363
361
|
}
|
|
364
362
|
}
|
|
365
363
|
|
|
366
|
-
@keyframes
|
|
364
|
+
@keyframes QandaOverlayFadeIn {
|
|
367
365
|
from {
|
|
368
366
|
opacity: 0;
|
|
369
367
|
}
|
|
@@ -390,7 +388,7 @@ $app-header-color: #007acc;
|
|
|
390
388
|
right: 0;
|
|
391
389
|
bottom: 0;
|
|
392
390
|
z-index: 19;
|
|
393
|
-
animation:
|
|
391
|
+
animation: QandaOverlayFadeIn 1s ease forwards;
|
|
394
392
|
background: var(--o3-color-palette-black-90);
|
|
395
393
|
margin-top: calc(var(--safe-area-inset-top, 0px) / 2);
|
|
396
394
|
}
|
|
@@ -402,14 +400,14 @@ $app-header-color: #007acc;
|
|
|
402
400
|
height: 100%;
|
|
403
401
|
width: 100%;
|
|
404
402
|
z-index: 20;
|
|
405
|
-
animation:
|
|
403
|
+
animation: QandaOverlaySlideUp 1s ease forwards;
|
|
406
404
|
|
|
407
405
|
@media (min-width: 740px) {
|
|
408
406
|
width: 375px;
|
|
409
407
|
right: 0;
|
|
410
408
|
top: 0;
|
|
411
409
|
border-radius: 0;
|
|
412
|
-
animation:
|
|
410
|
+
animation: QandaOverlaySlideIn 1s ease forwards;
|
|
413
411
|
}
|
|
414
412
|
}
|
|
415
413
|
|
|
@@ -559,7 +557,7 @@ $app-header-color: #007acc;
|
|
|
559
557
|
var(--o3-color-palette-white-80);
|
|
560
558
|
}
|
|
561
559
|
|
|
562
|
-
.qanda-block__question-
|
|
560
|
+
.qanda-block__question-summary {
|
|
563
561
|
margin-bottom: var(--o3-spacing-4xs);
|
|
564
562
|
}
|
|
565
563
|
|
|
@@ -677,7 +675,7 @@ $app-header-color: #007acc;
|
|
|
677
675
|
|
|
678
676
|
.qanda-container {
|
|
679
677
|
.qanda__stream {
|
|
680
|
-
margin: var(--o3-spacing-l) var(--o3-spacing-
|
|
678
|
+
margin: var(--o3-spacing-l) var(--o3-spacing-5xs) 0 var(--o3-spacing-5xs);
|
|
681
679
|
}
|
|
682
680
|
|
|
683
681
|
.qanda__stream-title {
|
|
@@ -3,5 +3,5 @@ import '../Expander/index';
|
|
|
3
3
|
type QandaBlockProps = Comment & {
|
|
4
4
|
showAnswerTime: boolean;
|
|
5
5
|
};
|
|
6
|
-
declare function QandaBlock({ id, body, children, byline,
|
|
6
|
+
declare function QandaBlock({ id, body, children, byline, summary, showAnswerTime, }: QandaBlockProps): import("react").JSX.Element;
|
|
7
7
|
export default QandaBlock;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
import type { TrackingData } from '../types/tracking';
|
|
2
|
-
export declare
|
|
1
|
+
import type { BaseTrackingData, TrackingData } from '../types/tracking';
|
|
2
|
+
export declare function trackingNS(string: string): string;
|
|
3
|
+
export declare const baseTrackingData: BaseTrackingData;
|
|
4
|
+
export declare const trackEvent: (customTrackingData: TrackingData) => void;
|