@financial-times/qanda-ui 0.0.1-beta.6 → 0.0.1-beta.8
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/dist/cjs/components/EmbedFormField/index.js +4 -0
- package/dist/cjs/components/ExpertDrawer/index.js +36 -0
- package/dist/cjs/components/FloatingActionBar/index.js +20 -5
- package/dist/cjs/components/Loader/index.js +7 -0
- package/dist/cjs/components/Overlay/index.js +12 -2
- package/dist/cjs/components/QandaContainer.js +17 -2
- package/dist/cjs/components/QuestionForm/index.js +2 -1
- package/dist/cjs/components/Stream/index.js +31 -0
- package/dist/cjs/services/comments-api.js +6 -0
- package/dist/cjs/store/expertSlice.js +26 -0
- package/dist/cjs/store/index.js +2 -0
- package/dist/esm/components/EmbedFormField/index.js +5 -1
- package/dist/esm/components/ExpertDrawer/index.js +31 -0
- package/dist/esm/components/FloatingActionBar/index.js +21 -6
- package/dist/esm/components/Loader/index.js +4 -0
- package/dist/esm/components/Overlay/index.js +9 -2
- package/dist/esm/components/QandaContainer.js +19 -4
- package/dist/esm/components/QuestionForm/index.js +2 -1
- package/dist/esm/components/Stream/index.js +26 -0
- package/dist/esm/services/comments-api.js +6 -0
- package/dist/esm/store/expertSlice.js +22 -0
- package/dist/esm/store/index.js +2 -0
- package/dist/qanda.scss +64 -22
- package/dist/types/components/EmbedFormField/index.d.ts +1 -1
- package/dist/types/components/ExpertDrawer/index.d.ts +2 -0
- package/dist/types/components/Loader/index.d.ts +14 -0
- package/dist/types/components/Overlay/index.d.ts +6 -1
- package/dist/types/services/comments-api.d.ts +23 -20
- package/dist/types/store/expertSlice.d.ts +15 -0
- package/dist/types/store/index.d.ts +18 -4
- package/package.json +1 -1
- package/dist/cjs/components/QandaOComments.js +0 -43
- package/dist/cjs/components/Stream.js +0 -28
- package/dist/esm/components/QandaOComments.js +0 -38
- package/dist/esm/components/Stream.js +0 -23
- package/dist/types/components/QandaOComments.d.ts +0 -2
- /package/dist/types/components/{Stream.d.ts → Stream/index.d.ts} +0 -0
|
@@ -8,6 +8,10 @@ const react_dom_1 = require("react-dom");
|
|
|
8
8
|
function EmbedFormField({ container }) {
|
|
9
9
|
const dispatch = (0, react_redux_1.useDispatch)();
|
|
10
10
|
const [portalTarget, setPortalTarget] = (0, react_1.useState)();
|
|
11
|
+
const expertView = (0, react_redux_1.useSelector)((state) => state.expert.expertView);
|
|
12
|
+
if (expertView) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
11
15
|
(0, react_1.useEffect)(() => {
|
|
12
16
|
if (container) {
|
|
13
17
|
const portalContainer = document.createElement('div');
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
7
|
+
const o_comments_1 = __importDefault(require("@financial-times/o-comments"));
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const react_redux_1 = require("react-redux");
|
|
10
|
+
const expertSlice_1 = require("../../store/expertSlice");
|
|
11
|
+
const QandaProvider_1 = require("../QandaProvider");
|
|
12
|
+
const reliability_1 = require("../../services/reliability");
|
|
13
|
+
const Overlay_1 = __importDefault(require("../Overlay"));
|
|
14
|
+
function ExpertDrawer() {
|
|
15
|
+
const dispatch = (0, react_redux_1.useDispatch)();
|
|
16
|
+
const { storyId, useStaging, title } = (0, react_1.useContext)(QandaProvider_1.QandaContext);
|
|
17
|
+
const { isExpertFormOpen, expertView } = (0, react_redux_1.useSelector)((state) => state.expert);
|
|
18
|
+
(0, react_1.useEffect)(() => {
|
|
19
|
+
if (isExpertFormOpen) {
|
|
20
|
+
try {
|
|
21
|
+
o_comments_1.default.init();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
reliability_1.qandaReliability.failure('expert-load-coral-ui', error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}, [isExpertFormOpen]);
|
|
28
|
+
if (!isExpertFormOpen) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return ((0, jsx_runtime_1.jsx)(Overlay_1.default, { title: "Live Q&A", closeCallback: () => dispatch((0, expertSlice_1.closeExpertForm)()), options: {
|
|
32
|
+
shadow: true,
|
|
33
|
+
noBackground: true,
|
|
34
|
+
}, children: (0, jsx_runtime_1.jsx)("div", { className: "o-comments", id: "o-comments-stream", "data-o-component": "o-comments", "data-o-comments-article-id": storyId, "data-o-comments-article-url": `https://www.ft.com/content/${storyId}`, "data-o-comments-use-staging-environment": useStaging, "data-o-comments-title": title }) }));
|
|
35
|
+
}
|
|
36
|
+
exports.default = ExpertDrawer;
|
|
@@ -4,6 +4,7 @@ const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
|
4
4
|
const react_redux_1 = require("react-redux");
|
|
5
5
|
const o3_button_1 = require("@financial-times/o3-button");
|
|
6
6
|
const questionSlice_1 = require("../../store/questionSlice");
|
|
7
|
+
const expertSlice_1 = require("../../store/expertSlice");
|
|
7
8
|
const useIsMobile_1 = require("../../hooks/useIsMobile");
|
|
8
9
|
const comments_api_1 = require("../../services/comments-api");
|
|
9
10
|
const updateComments_1 = require("../../store/updateComments");
|
|
@@ -26,12 +27,26 @@ function FloatingActionBar() {
|
|
|
26
27
|
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
27
28
|
}
|
|
28
29
|
};
|
|
30
|
+
const showExpertView = (0, react_redux_1.useSelector)((state) => state.expert.expertView);
|
|
31
|
+
const userConfig = {
|
|
32
|
+
descripton: 'Ask a question',
|
|
33
|
+
testIdSuffix: 'ask-a-question-button',
|
|
34
|
+
onClick: () => dispatch((0, questionSlice_1.openForm)()),
|
|
35
|
+
dataTrackable: 'open_question_form',
|
|
36
|
+
};
|
|
37
|
+
const expertConfig = {
|
|
38
|
+
descripton: 'Answer Q&A',
|
|
39
|
+
testIdSuffix: 'answer-a-qanda-button',
|
|
40
|
+
onClick: () => dispatch((0, expertSlice_1.openExpertForm)()),
|
|
41
|
+
dataTrackable: 'open_expert_drawer',
|
|
42
|
+
};
|
|
43
|
+
const view = showExpertView ? expertConfig : userConfig;
|
|
29
44
|
return ((0, jsx_runtime_1.jsxs)("div", { className: "floating-action-bar__container", "data-trackable": "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: [(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" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "floating-action-bar__buttons", children: [(0, jsx_runtime_1.jsx)(o3_button_1.Button, { attributes: {
|
|
30
|
-
ariaLabel:
|
|
31
|
-
'data-trackable':
|
|
32
|
-
'data-trackable-context-action':
|
|
33
|
-
'data-testid':
|
|
34
|
-
}, label:
|
|
45
|
+
ariaLabel: view.descripton,
|
|
46
|
+
'data-trackable': view.dataTrackable,
|
|
47
|
+
'data-trackable-context-action': view.descripton,
|
|
48
|
+
'data-testid': `floating-action-bar__${view.testIdSuffix}`,
|
|
49
|
+
}, label: view.descripton, type: "ghost", theme: "mono", icon: "edit", iconOnly: isMobile, onClick: view.onClick }), (0, jsx_runtime_1.jsx)(o3_button_1.Button, { attributes: {
|
|
35
50
|
ariaLabel: 'Back to top',
|
|
36
51
|
'data-trackable': 'back_to_top',
|
|
37
52
|
'data-trackable-context-action': 'Back to top',
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = Loader;
|
|
4
|
+
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
5
|
+
function Loader({ size = 'small', theme = 'light', extraClassNames = '', }) {
|
|
6
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: `o-loading o-loading--${theme} o-loading--${size} ${extraClassNames}`, role: "progressbar", "aria-label": "Loading content" }));
|
|
7
|
+
}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
4
7
|
const o3_button_1 = require("@financial-times/o3-button");
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
const classnames_1 = __importDefault(require("classnames"));
|
|
9
|
+
function Overlay({ title, children, closeCallback, options = {}, }) {
|
|
10
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "overlay", children: [(0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)([
|
|
11
|
+
'overlay__outer',
|
|
12
|
+
{ 'overlay__outer--no-background': options.noBackground },
|
|
13
|
+
]) }), (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)([
|
|
14
|
+
'overlay__inner',
|
|
15
|
+
{ 'overlay__inner--shadow': options.shadow },
|
|
16
|
+
]), children: [(0, jsx_runtime_1.jsx)("div", { className: "overlay__header", children: (0, jsx_runtime_1.jsxs)("div", { className: "overlay__header-bar", children: [(0, jsx_runtime_1.jsx)("span", { className: "o3-type-body-highlight overlay__header-title", children: title }), (0, jsx_runtime_1.jsx)(o3_button_1.Button, { attributes: { className: 'overlay__header-close' }, iconOnly: true, icon: "cross", label: "Close", type: "ghost", theme: "mono", onClick: () => closeCallback() })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "overlay__content", children: children })] })] }));
|
|
7
17
|
}
|
|
8
18
|
exports.default = Overlay;
|
|
@@ -7,9 +7,10 @@ const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
|
7
7
|
const react_1 = require("react");
|
|
8
8
|
const react_redux_1 = require("react-redux");
|
|
9
9
|
const user_1 = require("../store/user");
|
|
10
|
+
const expertSlice_1 = require("../store/expertSlice");
|
|
10
11
|
const QuestionForm_1 = __importDefault(require("./QuestionForm"));
|
|
11
12
|
const UserInfo_1 = __importDefault(require("./UserInfo"));
|
|
12
|
-
const
|
|
13
|
+
const ExpertDrawer_1 = __importDefault(require("./ExpertDrawer"));
|
|
13
14
|
const Stream_1 = __importDefault(require("./Stream"));
|
|
14
15
|
const Calendar_1 = __importDefault(require("./Calendar"));
|
|
15
16
|
const CountdownTimer_1 = __importDefault(require("./CountdownTimer"));
|
|
@@ -31,6 +32,20 @@ function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
|
31
32
|
commentsAPIUrl,
|
|
32
33
|
});
|
|
33
34
|
const status = updatedQA?.status || data?.status || 'pre-live';
|
|
35
|
+
const profile = (0, react_redux_1.useSelector)((state) => state.user.profile);
|
|
36
|
+
const { data: roleData } = (0, comments_api_1.useGetUserRolesQuery)({
|
|
37
|
+
storyId,
|
|
38
|
+
useStaging,
|
|
39
|
+
commentsAPIUrl,
|
|
40
|
+
token: profile.token,
|
|
41
|
+
}, { skip: !profile.token });
|
|
42
|
+
const expertView = roleData?.expertView;
|
|
43
|
+
(0, react_1.useEffect)(() => {
|
|
44
|
+
if (expertView !== undefined) {
|
|
45
|
+
dispatch((0, expertSlice_1.setExpertView)(expertView));
|
|
46
|
+
}
|
|
47
|
+
}, [expertView, dispatch]);
|
|
48
|
+
const showExpertView = (0, react_redux_1.useSelector)((state) => state.expert.expertView);
|
|
34
49
|
(0, react_1.useEffect)(() => {
|
|
35
50
|
dispatch((0, user_1.getUserProfile)({ useStaging, commentsAPIUrl }));
|
|
36
51
|
return () => {
|
|
@@ -38,6 +53,6 @@ function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
|
38
53
|
dispatch(comments_api_1.nextCommentsApi.util.resetApiState());
|
|
39
54
|
};
|
|
40
55
|
}, [dispatch, storyId]);
|
|
41
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "qanda-container", "data-trackable": "liveqa", children: [error && ((0, jsx_runtime_1.jsxs)("p", { children: ["We are not able to load the Q&A 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: [(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 !== 'close' && ((0, jsx_runtime_1.
|
|
56
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "qanda-container", "data-trackable": "liveqa", children: [error && ((0, jsx_runtime_1.jsxs)("p", { children: ["We are not able to load the Q&A 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 !== 'close' && ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(UserInfo_1.default, {}) })), data?.status === 'live' && (0, jsx_runtime_1.jsx)(FloatingActionBar_1.default, {}), (0, jsx_runtime_1.jsx)(EmbedFormField_1.default, { container: embedFormFieldContainer })] }))] }));
|
|
42
57
|
}
|
|
43
58
|
exports.default = QandaContainer;
|
|
@@ -12,6 +12,7 @@ const questionSlice_1 = require("../../store/questionSlice");
|
|
|
12
12
|
const QandaProvider_1 = require("../QandaProvider");
|
|
13
13
|
const comments_api_1 = require("../../services/comments-api");
|
|
14
14
|
const Overlay_1 = __importDefault(require("../Overlay"));
|
|
15
|
+
const Loader_1 = __importDefault(require("../Loader"));
|
|
15
16
|
const o3_button_1 = require("@financial-times/o3-button");
|
|
16
17
|
const MessageBox_1 = __importDefault(require("../Overlay/MessageBox"));
|
|
17
18
|
const user_1 = require("../../store/user");
|
|
@@ -151,5 +152,5 @@ function QuestionForm() {
|
|
|
151
152
|
},
|
|
152
153
|
// @ts-expect-error - o3 Button is currently accepting a JSX element as label
|
|
153
154
|
// but the type definition needs to be updated by Origami team
|
|
154
|
-
label: isLoading ? (
|
|
155
|
+
label: isLoading ? (0, jsx_runtime_1.jsx)(Loader_1.default, {}) : 'Submit your question', type: "primary", theme: "mono" }), !profile?.token && ((0, jsx_runtime_1.jsx)("span", { className: "o3-type-detail", children: "Submitting a question will create a community profile with FT." }))] }) })), isSuccess && ((0, jsx_runtime_1.jsx)(MessageBox_1.default, { color: "#00572C", styles: "o-message--alert o-message--success", title: "Question sent", text: "Your question is in the queue and will be reviewed by our editors." })), error && ((0, jsx_runtime_1.jsx)(MessageBox_1.default, { color: "var(--o3-color-use-case-error)", styles: "o-message--alert o-message--error", title: "Connection issue", text: "Could not submit question: [error messages to come in another ticket]" })), (0, jsx_runtime_1.jsx)(MessageBox_1.default, { styles: "o-message--notice o-message--inform", title: (0, messagesByUserType_1.getTitleByUser)(profile), text: (0, messagesByUserType_1.getTextByUser)(profile) })] }));
|
|
155
156
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const react_redux_1 = require("react-redux");
|
|
9
|
+
const index_1 = __importDefault(require("../QandaBlock/index"));
|
|
10
|
+
const QandaProvider_1 = require("../QandaProvider");
|
|
11
|
+
const Loader_1 = __importDefault(require("../Loader"));
|
|
12
|
+
const comments_api_1 = require("../../services/comments-api");
|
|
13
|
+
function Stream() {
|
|
14
|
+
const latestAnsweredQuestionId = (0, react_redux_1.useSelector)((state) => state.stream.latestAnsweredQuestionId);
|
|
15
|
+
const { storyId, useStaging, commentsAPIUrl } = (0, react_1.useContext)(QandaProvider_1.QandaContext);
|
|
16
|
+
const { data, error, isLoading } = (0, comments_api_1.useGetQandAStreamQuery)({
|
|
17
|
+
storyId,
|
|
18
|
+
useStaging,
|
|
19
|
+
commentsAPIUrl,
|
|
20
|
+
});
|
|
21
|
+
(0, react_1.useEffect)(() => {
|
|
22
|
+
const element = document.getElementById(latestAnsweredQuestionId);
|
|
23
|
+
element?.scrollIntoView({ behavior: 'smooth' });
|
|
24
|
+
}, [latestAnsweredQuestionId]);
|
|
25
|
+
return ((0, jsx_runtime_1.jsxs)("section", { className: "qanda__stream", children: [(0, jsx_runtime_1.jsx)("h2", { className: "o3-type-title-md qanda__stream-title", children: data && data.status && data.status === 'pre-live'
|
|
26
|
+
? 'Top questions so far'
|
|
27
|
+
: 'What our readers are asking' }), (0, jsx_runtime_1.jsxs)("div", { className: "qanda__blocks-container", "data-testid": "qanda__blocks-container", id: "qanda__blocks-container", "aria-busy": isLoading, children: [isLoading && ((0, jsx_runtime_1.jsx)(Loader_1.default, { theme: "dark", extraClassNames: "qanda__stream-loader" })), error && (0, jsx_runtime_1.jsx)("p", { children: "Failed to load Q&A stream" }), data &&
|
|
28
|
+
data.qandas &&
|
|
29
|
+
data.qandas.map((qandaBlock) => ((0, jsx_runtime_1.jsx)(index_1.default, { id: qandaBlock.id, body: qandaBlock.body, type: "comment", publishedDate: qandaBlock.publishedDate, author: qandaBlock.author, byline: qandaBlock.byline, showAnswerTime: data.status === 'live', children: qandaBlock.children }, qandaBlock.id)))] })] }));
|
|
30
|
+
}
|
|
31
|
+
exports.default = Stream;
|
|
@@ -101,6 +101,12 @@ exports.nextCommentsApi = (0, react_1.createApi)({
|
|
|
101
101
|
Authorization: `Bearer ${token}`,
|
|
102
102
|
},
|
|
103
103
|
}),
|
|
104
|
+
transformResponse: (response, meta, arg) => {
|
|
105
|
+
const allowedRoles = ['ADMIN', 'MODERATOR'];
|
|
106
|
+
const { isExpert, isStaffExpert, role } = response;
|
|
107
|
+
const expertView = isExpert || isStaffExpert || !!(role && allowedRoles.includes(role));
|
|
108
|
+
return { expertView };
|
|
109
|
+
},
|
|
104
110
|
}),
|
|
105
111
|
// POST A QUESTION
|
|
106
112
|
postQuestion: builder.mutation({
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.setExpertView = exports.closeExpertForm = exports.openExpertForm = exports.expertSlice = void 0;
|
|
5
|
+
const toolkit_1 = require("@reduxjs/toolkit");
|
|
6
|
+
const initialState = {
|
|
7
|
+
isExpertFormOpen: false,
|
|
8
|
+
expertView: undefined,
|
|
9
|
+
};
|
|
10
|
+
exports.expertSlice = (0, toolkit_1.createSlice)({
|
|
11
|
+
name: 'expert',
|
|
12
|
+
initialState,
|
|
13
|
+
reducers: {
|
|
14
|
+
openExpertForm: (state) => {
|
|
15
|
+
state.isExpertFormOpen = true;
|
|
16
|
+
},
|
|
17
|
+
closeExpertForm: (state) => {
|
|
18
|
+
state.isExpertFormOpen = false;
|
|
19
|
+
},
|
|
20
|
+
setExpertView: (state, action) => {
|
|
21
|
+
state.expertView = action.payload;
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
_a = exports.expertSlice.actions, exports.openExpertForm = _a.openExpertForm, exports.closeExpertForm = _a.closeExpertForm, exports.setExpertView = _a.setExpertView;
|
|
26
|
+
exports.default = exports.expertSlice.reducer;
|
package/dist/cjs/store/index.js
CHANGED
|
@@ -9,12 +9,14 @@ const query_1 = require("@reduxjs/toolkit/query");
|
|
|
9
9
|
const questionSlice_1 = __importDefault(require("./questionSlice"));
|
|
10
10
|
const stream_1 = require("./stream");
|
|
11
11
|
const user_1 = require("./user");
|
|
12
|
+
const expertSlice_1 = __importDefault(require("./expertSlice"));
|
|
12
13
|
const comments_api_1 = require("../services/comments-api");
|
|
13
14
|
const error_middleware_1 = require("../services/error-middleware");
|
|
14
15
|
exports.rootReducer = (0, toolkit_1.combineReducers)({
|
|
15
16
|
stream: stream_1.stream.reducer,
|
|
16
17
|
question: questionSlice_1.default,
|
|
17
18
|
user: user_1.user.reducer,
|
|
19
|
+
expert: expertSlice_1.default,
|
|
18
20
|
nextCommentsApi: comments_api_1.nextCommentsApi.reducer,
|
|
19
21
|
});
|
|
20
22
|
exports.store = (0, toolkit_1.configureStore)({
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
|
-
import { useDispatch } from 'react-redux';
|
|
2
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
3
3
|
import { openForm } from '../../store/questionSlice';
|
|
4
4
|
import { useEffect, useState } from 'react';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
6
|
function EmbedFormField({ container }) {
|
|
7
7
|
const dispatch = useDispatch();
|
|
8
8
|
const [portalTarget, setPortalTarget] = useState();
|
|
9
|
+
const expertView = useSelector((state) => state.expert.expertView);
|
|
10
|
+
if (expertView) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
9
13
|
useEffect(() => {
|
|
10
14
|
if (container) {
|
|
11
15
|
const portalContainer = document.createElement('div');
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import OComments from '@financial-times/o-comments';
|
|
3
|
+
import { useEffect, useContext } from 'react';
|
|
4
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
5
|
+
import { closeExpertForm } from '../../store/expertSlice';
|
|
6
|
+
import { QandaContext } from '../QandaProvider';
|
|
7
|
+
import { qandaReliability } from '../../services/reliability';
|
|
8
|
+
import Overlay from '../Overlay';
|
|
9
|
+
function ExpertDrawer() {
|
|
10
|
+
const dispatch = useDispatch();
|
|
11
|
+
const { storyId, useStaging, title } = useContext(QandaContext);
|
|
12
|
+
const { isExpertFormOpen, expertView } = useSelector((state) => state.expert);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (isExpertFormOpen) {
|
|
15
|
+
try {
|
|
16
|
+
OComments.init();
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
qandaReliability.failure('expert-load-coral-ui', error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}, [isExpertFormOpen]);
|
|
23
|
+
if (!isExpertFormOpen) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return (_jsx(Overlay, { title: "Live Q&A", closeCallback: () => dispatch(closeExpertForm()), options: {
|
|
27
|
+
shadow: true,
|
|
28
|
+
noBackground: true,
|
|
29
|
+
}, children: _jsx("div", { className: "o-comments", id: "o-comments-stream", "data-o-component": "o-comments", "data-o-comments-article-id": storyId, "data-o-comments-article-url": `https://www.ft.com/content/${storyId}`, "data-o-comments-use-staging-environment": useStaging, "data-o-comments-title": title }) }));
|
|
30
|
+
}
|
|
31
|
+
export default ExpertDrawer;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
-
import { useDispatch } from 'react-redux';
|
|
2
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
3
3
|
import { Button } from '@financial-times/o3-button';
|
|
4
4
|
import { openForm } from '../../store/questionSlice';
|
|
5
|
+
import { openExpertForm } from '../../store/expertSlice';
|
|
5
6
|
import { useIsMobile } from '../../hooks/useIsMobile';
|
|
6
7
|
import { useUpdatedComments } from '../../services/comments-api';
|
|
7
8
|
import { updateComments } from '../../store/updateComments';
|
|
@@ -24,12 +25,26 @@ function FloatingActionBar() {
|
|
|
24
25
|
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
25
26
|
}
|
|
26
27
|
};
|
|
28
|
+
const showExpertView = useSelector((state) => state.expert.expertView);
|
|
29
|
+
const userConfig = {
|
|
30
|
+
descripton: 'Ask a question',
|
|
31
|
+
testIdSuffix: 'ask-a-question-button',
|
|
32
|
+
onClick: () => dispatch(openForm()),
|
|
33
|
+
dataTrackable: 'open_question_form',
|
|
34
|
+
};
|
|
35
|
+
const expertConfig = {
|
|
36
|
+
descripton: 'Answer Q&A',
|
|
37
|
+
testIdSuffix: 'answer-a-qanda-button',
|
|
38
|
+
onClick: () => dispatch(openExpertForm()),
|
|
39
|
+
dataTrackable: 'open_expert_drawer',
|
|
40
|
+
};
|
|
41
|
+
const view = showExpertView ? expertConfig : userConfig;
|
|
27
42
|
return (_jsxs("div", { className: "floating-action-bar__container", "data-trackable": "floating-action-bar", children: [_jsx("div", { className: "floating-action-bar__fade-overlay" }), _jsxs("div", { className: "floating-action-bar", "data-testid": "floating-action-bar", children: [_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" }) }), _jsxs("div", { className: "floating-action-bar__buttons", children: [_jsx(Button, { attributes: {
|
|
28
|
-
ariaLabel:
|
|
29
|
-
'data-trackable':
|
|
30
|
-
'data-trackable-context-action':
|
|
31
|
-
'data-testid':
|
|
32
|
-
}, label:
|
|
43
|
+
ariaLabel: view.descripton,
|
|
44
|
+
'data-trackable': view.dataTrackable,
|
|
45
|
+
'data-trackable-context-action': view.descripton,
|
|
46
|
+
'data-testid': `floating-action-bar__${view.testIdSuffix}`,
|
|
47
|
+
}, label: view.descripton, type: "ghost", theme: "mono", icon: "edit", iconOnly: isMobile, onClick: view.onClick }), _jsx(Button, { attributes: {
|
|
33
48
|
ariaLabel: 'Back to top',
|
|
34
49
|
'data-trackable': 'back_to_top',
|
|
35
50
|
'data-trackable-context-action': 'Back to top',
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
export default function Loader({ size = 'small', theme = 'light', extraClassNames = '', }) {
|
|
3
|
+
return (_jsx("div", { className: `o-loading o-loading--${theme} o-loading--${size} ${extraClassNames}`, role: "progressbar", "aria-label": "Loading content" }));
|
|
4
|
+
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { Button } from '@financial-times/o3-button';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
function Overlay({ title, children, closeCallback, options = {}, }) {
|
|
5
|
+
return (_jsxs("div", { className: "overlay", children: [_jsx("div", { className: classNames([
|
|
6
|
+
'overlay__outer',
|
|
7
|
+
{ 'overlay__outer--no-background': options.noBackground },
|
|
8
|
+
]) }), _jsxs("div", { className: classNames([
|
|
9
|
+
'overlay__inner',
|
|
10
|
+
{ 'overlay__inner--shadow': options.shadow },
|
|
11
|
+
]), children: [_jsx("div", { className: "overlay__header", children: _jsxs("div", { className: "overlay__header-bar", children: [_jsx("span", { className: "o3-type-body-highlight overlay__header-title", children: title }), _jsx(Button, { attributes: { className: 'overlay__header-close' }, iconOnly: true, icon: "cross", label: "Close", type: "ghost", theme: "mono", onClick: () => closeCallback() })] }) }), _jsx("div", { className: "overlay__content", children: children })] })] }));
|
|
5
12
|
}
|
|
6
13
|
export default Overlay;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
2
|
import { useEffect, useContext } from 'react';
|
|
3
|
-
import { useDispatch } from 'react-redux';
|
|
3
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
4
4
|
import { getUserProfile } from '../store/user';
|
|
5
|
+
import { setExpertView } from '../store/expertSlice';
|
|
5
6
|
import QuestionForm from './QuestionForm';
|
|
6
7
|
import UserInfo from './UserInfo';
|
|
7
|
-
import
|
|
8
|
+
import ExpertDrawer from './ExpertDrawer';
|
|
8
9
|
import Stream from './Stream';
|
|
9
10
|
import Calendar from './Calendar';
|
|
10
11
|
import CountdownTimer from './CountdownTimer';
|
|
11
12
|
import FloatingActionBar from './FloatingActionBar';
|
|
12
13
|
import EmbedFormField from './EmbedFormField';
|
|
13
14
|
import { QandaContext } from './QandaProvider';
|
|
14
|
-
import { useGetQandAStreamQuery, useUpdatedQA, nextCommentsApi, } from '../services/comments-api';
|
|
15
|
+
import { useGetQandAStreamQuery, useUpdatedQA, useGetUserRolesQuery, nextCommentsApi, } from '../services/comments-api';
|
|
15
16
|
function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
16
17
|
const { storyId, useStaging, commentsAPIUrl } = useContext(QandaContext);
|
|
17
18
|
const dispatch = useDispatch();
|
|
@@ -26,6 +27,20 @@ function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
|
26
27
|
commentsAPIUrl,
|
|
27
28
|
});
|
|
28
29
|
const status = updatedQA?.status || data?.status || 'pre-live';
|
|
30
|
+
const profile = useSelector((state) => state.user.profile);
|
|
31
|
+
const { data: roleData } = useGetUserRolesQuery({
|
|
32
|
+
storyId,
|
|
33
|
+
useStaging,
|
|
34
|
+
commentsAPIUrl,
|
|
35
|
+
token: profile.token,
|
|
36
|
+
}, { skip: !profile.token });
|
|
37
|
+
const expertView = roleData?.expertView;
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (expertView !== undefined) {
|
|
40
|
+
dispatch(setExpertView(expertView));
|
|
41
|
+
}
|
|
42
|
+
}, [expertView, dispatch]);
|
|
43
|
+
const showExpertView = useSelector((state) => state.expert.expertView);
|
|
29
44
|
useEffect(() => {
|
|
30
45
|
dispatch(getUserProfile({ useStaging, commentsAPIUrl }));
|
|
31
46
|
return () => {
|
|
@@ -33,6 +48,6 @@ function QandaContainer({ embedFormFieldContainer, countdownTimerContainer, }) {
|
|
|
33
48
|
dispatch(nextCommentsApi.util.resetApiState());
|
|
34
49
|
};
|
|
35
50
|
}, [dispatch, storyId]);
|
|
36
|
-
return (_jsxs("div", { className: "qanda-container", "data-trackable": "liveqa", children: [error && (_jsxs("p", { children: ["We are not able to load the Q&A at the moment. Please try again later. Error:", error] })), !isLoading && !error && (_jsxs(_Fragment, { children: [status !== 'close' && (_jsxs(_Fragment, { children: [_jsx(QuestionForm, {}), _jsx(CountdownTimer, { container: countdownTimerContainer })] })), status === 'pre-live' && _jsx(Calendar, {}), _jsx(Stream, {}), status !== 'close' && (
|
|
51
|
+
return (_jsxs("div", { className: "qanda-container", "data-trackable": "liveqa", children: [error && (_jsxs("p", { children: ["We are not able to load the Q&A 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 !== 'close' && (_jsx(_Fragment, { children: _jsx(UserInfo, {}) })), data?.status === 'live' && _jsx(FloatingActionBar, {}), _jsx(EmbedFormField, { container: embedFormFieldContainer })] }))] }));
|
|
37
52
|
}
|
|
38
53
|
export default QandaContainer;
|
|
@@ -6,6 +6,7 @@ import { openForm, closeForm, updateQuestion, updateDisplayNameError, } from '..
|
|
|
6
6
|
import { QandaContext } from '../QandaProvider';
|
|
7
7
|
import { usePostQuestionMutation } from '../../services/comments-api';
|
|
8
8
|
import Overlay from '../Overlay';
|
|
9
|
+
import Loader from '../Loader';
|
|
9
10
|
import { Button } from '@financial-times/o3-button';
|
|
10
11
|
import MessageBox from '../Overlay/MessageBox';
|
|
11
12
|
import { getUserProfile } from '../../store/user';
|
|
@@ -145,5 +146,5 @@ export default function QuestionForm() {
|
|
|
145
146
|
},
|
|
146
147
|
// @ts-expect-error - o3 Button is currently accepting a JSX element as label
|
|
147
148
|
// but the type definition needs to be updated by Origami team
|
|
148
|
-
label: isLoading ?
|
|
149
|
+
label: isLoading ? _jsx(Loader, {}) : 'Submit your question', type: "primary", theme: "mono" }), !profile?.token && (_jsx("span", { className: "o3-type-detail", children: "Submitting a question will create a community profile with FT." }))] }) })), isSuccess && (_jsx(MessageBox, { color: "#00572C", styles: "o-message--alert o-message--success", title: "Question sent", text: "Your question is in the queue and will be reviewed by our editors." })), error && (_jsx(MessageBox, { color: "var(--o3-color-use-case-error)", styles: "o-message--alert o-message--error", title: "Connection issue", text: "Could not submit question: [error messages to come in another ticket]" })), _jsx(MessageBox, { styles: "o-message--notice o-message--inform", title: getTitleByUser(profile), text: getTextByUser(profile) })] }));
|
|
149
150
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useEffect, useContext } from 'react';
|
|
3
|
+
import { useSelector } from 'react-redux';
|
|
4
|
+
import QandaBlock from '../QandaBlock/index';
|
|
5
|
+
import { QandaContext } from '../QandaProvider';
|
|
6
|
+
import Loader from '../Loader';
|
|
7
|
+
import { useGetQandAStreamQuery } from '../../services/comments-api';
|
|
8
|
+
function Stream() {
|
|
9
|
+
const latestAnsweredQuestionId = useSelector((state) => state.stream.latestAnsweredQuestionId);
|
|
10
|
+
const { storyId, useStaging, commentsAPIUrl } = useContext(QandaContext);
|
|
11
|
+
const { data, error, isLoading } = useGetQandAStreamQuery({
|
|
12
|
+
storyId,
|
|
13
|
+
useStaging,
|
|
14
|
+
commentsAPIUrl,
|
|
15
|
+
});
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const element = document.getElementById(latestAnsweredQuestionId);
|
|
18
|
+
element?.scrollIntoView({ behavior: 'smooth' });
|
|
19
|
+
}, [latestAnsweredQuestionId]);
|
|
20
|
+
return (_jsxs("section", { className: "qanda__stream", children: [_jsx("h2", { className: "o3-type-title-md qanda__stream-title", children: data && data.status && data.status === 'pre-live'
|
|
21
|
+
? 'Top questions so far'
|
|
22
|
+
: 'What our readers are asking' }), _jsxs("div", { className: "qanda__blocks-container", "data-testid": "qanda__blocks-container", id: "qanda__blocks-container", "aria-busy": isLoading, children: [isLoading && (_jsx(Loader, { theme: "dark", extraClassNames: "qanda__stream-loader" })), error && _jsx("p", { children: "Failed to load Q&A stream" }), data &&
|
|
23
|
+
data.qandas &&
|
|
24
|
+
data.qandas.map((qandaBlock) => (_jsx(QandaBlock, { id: qandaBlock.id, body: qandaBlock.body, type: "comment", publishedDate: qandaBlock.publishedDate, author: qandaBlock.author, byline: qandaBlock.byline, showAnswerTime: data.status === 'live', children: qandaBlock.children }, qandaBlock.id)))] })] }));
|
|
25
|
+
}
|
|
26
|
+
export default Stream;
|
|
@@ -98,6 +98,12 @@ export const nextCommentsApi = createApi({
|
|
|
98
98
|
Authorization: `Bearer ${token}`,
|
|
99
99
|
},
|
|
100
100
|
}),
|
|
101
|
+
transformResponse: (response, meta, arg) => {
|
|
102
|
+
const allowedRoles = ['ADMIN', 'MODERATOR'];
|
|
103
|
+
const { isExpert, isStaffExpert, role } = response;
|
|
104
|
+
const expertView = isExpert || isStaffExpert || !!(role && allowedRoles.includes(role));
|
|
105
|
+
return { expertView };
|
|
106
|
+
},
|
|
101
107
|
}),
|
|
102
108
|
// POST A QUESTION
|
|
103
109
|
postQuestion: builder.mutation({
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
const initialState = {
|
|
3
|
+
isExpertFormOpen: false,
|
|
4
|
+
expertView: undefined,
|
|
5
|
+
};
|
|
6
|
+
export const expertSlice = createSlice({
|
|
7
|
+
name: 'expert',
|
|
8
|
+
initialState,
|
|
9
|
+
reducers: {
|
|
10
|
+
openExpertForm: (state) => {
|
|
11
|
+
state.isExpertFormOpen = true;
|
|
12
|
+
},
|
|
13
|
+
closeExpertForm: (state) => {
|
|
14
|
+
state.isExpertFormOpen = false;
|
|
15
|
+
},
|
|
16
|
+
setExpertView: (state, action) => {
|
|
17
|
+
state.expertView = action.payload;
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
export const { openExpertForm, closeExpertForm, setExpertView } = expertSlice.actions;
|
|
22
|
+
export default expertSlice.reducer;
|
package/dist/esm/store/index.js
CHANGED
|
@@ -3,12 +3,14 @@ import { setupListeners } from '@reduxjs/toolkit/query';
|
|
|
3
3
|
import questionReducer from './questionSlice';
|
|
4
4
|
import { stream } from './stream';
|
|
5
5
|
import { user } from './user';
|
|
6
|
+
import expertReducer from './expertSlice';
|
|
6
7
|
import { nextCommentsApi } from '../services/comments-api';
|
|
7
8
|
import { rtkQueryErrorLogger } from '../services/error-middleware';
|
|
8
9
|
export const rootReducer = combineReducers({
|
|
9
10
|
stream: stream.reducer,
|
|
10
11
|
question: questionReducer,
|
|
11
12
|
user: user.reducer,
|
|
13
|
+
expert: expertReducer,
|
|
12
14
|
nextCommentsApi: nextCommentsApi.reducer,
|
|
13
15
|
});
|
|
14
16
|
export const store = configureStore({
|
package/dist/qanda.scss
CHANGED
|
@@ -6,7 +6,6 @@ $app-header-color: #007acc;
|
|
|
6
6
|
@import '@financial-times/o-forms/main';
|
|
7
7
|
@import '@financial-times/o-icons/main';
|
|
8
8
|
@import '@financial-times/o-labels/main';
|
|
9
|
-
@import '@financial-times/o-loading/main';
|
|
10
9
|
@import '@financial-times/o-message/main';
|
|
11
10
|
@import '@financial-times/o3-foundation/css/core.css';
|
|
12
11
|
/* Inlined from ../components/Author/styles.css */
|
|
@@ -171,6 +170,11 @@ $app-header-color: #007acc;
|
|
|
171
170
|
left: 0;
|
|
172
171
|
right: 0;
|
|
173
172
|
display: flex;
|
|
173
|
+
/* Ensure FAB is on top of ...
|
|
174
|
+
1. some dinamically loaded teasers at the bottom of the article
|
|
175
|
+
2. the sharing bar on mobile
|
|
176
|
+
*/
|
|
177
|
+
z-index: 7;
|
|
174
178
|
}
|
|
175
179
|
|
|
176
180
|
.floating-action-bar__fade-overlay {
|
|
@@ -306,6 +310,24 @@ $app-header-color: #007acc;
|
|
|
306
310
|
margin-top: var(--o3-spacing-2xs);
|
|
307
311
|
}
|
|
308
312
|
|
|
313
|
+
/* Inlined from ../components/Loader/styles.scss */
|
|
314
|
+
@import '@financial-times/o-loading/main';
|
|
315
|
+
|
|
316
|
+
@include oLoading(
|
|
317
|
+
$opts: (
|
|
318
|
+
'themes': (
|
|
319
|
+
'light',
|
|
320
|
+
'dark',
|
|
321
|
+
),
|
|
322
|
+
'sizes': (
|
|
323
|
+
'mini',
|
|
324
|
+
'small',
|
|
325
|
+
'medium',
|
|
326
|
+
'large',
|
|
327
|
+
),
|
|
328
|
+
)
|
|
329
|
+
);
|
|
330
|
+
|
|
309
331
|
/* Inlined from ../components/Overlay/styles.css */
|
|
310
332
|
@import '@financial-times/o3-button/css/core.css';
|
|
311
333
|
|
|
@@ -345,7 +367,8 @@ $app-header-color: #007acc;
|
|
|
345
367
|
position: fixed;
|
|
346
368
|
top: 0;
|
|
347
369
|
left: 0;
|
|
348
|
-
|
|
370
|
+
/* Just going on top of the main navigation */
|
|
371
|
+
z-index: 100;
|
|
349
372
|
}
|
|
350
373
|
|
|
351
374
|
.overlay__outer {
|
|
@@ -359,6 +382,10 @@ $app-header-color: #007acc;
|
|
|
359
382
|
background: var(--o3-color-palette-black-90);
|
|
360
383
|
}
|
|
361
384
|
|
|
385
|
+
.overlay__outer--no-background {
|
|
386
|
+
background: none;
|
|
387
|
+
}
|
|
388
|
+
|
|
362
389
|
.overlay__inner {
|
|
363
390
|
border-radius: var(--o3-spacing-2xs) var(--o3-spacing-2xs) 0 0;
|
|
364
391
|
background: var(--o3-color-use-case-page-background);
|
|
@@ -377,6 +404,15 @@ $app-header-color: #007acc;
|
|
|
377
404
|
}
|
|
378
405
|
}
|
|
379
406
|
|
|
407
|
+
.overlay__inner--shadow {
|
|
408
|
+
@media (min-width: 740px) {
|
|
409
|
+
width: 420px;
|
|
410
|
+
box-shadow:
|
|
411
|
+
-4px 6px 10px 0 rgba(0, 0, 0, 0.15),
|
|
412
|
+
-4px 4px 4px 0 rgba(0, 0, 0, 0.25);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
380
416
|
.overlay__header {
|
|
381
417
|
border-bottom: 1px solid var(--o3-color-palette-black-10);
|
|
382
418
|
display: flex;
|
|
@@ -487,15 +523,6 @@ $app-header-color: #007acc;
|
|
|
487
523
|
}
|
|
488
524
|
|
|
489
525
|
.qanda-container {
|
|
490
|
-
.qanda__blocks-container {
|
|
491
|
-
max-width: 1220px;
|
|
492
|
-
margin: auto;
|
|
493
|
-
display: flex;
|
|
494
|
-
flex-direction: column;
|
|
495
|
-
gap: var(--o3-spacing-l);
|
|
496
|
-
margin-bottom: var(--o3-spacing-l);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
526
|
.qanda-block {
|
|
500
527
|
display: flex;
|
|
501
528
|
flex-direction: column;
|
|
@@ -646,6 +673,32 @@ $app-header-color: #007acc;
|
|
|
646
673
|
}
|
|
647
674
|
}
|
|
648
675
|
|
|
676
|
+
/* Inlined from ../components/Stream/styles.css */
|
|
677
|
+
@import '@financial-times/o3-foundation/css/core.css';
|
|
678
|
+
|
|
679
|
+
.qanda-container {
|
|
680
|
+
.qanda__stream {
|
|
681
|
+
margin-top: var(--o3-spacing-l);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.qanda__stream-title {
|
|
685
|
+
margin: 0 0 var(--o3-spacing-s);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
.qanda__stream-loader {
|
|
689
|
+
align-self: center;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
.qanda__blocks-container {
|
|
693
|
+
max-width: 1220px;
|
|
694
|
+
margin: auto;
|
|
695
|
+
display: flex;
|
|
696
|
+
flex-direction: column;
|
|
697
|
+
gap: var(--o3-spacing-l);
|
|
698
|
+
margin-bottom: var(--o3-spacing-l);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
649
702
|
|
|
650
703
|
@include oForms(
|
|
651
704
|
$opts: (
|
|
@@ -671,17 +724,6 @@ $app-header-color: #007acc;
|
|
|
671
724
|
)
|
|
672
725
|
);
|
|
673
726
|
|
|
674
|
-
@include oLoading(
|
|
675
|
-
$opts: (
|
|
676
|
-
'themes': (
|
|
677
|
-
'light',
|
|
678
|
-
),
|
|
679
|
-
'sizes': (
|
|
680
|
-
'small',
|
|
681
|
-
),
|
|
682
|
-
)
|
|
683
|
-
);
|
|
684
|
-
|
|
685
727
|
@include oMessage(
|
|
686
728
|
$opts: (
|
|
687
729
|
'types': (
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
type EmbedFormFieldProps = {
|
|
2
2
|
container?: HTMLElement;
|
|
3
3
|
};
|
|
4
|
-
declare function EmbedFormField({ container }: EmbedFormFieldProps): import("react").JSX.Element;
|
|
4
|
+
declare function EmbedFormField({ container }: EmbedFormFieldProps): import("react").JSX.Element | null;
|
|
5
5
|
export default EmbedFormField;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loader component that shows the o-loading spinner, defaults to small light variant
|
|
3
|
+
* @typedef {Object} LoaderProps
|
|
4
|
+
* @property {('mini'|'small'|'medium'|'large')} [size] - Size variant of the loader.
|
|
5
|
+
* @property {('dark'|'light')} [theme] - Theme variant of the loader.
|
|
6
|
+
|
|
7
|
+
* @property {string} [extraClassNames] - Additional CSS class names to be applied to the loader component for custom styling.
|
|
8
|
+
*/
|
|
9
|
+
export type LoaderProps = {
|
|
10
|
+
size?: 'mini' | 'small' | 'medium' | 'large';
|
|
11
|
+
theme?: 'dark' | 'light';
|
|
12
|
+
extraClassNames?: string;
|
|
13
|
+
};
|
|
14
|
+
export default function Loader({ size, theme, extraClassNames, }: LoaderProps): import("react-dom/src").JSX.Element;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
type OverlayOptions = {
|
|
2
|
+
noBackground?: boolean;
|
|
3
|
+
shadow?: boolean;
|
|
4
|
+
};
|
|
1
5
|
type OverlayProps = {
|
|
2
6
|
title: String;
|
|
3
7
|
children: React.ReactNode;
|
|
4
8
|
closeCallback: () => void;
|
|
9
|
+
options?: OverlayOptions;
|
|
5
10
|
};
|
|
6
|
-
declare function Overlay({ title, children, closeCallback }: OverlayProps): import("react-dom/src").JSX.Element;
|
|
11
|
+
declare function Overlay({ title, children, closeCallback, options, }: OverlayProps): import("react-dom/src").JSX.Element;
|
|
7
12
|
export default Overlay;
|
|
@@ -30,10 +30,13 @@ type CachedData = {
|
|
|
30
30
|
updateQA?: QA;
|
|
31
31
|
[key: string]: any;
|
|
32
32
|
};
|
|
33
|
+
type UserRolesTransformed = {
|
|
34
|
+
expertView: boolean;
|
|
35
|
+
};
|
|
33
36
|
export declare const nextCommentsApi: import("@reduxjs/toolkit/query").Api<import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, {
|
|
34
37
|
getQandAStream: import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, CommentsStreamTransformed, "nextCommentsApi">;
|
|
35
38
|
getQandAUpdates: import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, CachedData, "nextCommentsApi">;
|
|
36
|
-
getUserRoles: import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
39
|
+
getUserRoles: import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">;
|
|
37
40
|
postQuestion: import("@reduxjs/toolkit/query").MutationDefinition<CommentsAPIUrlQuestionParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, any, "nextCommentsApi">;
|
|
38
41
|
}, "nextCommentsApi", never, typeof import("@reduxjs/toolkit/query").coreModuleName | typeof import("@reduxjs/toolkit/query/react").reactHooksModuleName>;
|
|
39
42
|
export declare const useGetQandAStreamQuery: <R extends Record<string, any> = import("@reduxjs/toolkit/query").TSHelpersId<(Omit<{
|
|
@@ -310,7 +313,7 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
310
313
|
startedTimeStamp?: undefined | undefined;
|
|
311
314
|
fulfilledTimeStamp?: undefined | undefined;
|
|
312
315
|
} & {
|
|
313
|
-
currentData?:
|
|
316
|
+
currentData?: UserRolesTransformed | undefined;
|
|
314
317
|
isUninitialized: false;
|
|
315
318
|
isLoading: false;
|
|
316
319
|
isFetching: false;
|
|
@@ -318,8 +321,8 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
318
321
|
isError: false;
|
|
319
322
|
}, "isUninitialized"> & {
|
|
320
323
|
isUninitialized: true;
|
|
321
|
-
}) | import("@reduxjs/toolkit/query").TSHelpersOverride<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
322
|
-
currentData?:
|
|
324
|
+
}) | import("@reduxjs/toolkit/query").TSHelpersOverride<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">> & {
|
|
325
|
+
currentData?: UserRolesTransformed | undefined;
|
|
323
326
|
isUninitialized: false;
|
|
324
327
|
isLoading: false;
|
|
325
328
|
isFetching: false;
|
|
@@ -333,8 +336,8 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
333
336
|
isSuccess: true;
|
|
334
337
|
isFetching: true;
|
|
335
338
|
error: undefined;
|
|
336
|
-
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
337
|
-
currentData?:
|
|
339
|
+
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">> & {
|
|
340
|
+
currentData?: UserRolesTransformed | undefined;
|
|
338
341
|
isUninitialized: false;
|
|
339
342
|
isLoading: false;
|
|
340
343
|
isFetching: false;
|
|
@@ -344,8 +347,8 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
344
347
|
isSuccess: true;
|
|
345
348
|
isFetching: false;
|
|
346
349
|
error: undefined;
|
|
347
|
-
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
348
|
-
currentData?:
|
|
350
|
+
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">> & {
|
|
351
|
+
currentData?: UserRolesTransformed | undefined;
|
|
349
352
|
isUninitialized: false;
|
|
350
353
|
isLoading: false;
|
|
351
354
|
isFetching: false;
|
|
@@ -353,8 +356,8 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
353
356
|
isError: false;
|
|
354
357
|
}, "data" | "fulfilledTimeStamp" | "currentData">>) | ({
|
|
355
358
|
isError: true;
|
|
356
|
-
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
357
|
-
currentData?:
|
|
359
|
+
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">> & {
|
|
360
|
+
currentData?: UserRolesTransformed | undefined;
|
|
358
361
|
isUninitialized: false;
|
|
359
362
|
isLoading: false;
|
|
360
363
|
isFetching: false;
|
|
@@ -377,7 +380,7 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
377
380
|
startedTimeStamp?: undefined | undefined;
|
|
378
381
|
fulfilledTimeStamp?: undefined | undefined;
|
|
379
382
|
} & {
|
|
380
|
-
currentData?:
|
|
383
|
+
currentData?: UserRolesTransformed | undefined;
|
|
381
384
|
isUninitialized: false;
|
|
382
385
|
isLoading: false;
|
|
383
386
|
isFetching: false;
|
|
@@ -385,8 +388,8 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
385
388
|
isError: false;
|
|
386
389
|
}, "isUninitialized"> & {
|
|
387
390
|
isUninitialized: true;
|
|
388
|
-
}) | import("@reduxjs/toolkit/query").TSHelpersOverride<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
389
|
-
currentData?:
|
|
391
|
+
}) | import("@reduxjs/toolkit/query").TSHelpersOverride<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">> & {
|
|
392
|
+
currentData?: UserRolesTransformed | undefined;
|
|
390
393
|
isUninitialized: false;
|
|
391
394
|
isLoading: false;
|
|
392
395
|
isFetching: false;
|
|
@@ -400,8 +403,8 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
400
403
|
isSuccess: true;
|
|
401
404
|
isFetching: true;
|
|
402
405
|
error: undefined;
|
|
403
|
-
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
404
|
-
currentData?:
|
|
406
|
+
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">> & {
|
|
407
|
+
currentData?: UserRolesTransformed | undefined;
|
|
405
408
|
isUninitialized: false;
|
|
406
409
|
isLoading: false;
|
|
407
410
|
isFetching: false;
|
|
@@ -411,8 +414,8 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
411
414
|
isSuccess: true;
|
|
412
415
|
isFetching: false;
|
|
413
416
|
error: undefined;
|
|
414
|
-
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
415
|
-
currentData?:
|
|
417
|
+
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">> & {
|
|
418
|
+
currentData?: UserRolesTransformed | undefined;
|
|
416
419
|
isUninitialized: false;
|
|
417
420
|
isLoading: false;
|
|
418
421
|
isFetching: false;
|
|
@@ -420,8 +423,8 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
420
423
|
isError: false;
|
|
421
424
|
}, "data" | "fulfilledTimeStamp" | "currentData">>) | ({
|
|
422
425
|
isError: true;
|
|
423
|
-
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
424
|
-
currentData?:
|
|
426
|
+
} & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">> & {
|
|
427
|
+
currentData?: UserRolesTransformed | undefined;
|
|
425
428
|
isUninitialized: false;
|
|
426
429
|
isLoading: false;
|
|
427
430
|
isFetching: false;
|
|
@@ -431,7 +434,7 @@ export declare const useGetQandAStreamQuery: <R extends Record<string, any> = im
|
|
|
431
434
|
status: import("@reduxjs/toolkit/query").QueryStatus;
|
|
432
435
|
}) => R) | undefined;
|
|
433
436
|
}) | undefined) => [R][R extends any ? 0 : never] & {
|
|
434
|
-
refetch: () => import("@reduxjs/toolkit/query").QueryActionCreatorResult<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
437
|
+
refetch: () => import("@reduxjs/toolkit/query").QueryActionCreatorResult<import("@reduxjs/toolkit/query").QueryDefinition<CommentsAPIUrlTokenParams, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, UserRolesTransformed, "nextCommentsApi">>;
|
|
435
438
|
}, usePostQuestionMutation: <R extends Record<string, any> = ({
|
|
436
439
|
requestId?: undefined;
|
|
437
440
|
status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ExpertState {
|
|
2
|
+
isExpertFormOpen: boolean;
|
|
3
|
+
expertView?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare const expertSlice: import("@reduxjs/toolkit").Slice<ExpertState, {
|
|
6
|
+
openExpertForm: (state: import("immer").WritableDraft<ExpertState>) => void;
|
|
7
|
+
closeExpertForm: (state: import("immer").WritableDraft<ExpertState>) => void;
|
|
8
|
+
setExpertView: (state: import("immer").WritableDraft<ExpertState>, action: {
|
|
9
|
+
payload: any;
|
|
10
|
+
type: string;
|
|
11
|
+
}) => void;
|
|
12
|
+
}, "expert", "expert", import("@reduxjs/toolkit").SliceSelectors<ExpertState>>;
|
|
13
|
+
export declare const openExpertForm: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expert/openExpertForm">, closeExpertForm: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expert/closeExpertForm">, setExpertView: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "expert/setExpertView">;
|
|
14
|
+
declare const _default: import("redux").Reducer<ExpertState>;
|
|
15
|
+
export default _default;
|
|
@@ -2,10 +2,12 @@ import { ThunkAction, Action } from '@reduxjs/toolkit';
|
|
|
2
2
|
import { QuestionState } from './questionSlice';
|
|
3
3
|
import { StreamState } from './stream';
|
|
4
4
|
import { UserState } from './user';
|
|
5
|
+
import { ExpertState } from './expertSlice';
|
|
5
6
|
export declare const rootReducer: import("redux").Reducer<{
|
|
6
7
|
stream: StreamState;
|
|
7
8
|
question: QuestionState;
|
|
8
9
|
user: UserState;
|
|
10
|
+
expert: ExpertState;
|
|
9
11
|
nextCommentsApi: import("@reduxjs/toolkit/query").CombinedState<{
|
|
10
12
|
getQandAStream: import("@reduxjs/toolkit/query").QueryDefinition<{
|
|
11
13
|
storyId: string;
|
|
@@ -35,7 +37,9 @@ export declare const rootReducer: import("redux").Reducer<{
|
|
|
35
37
|
commentsAPIUrl: string;
|
|
36
38
|
} & {
|
|
37
39
|
token: string;
|
|
38
|
-
}, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, import("@reduxjs/toolkit/query").FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
40
|
+
}, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, import("@reduxjs/toolkit/query").FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, {
|
|
41
|
+
expertView: boolean;
|
|
42
|
+
}, "nextCommentsApi">;
|
|
39
43
|
postQuestion: import("@reduxjs/toolkit/query").MutationDefinition<{
|
|
40
44
|
storyId: string;
|
|
41
45
|
useStaging: boolean;
|
|
@@ -51,6 +55,7 @@ export declare const rootReducer: import("redux").Reducer<{
|
|
|
51
55
|
stream: StreamState | undefined;
|
|
52
56
|
question: QuestionState | undefined;
|
|
53
57
|
user: UserState | undefined;
|
|
58
|
+
expert: ExpertState | undefined;
|
|
54
59
|
nextCommentsApi: import("@reduxjs/toolkit/query").CombinedState<{
|
|
55
60
|
getQandAStream: import("@reduxjs/toolkit/query").QueryDefinition<{
|
|
56
61
|
storyId: string;
|
|
@@ -80,7 +85,9 @@ export declare const rootReducer: import("redux").Reducer<{
|
|
|
80
85
|
commentsAPIUrl: string;
|
|
81
86
|
} & {
|
|
82
87
|
token: string;
|
|
83
|
-
}, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, import("@reduxjs/toolkit/query").FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
88
|
+
}, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, import("@reduxjs/toolkit/query").FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, {
|
|
89
|
+
expertView: boolean;
|
|
90
|
+
}, "nextCommentsApi">;
|
|
84
91
|
postQuestion: import("@reduxjs/toolkit/query").MutationDefinition<{
|
|
85
92
|
storyId: string;
|
|
86
93
|
useStaging: boolean;
|
|
@@ -97,11 +104,13 @@ export type RootState = {
|
|
|
97
104
|
stream: StreamState;
|
|
98
105
|
question: QuestionState;
|
|
99
106
|
user: UserState;
|
|
107
|
+
expert: ExpertState;
|
|
100
108
|
};
|
|
101
109
|
export declare const store: import("@reduxjs/toolkit").EnhancedStore<{
|
|
102
110
|
stream: StreamState;
|
|
103
111
|
question: QuestionState;
|
|
104
112
|
user: UserState;
|
|
113
|
+
expert: ExpertState;
|
|
105
114
|
nextCommentsApi: import("@reduxjs/toolkit/query").CombinedState<{
|
|
106
115
|
getQandAStream: import("@reduxjs/toolkit/query").QueryDefinition<{
|
|
107
116
|
storyId: string;
|
|
@@ -131,7 +140,9 @@ export declare const store: import("@reduxjs/toolkit").EnhancedStore<{
|
|
|
131
140
|
commentsAPIUrl: string;
|
|
132
141
|
} & {
|
|
133
142
|
token: string;
|
|
134
|
-
}, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, import("@reduxjs/toolkit/query").FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
143
|
+
}, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, import("@reduxjs/toolkit/query").FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, {
|
|
144
|
+
expertView: boolean;
|
|
145
|
+
}, "nextCommentsApi">;
|
|
135
146
|
postQuestion: import("@reduxjs/toolkit/query").MutationDefinition<{
|
|
136
147
|
storyId: string;
|
|
137
148
|
useStaging: boolean;
|
|
@@ -148,6 +159,7 @@ export declare const store: import("@reduxjs/toolkit").EnhancedStore<{
|
|
|
148
159
|
stream: StreamState;
|
|
149
160
|
question: QuestionState;
|
|
150
161
|
user: UserState;
|
|
162
|
+
expert: ExpertState;
|
|
151
163
|
nextCommentsApi: import("@reduxjs/toolkit/query").CombinedState<{
|
|
152
164
|
getQandAStream: import("@reduxjs/toolkit/query").QueryDefinition<{
|
|
153
165
|
storyId: string;
|
|
@@ -177,7 +189,9 @@ export declare const store: import("@reduxjs/toolkit").EnhancedStore<{
|
|
|
177
189
|
commentsAPIUrl: string;
|
|
178
190
|
} & {
|
|
179
191
|
token: string;
|
|
180
|
-
}, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, import("@reduxjs/toolkit/query").FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never,
|
|
192
|
+
}, import("@reduxjs/toolkit/query").BaseQueryFn<string | import("@reduxjs/toolkit/query").FetchArgs, unknown, import("@reduxjs/toolkit/query").FetchBaseQueryError, {}, import("@reduxjs/toolkit/query").FetchBaseQueryMeta>, never, {
|
|
193
|
+
expertView: boolean;
|
|
194
|
+
}, "nextCommentsApi">;
|
|
181
195
|
postQuestion: import("@reduxjs/toolkit/query").MutationDefinition<{
|
|
182
196
|
storyId: string;
|
|
183
197
|
useStaging: boolean;
|
package/package.json
CHANGED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
7
|
-
const o_comments_1 = __importDefault(require("@financial-times/o-comments"));
|
|
8
|
-
const react_1 = require("react");
|
|
9
|
-
const react_redux_1 = require("react-redux");
|
|
10
|
-
const QandaProvider_1 = require("./QandaProvider");
|
|
11
|
-
const comments_api_1 = require("../services/comments-api");
|
|
12
|
-
const reliability_1 = require("../services/reliability");
|
|
13
|
-
function QandaOComments() {
|
|
14
|
-
const allowedRoles = ['ADMIN', 'MODERATOR'];
|
|
15
|
-
const { storyId, useStaging, commentsAPIUrl, title } = (0, react_1.useContext)(QandaProvider_1.QandaContext);
|
|
16
|
-
const profile = (0, react_redux_1.useSelector)((state) => state.user.profile);
|
|
17
|
-
if (!profile) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
const { data: userRole, error, isLoading, } = (0, comments_api_1.useGetUserRolesQuery)({
|
|
21
|
-
storyId,
|
|
22
|
-
useStaging,
|
|
23
|
-
commentsAPIUrl,
|
|
24
|
-
token: profile.token,
|
|
25
|
-
}, { skip: !profile.token });
|
|
26
|
-
(0, react_1.useEffect)(() => {
|
|
27
|
-
if (!userRole) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
const { isExpert, isStaffExpert, role } = userRole;
|
|
31
|
-
const showCoral = isExpert || isStaffExpert || (role && allowedRoles.includes(role));
|
|
32
|
-
if (showCoral) {
|
|
33
|
-
try {
|
|
34
|
-
o_comments_1.default.init();
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
reliability_1.qandaReliability.failure('expert-load-coral-ui', error);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}, [userRole]);
|
|
41
|
-
return ((0, jsx_runtime_1.jsx)("div", { className: "o-comments", id: "o-comments-stream", "data-o-component": "o-comments", "data-o-comments-article-id": storyId, "data-o-comments-article-url": `https://www.ft.com/content/${storyId}`, "data-o-comments-use-staging-environment": useStaging, "data-o-comments-title": title }));
|
|
42
|
-
}
|
|
43
|
-
exports.default = QandaOComments;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const jsx_runtime_1 = require("preact/jsx-runtime");
|
|
7
|
-
const react_1 = require("react");
|
|
8
|
-
const react_redux_1 = require("react-redux");
|
|
9
|
-
const index_1 = __importDefault(require("./QandaBlock/index"));
|
|
10
|
-
const QandaProvider_1 = require("./QandaProvider");
|
|
11
|
-
const comments_api_1 = require("../services/comments-api");
|
|
12
|
-
function Stream() {
|
|
13
|
-
const latestAnsweredQuestionId = (0, react_redux_1.useSelector)((state) => state.stream.latestAnsweredQuestionId);
|
|
14
|
-
const { storyId, useStaging, commentsAPIUrl } = (0, react_1.useContext)(QandaProvider_1.QandaContext);
|
|
15
|
-
const { data, error, isLoading } = (0, comments_api_1.useGetQandAStreamQuery)({
|
|
16
|
-
storyId,
|
|
17
|
-
useStaging,
|
|
18
|
-
commentsAPIUrl,
|
|
19
|
-
});
|
|
20
|
-
(0, react_1.useEffect)(() => {
|
|
21
|
-
const element = document.getElementById(latestAnsweredQuestionId);
|
|
22
|
-
element?.scrollIntoView({ behavior: 'smooth' });
|
|
23
|
-
}, [latestAnsweredQuestionId]);
|
|
24
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "qanda__blocks-container", "data-testid": "qanda__blocks-container", id: "qanda__blocks-container", children: [isLoading && (0, jsx_runtime_1.jsx)("p", { children: "Loading Stream for you, be patient..." }), error && (0, jsx_runtime_1.jsx)("p", { children: "Failed to load Q&A stream" }), data &&
|
|
25
|
-
data.qandas &&
|
|
26
|
-
data.qandas.map((qandaBlock) => ((0, jsx_runtime_1.jsx)(index_1.default, { id: qandaBlock.id, body: qandaBlock.body, type: "comment", publishedDate: qandaBlock.publishedDate, author: qandaBlock.author, byline: qandaBlock.byline, showAnswerTime: data.status === 'live', children: qandaBlock.children }, qandaBlock.id)))] }));
|
|
27
|
-
}
|
|
28
|
-
exports.default = Stream;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
-
import OComments from '@financial-times/o-comments';
|
|
3
|
-
import { useEffect, useContext } from 'react';
|
|
4
|
-
import { useSelector } from 'react-redux';
|
|
5
|
-
import { QandaContext } from './QandaProvider';
|
|
6
|
-
import { useGetUserRolesQuery } from '../services/comments-api';
|
|
7
|
-
import { qandaReliability } from '../services/reliability';
|
|
8
|
-
function QandaOComments() {
|
|
9
|
-
const allowedRoles = ['ADMIN', 'MODERATOR'];
|
|
10
|
-
const { storyId, useStaging, commentsAPIUrl, title } = useContext(QandaContext);
|
|
11
|
-
const profile = useSelector((state) => state.user.profile);
|
|
12
|
-
if (!profile) {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
const { data: userRole, error, isLoading, } = useGetUserRolesQuery({
|
|
16
|
-
storyId,
|
|
17
|
-
useStaging,
|
|
18
|
-
commentsAPIUrl,
|
|
19
|
-
token: profile.token,
|
|
20
|
-
}, { skip: !profile.token });
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
if (!userRole) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
const { isExpert, isStaffExpert, role } = userRole;
|
|
26
|
-
const showCoral = isExpert || isStaffExpert || (role && allowedRoles.includes(role));
|
|
27
|
-
if (showCoral) {
|
|
28
|
-
try {
|
|
29
|
-
OComments.init();
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
qandaReliability.failure('expert-load-coral-ui', error);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}, [userRole]);
|
|
36
|
-
return (_jsx("div", { className: "o-comments", id: "o-comments-stream", "data-o-component": "o-comments", "data-o-comments-article-id": storyId, "data-o-comments-article-url": `https://www.ft.com/content/${storyId}`, "data-o-comments-use-staging-environment": useStaging, "data-o-comments-title": title }));
|
|
37
|
-
}
|
|
38
|
-
export default QandaOComments;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
-
import { useEffect, useContext } from 'react';
|
|
3
|
-
import { useSelector } from 'react-redux';
|
|
4
|
-
import QandaBlock from './QandaBlock/index';
|
|
5
|
-
import { QandaContext } from './QandaProvider';
|
|
6
|
-
import { useGetQandAStreamQuery } from '../services/comments-api';
|
|
7
|
-
function Stream() {
|
|
8
|
-
const latestAnsweredQuestionId = useSelector((state) => state.stream.latestAnsweredQuestionId);
|
|
9
|
-
const { storyId, useStaging, commentsAPIUrl } = useContext(QandaContext);
|
|
10
|
-
const { data, error, isLoading } = useGetQandAStreamQuery({
|
|
11
|
-
storyId,
|
|
12
|
-
useStaging,
|
|
13
|
-
commentsAPIUrl,
|
|
14
|
-
});
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
const element = document.getElementById(latestAnsweredQuestionId);
|
|
17
|
-
element?.scrollIntoView({ behavior: 'smooth' });
|
|
18
|
-
}, [latestAnsweredQuestionId]);
|
|
19
|
-
return (_jsxs("div", { className: "qanda__blocks-container", "data-testid": "qanda__blocks-container", id: "qanda__blocks-container", children: [isLoading && _jsx("p", { children: "Loading Stream for you, be patient..." }), error && _jsx("p", { children: "Failed to load Q&A stream" }), data &&
|
|
20
|
-
data.qandas &&
|
|
21
|
-
data.qandas.map((qandaBlock) => (_jsx(QandaBlock, { id: qandaBlock.id, body: qandaBlock.body, type: "comment", publishedDate: qandaBlock.publishedDate, author: qandaBlock.author, byline: qandaBlock.byline, showAnswerTime: data.status === 'live', children: qandaBlock.children }, qandaBlock.id)))] }));
|
|
22
|
-
}
|
|
23
|
-
export default Stream;
|
|
File without changes
|