diff --git a/.env b/.env
index 9fc7c719..df8553a6 100644
--- a/.env
+++ b/.env
@@ -19,3 +19,4 @@ REFRESH_ACCESS_TOKEN_ENDPOINT=''
SEGMENT_KEY=''
SITE_NAME=''
USER_INFO_COOKIE_NAME=''
+FEEDBACK_FORM_URL=''
diff --git a/.env.development b/.env.development
index 5266dd5d..c1ee024f 100644
--- a/.env.development
+++ b/.env.development
@@ -20,3 +20,4 @@ REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
SEGMENT_KEY=''
SITE_NAME=localhost
USER_INFO_COOKIE_NAME='edx-user-info'
+FEEDBACK_FORM_URL=''
diff --git a/.env.test b/.env.test
index e6a9bc01..553e1106 100644
--- a/.env.test
+++ b/.env.test
@@ -18,3 +18,4 @@ REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
SEGMENT_KEY=''
SITE_NAME=localhost
USER_INFO_COOKIE_NAME='edx-user-info'
+FEEDBACK_FORM_URL=''
diff --git a/src/components/Feedback/index.jsx b/src/components/Feedback/index.jsx
new file mode 100644
index 00000000..a8724edc
--- /dev/null
+++ b/src/components/Feedback/index.jsx
@@ -0,0 +1,34 @@
+import React from 'react';
+
+import { ensureConfig, getConfig } from '@edx/frontend-platform';
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
+import { Hyperlink } from '@edx/paragon';
+
+import messages from './messages';
+
+ensureConfig(['FEEDBACK_FORM_URL'], 'Feedback');
+
+const Feedback = ({ intl, ...props }) => {
+ const formUrl = getConfig().FEEDBACK_FORM_URL;
+
+ return (
+ formUrl && (
+
+ {intl.formatMessage(messages.feedbackLink)}
+
+ )
+ );
+};
+
+Feedback.propTypes = {
+ intl: intlShape.isRequired,
+};
+
+export default injectIntl(Feedback);
diff --git a/src/components/Feedback/messages.js b/src/components/Feedback/messages.js
new file mode 100644
index 00000000..3f92792a
--- /dev/null
+++ b/src/components/Feedback/messages.js
@@ -0,0 +1,11 @@
+import { defineMessages } from '@edx/frontend-platform/i18n';
+
+const messages = defineMessages({
+ feedbackLink: {
+ id: 'components.feedbackLink',
+ defaultMessage: 'Give Feedback',
+ description: 'Alt description for feedback button for give feedback.',
+ },
+});
+
+export default messages;
diff --git a/src/discussions/discussions-home/DiscussionsHome.test.jsx b/src/discussions/discussions-home/DiscussionsHome.test.jsx
index d7e56170..dfa49f13 100644
--- a/src/discussions/discussions-home/DiscussionsHome.test.jsx
+++ b/src/discussions/discussions-home/DiscussionsHome.test.jsx
@@ -3,7 +3,7 @@ import { IntlProvider } from 'react-intl';
import { Context as ResponsiveContext } from 'react-responsive';
import { MemoryRouter } from 'react-router';
-import { initializeMockApp } from '@edx/frontend-platform';
+import { getConfig, initializeMockApp, setConfig } from '@edx/frontend-platform';
import { AppProvider } from '@edx/frontend-platform/react';
import { initializeStore } from '../../store';
@@ -38,6 +38,11 @@ describe('DiscussionsHome', () => {
},
});
+ setConfig({
+ ...getConfig(),
+ FEEDBACK_FORM_URL: 'test-url',
+ });
+
store = initializeStore();
});
@@ -50,22 +55,19 @@ describe('DiscussionsHome', () => {
await screen.findByTestId('topics-view');
});
- test('full view should hide close button', async () => {
+ test('full view should hide close button and display feedback button', async () => {
renderComponent(`/${courseId}/topics`);
- expect(screen.queryByText(navigationBarMessages.allTopics.defaultMessage))
- .toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Close' }))
- .not
- .toBeInTheDocument();
+
+ expect(screen.queryByText(navigationBarMessages.allTopics.defaultMessage)).toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Close' })).not.toBeInTheDocument();
+ expect(screen.queryByText('Give Feedback')).toBeInTheDocument();
});
- test('in-context view should show close button', async () => {
+ test('in-context view should show close button and display feedback button', async () => {
renderComponent(`/${courseId}/topics?inContext`);
- expect(screen.queryByText(navigationBarMessages.allTopics.defaultMessage))
- .not
- .toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Close' }))
- .toBeInTheDocument();
+ expect(screen.queryByText(navigationBarMessages.allTopics.defaultMessage)).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Close' })).toBeInTheDocument();
+ expect(screen.queryByText('Give Feedback')).toBeInTheDocument();
});
});
diff --git a/src/discussions/posts/post-actions-bar/PostActionsBar.jsx b/src/discussions/posts/post-actions-bar/PostActionsBar.jsx
index 4510953c..bed6dfb2 100644
--- a/src/discussions/posts/post-actions-bar/PostActionsBar.jsx
+++ b/src/discussions/posts/post-actions-bar/PostActionsBar.jsx
@@ -11,6 +11,7 @@ import {
} from '@edx/paragon';
import { Close } from '@edx/paragon/icons';
+import Feedback from '../../../components/Feedback';
import { Routes } from '../../../data/constants';
import { DiscussionContext } from '../../common/context';
import { discussionsPath } from '../../utils';
@@ -29,6 +30,7 @@ function PostActionsBar({
const handleCloseInContext = () => null;
return (
+
{!inContext && (
<>