feat: use frontend-plugin-framework to provide a FooterSlot
This commit is contained in:
@@ -6,7 +6,7 @@ import { logError } from '@edx/frontend-platform/logging';
|
||||
import { initializeHotjar } from '@edx/frontend-enterprise-hotjar';
|
||||
|
||||
import { ErrorPage, AppContext } from '@edx/frontend-platform/react';
|
||||
import Footer from '@edx/frontend-component-footer';
|
||||
import FooterSlot from '@openedx/frontend-slot-footer';
|
||||
import { Alert } from '@openedx/paragon';
|
||||
|
||||
import { RequestKeys } from 'data/constants/requests';
|
||||
@@ -109,7 +109,7 @@ export const App = () => {
|
||||
)}
|
||||
</main>
|
||||
</AppWrapper>
|
||||
<Footer logo={getConfig().LOGO_POWERED_BY_OPEN_EDX_URL_SVG} />
|
||||
<FooterSlot />
|
||||
<ZendeskFab />
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { shallow } from '@edx/react-unit-test-utils';
|
||||
|
||||
import Footer from '@edx/frontend-component-footer';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
@@ -15,7 +14,7 @@ import { ExperimentProvider } from 'ExperimentContext';
|
||||
import { App } from './App';
|
||||
import messages from './messages';
|
||||
|
||||
jest.mock('@edx/frontend-component-footer', () => 'Footer');
|
||||
jest.mock('@edx/frontend-component-footer', () => ({ FooterSlot: 'Footer' }));
|
||||
|
||||
jest.mock('containers/Dashboard', () => 'Dashboard');
|
||||
jest.mock('containers/LearnerDashboardHeader', () => 'LearnerDashboardHeader');
|
||||
@@ -38,8 +37,6 @@ jest.mock('hooks', () => ({
|
||||
}));
|
||||
jest.mock('data/store', () => 'data/store');
|
||||
|
||||
const logo = 'fakeLogo.png';
|
||||
|
||||
jest.mock('@edx/frontend-platform', () => ({
|
||||
getConfig: jest.fn(() => ({})),
|
||||
}));
|
||||
@@ -66,9 +63,6 @@ describe('App router component', () => {
|
||||
it('displays learner dashboard header', () => {
|
||||
expect(el.instance.findByType(LearnerDashboardHeader).length).toEqual(1);
|
||||
});
|
||||
test('Footer logo drawn from env variable', () => {
|
||||
expect(el.instance.findByType(Footer)[0].props.logo).toEqual(logo);
|
||||
});
|
||||
it('wraps the header and main components in an AppWrapper widget container', () => {
|
||||
const container = el.instance.findByType(AppWrapper)[0];
|
||||
expect(container.children[0].type).toEqual('LearnerDashboardHeader');
|
||||
@@ -78,7 +72,7 @@ describe('App router component', () => {
|
||||
describe('no network failure', () => {
|
||||
beforeAll(() => {
|
||||
reduxHooks.useRequestIsFailed.mockReturnValue(false);
|
||||
getConfig.mockReturnValue({ LOGO_POWERED_BY_OPEN_EDX_URL_SVG: logo });
|
||||
getConfig.mockReturnValue({});
|
||||
el = shallow(<App />);
|
||||
});
|
||||
runBasicTests();
|
||||
@@ -96,7 +90,7 @@ describe('App router component', () => {
|
||||
describe('no network failure with optimizely url', () => {
|
||||
beforeAll(() => {
|
||||
reduxHooks.useRequestIsFailed.mockReturnValue(false);
|
||||
getConfig.mockReturnValue({ LOGO_POWERED_BY_OPEN_EDX_URL_SVG: logo, OPTIMIZELY_URL: 'fake.url' });
|
||||
getConfig.mockReturnValue({ OPTIMIZELY_URL: 'fake.url' });
|
||||
el = shallow(<App />);
|
||||
});
|
||||
runBasicTests();
|
||||
@@ -114,7 +108,7 @@ describe('App router component', () => {
|
||||
describe('no network failure with optimizely project id', () => {
|
||||
beforeAll(() => {
|
||||
reduxHooks.useRequestIsFailed.mockReturnValue(false);
|
||||
getConfig.mockReturnValue({ LOGO_POWERED_BY_OPEN_EDX_URL_SVG: logo, OPTIMIZELY_PROJECT_ID: 'fakeId' });
|
||||
getConfig.mockReturnValue({ OPTIMIZELY_PROJECT_ID: 'fakeId' });
|
||||
el = shallow(<App />);
|
||||
});
|
||||
runBasicTests();
|
||||
@@ -132,7 +126,7 @@ describe('App router component', () => {
|
||||
describe('initialize failure', () => {
|
||||
beforeAll(() => {
|
||||
reduxHooks.useRequestIsFailed.mockImplementation((key) => key === RequestKeys.initialize);
|
||||
getConfig.mockReturnValue({ LOGO_POWERED_BY_OPEN_EDX_URL_SVG: logo });
|
||||
getConfig.mockReturnValue({});
|
||||
el = shallow(<App />);
|
||||
});
|
||||
runBasicTests();
|
||||
@@ -150,7 +144,7 @@ describe('App router component', () => {
|
||||
describe('refresh failure', () => {
|
||||
beforeAll(() => {
|
||||
reduxHooks.useRequestIsFailed.mockImplementation((key) => key === RequestKeys.refreshList);
|
||||
getConfig.mockReturnValue({ LOGO_POWERED_BY_OPEN_EDX_URL_SVG: logo });
|
||||
getConfig.mockReturnValue({});
|
||||
el = shallow(<App />);
|
||||
});
|
||||
runBasicTests();
|
||||
|
||||
@@ -27,9 +27,7 @@ exports[`App router component component initialize failure snapshot 1`] = `
|
||||
</Alert>
|
||||
</main>
|
||||
</AppWrapper>
|
||||
<Footer
|
||||
logo="fakeLogo.png"
|
||||
/>
|
||||
<FooterSlot />
|
||||
<ZendeskFab />
|
||||
</div>
|
||||
</Fragment>
|
||||
@@ -58,9 +56,7 @@ exports[`App router component component no network failure snapshot 1`] = `
|
||||
</ExperimentProvider>
|
||||
</main>
|
||||
</AppWrapper>
|
||||
<Footer
|
||||
logo="fakeLogo.png"
|
||||
/>
|
||||
<FooterSlot />
|
||||
<ZendeskFab />
|
||||
</div>
|
||||
</Fragment>
|
||||
@@ -92,9 +88,7 @@ exports[`App router component component no network failure with optimizely proje
|
||||
</ExperimentProvider>
|
||||
</main>
|
||||
</AppWrapper>
|
||||
<Footer
|
||||
logo="fakeLogo.png"
|
||||
/>
|
||||
<FooterSlot />
|
||||
<ZendeskFab />
|
||||
</div>
|
||||
</Fragment>
|
||||
@@ -126,9 +120,7 @@ exports[`App router component component no network failure with optimizely url s
|
||||
</ExperimentProvider>
|
||||
</main>
|
||||
</AppWrapper>
|
||||
<Footer
|
||||
logo="fakeLogo.png"
|
||||
/>
|
||||
<FooterSlot />
|
||||
<ZendeskFab />
|
||||
</div>
|
||||
</Fragment>
|
||||
@@ -161,9 +153,7 @@ exports[`App router component component refresh failure snapshot 1`] = `
|
||||
</Alert>
|
||||
</main>
|
||||
</AppWrapper>
|
||||
<Footer
|
||||
logo="fakeLogo.png"
|
||||
/>
|
||||
<FooterSlot />
|
||||
<ZendeskFab />
|
||||
</div>
|
||||
</Fragment>
|
||||
|
||||
50
src/plugin-slots/FooterSlot/README.md
Normal file
50
src/plugin-slots/FooterSlot/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Footer Slot
|
||||
|
||||
### Slot ID: `footer_slot`
|
||||
|
||||
## Description
|
||||
|
||||
This slot is used to replace/modify/hide the footer.
|
||||
|
||||
The implementation of the `FooterSlot` component lives in [the `frontend-slot-footer` repository](https://github.com/openedx/frontend-slot-footer/).
|
||||
|
||||
## Example
|
||||
|
||||
The following `env.config.jsx` will replace the default footer.
|
||||
|
||||

|
||||
|
||||
with a simple custom footer
|
||||
|
||||

|
||||
|
||||
```jsx
|
||||
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
|
||||
|
||||
const config = {
|
||||
pluginSlots: {
|
||||
footer_slot: {
|
||||
plugins: [
|
||||
{
|
||||
// Hide the default footer
|
||||
op: PLUGIN_OPERATIONS.Hide,
|
||||
widgetId: 'default_contents',
|
||||
},
|
||||
{
|
||||
// Insert a custom footer
|
||||
op: PLUGIN_OPERATIONS.Insert,
|
||||
widget: {
|
||||
id: 'custom_footer',
|
||||
type: DIRECT_PLUGIN,
|
||||
RenderWidget: () => (
|
||||
<h1 style={{textAlign: 'center'}}>🦶</h1>
|
||||
),
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default config;
|
||||
```
|
||||
BIN
src/plugin-slots/FooterSlot/images/custom_footer.png
Normal file
BIN
src/plugin-slots/FooterSlot/images/custom_footer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
src/plugin-slots/FooterSlot/images/default_footer.png
Normal file
BIN
src/plugin-slots/FooterSlot/images/default_footer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
3
src/plugin-slots/README.md
Normal file
3
src/plugin-slots/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# `frontend-app-learner-dashboard` Plugin Slots
|
||||
|
||||
* [`footer_slot`](./FooterSlot/)
|
||||
Reference in New Issue
Block a user