Skip to content

Commit 1240cdc

Browse files
committed
feat: implement footer using UI Plugin approach using frontend-plugin-framework
1 parent 1aa6b3e commit 1240cdc

File tree

8 files changed

+398
-108
lines changed

8 files changed

+398
-108
lines changed

package-lock.json

Lines changed: 221 additions & 81 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@
5656
"@fortawesome/free-brands-svg-icons": "6.4.2",
5757
"@fortawesome/free-regular-svg-icons": "6.4.2",
5858
"@fortawesome/free-solid-svg-icons": "6.4.2",
59-
"@fortawesome/react-fontawesome": "0.2.0"
59+
"@fortawesome/react-fontawesome": "0.2.0",
60+
"@openedx-plugins/footer-links": "file:../src/plugins/footer-links",
61+
"@openedx/frontend-plugin-framework": "file:../frontend-plugin-framework"
6062
},
6163
"peerDependencies": {
6264
"@edx/frontend-platform": "^4.0.0 || ^5.0.0",

src/components/Footer.jsx

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { ensureConfig } from '@edx/frontend-platform/config';
66
import { AppContext } from '@edx/frontend-platform/react';
77
import { Image } from '@edx/paragon';
88
import { getConfig } from '@edx/frontend-platform';
9+
import { PluginSlot } from '@openedx/frontend-plugin-framework/src/index';
10+
import FooterLinks from '../plugins/footer-links';
911

1012
import messages from './Footer.messages';
1113
import LanguageSelector from './LanguageSelector';
@@ -51,35 +53,42 @@ class SiteFooter extends React.Component {
5153
<div className="footer-top">
5254
<div className="powered-area">
5355
<ul className="logo-list">
54-
<li>{intl.formatMessage(messages['footer.poweredby.text'])}</li>
55-
<li>
56-
<a href="https://docs.tutor.overhang.io" rel="noreferrer" target="_blank">
57-
<Image
58-
src={`${config.LMS_BASE_URL}/static/indigo/images/tutor-logo.png`}
59-
alt={intl.formatMessage(messages['footer.tutorlogo.altText'])}
60-
width="57"
61-
/>
62-
</a>
63-
</li>
64-
<li>
65-
<a href="https://open.edx.org" rel="noreferrer" target="_blank">
66-
<Image
67-
src={logo || `${config.LMS_BASE_URL}/static/indigo/images/openedx-logo.png`}
68-
alt={intl.formatMessage(messages['footer.logo.altText'])}
69-
width="79"
70-
/>
71-
</a>
72-
</li>
56+
<PluginSlot id="poweredby_text_slot"><li>{intl.formatMessage(messages['footer.poweredby.text'])}</li></PluginSlot>
57+
<PluginSlot id="tutor_logo_slot">
58+
<li>
59+
<a href="https://docs.tutor.overhang.io" rel="noreferrer" target="_blank">
60+
<Image
61+
src={`${config.LMS_BASE_URL}/static/indigo/images/tutor-logo.png`}
62+
alt={intl.formatMessage(messages['footer.tutorlogo.altText'])}
63+
width="57"
64+
/>
65+
</a>
66+
</li>
67+
</PluginSlot>
68+
<PluginSlot id="openedx_logo_slot">
69+
<li>
70+
<a href="https://open.edx.org" rel="noreferrer" target="_blank">
71+
<Image
72+
src={logo || `${config.LMS_BASE_URL}/static/indigo/images/openedx-logo.png`}
73+
alt={intl.formatMessage(messages['footer.logo.altText'])}
74+
width="79"
75+
/>
76+
</a>
77+
</li>
78+
</PluginSlot>
7379
</ul>
7480
</div>
7581
</div>
76-
<span className="copyright-site">{intl.formatMessage(messages['footer.copyright.text'])}</span>
77-
{showLanguageSelector && (
78-
<LanguageSelector
79-
options={supportedLanguages}
80-
onSubmit={onLanguageSelected}
81-
/>
82-
)}
82+
<PluginSlot id="footer-middle"><FooterLinks /></PluginSlot>
83+
<PluginSlot id="copyright_text_slot"><span className="copyright-site">{intl.formatMessage(messages['footer.copyright.text'])}</span></PluginSlot>
84+
<PluginSlot id="lang_selector_slot">
85+
{showLanguageSelector && (
86+
<LanguageSelector
87+
options={supportedLanguages}
88+
onSubmit={onLanguageSelected}
89+
/>
90+
)}
91+
</PluginSlot>
8392
</footer>
8493
</div>
8594
);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { useEffect, useState } from 'react';
2+
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
3+
import { getHttpClient } from '@edx/frontend-platform/auth';
4+
5+
const useFooterLinks = () => {
6+
const [data, setData] = useState({});
7+
const [loading, setLoading] = useState(false);
8+
9+
useEffect(() => {
10+
const fetchData = async () => {
11+
const url = `${getConfig().LMS_BASE_URL}/api/branding/v1/footer`;
12+
setLoading(true);
13+
const { data: footerLinks } = await getHttpClient().get(url, {
14+
headers: {
15+
Accept: 'application/json',
16+
},
17+
18+
});
19+
const camelCasedData = camelCaseObject(footerLinks);
20+
setData(camelCasedData);
21+
setLoading(false);
22+
};
23+
24+
fetchData();
25+
}, []);
26+
27+
return { data, loading };
28+
};
29+
30+
export default useFooterLinks;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
3+
import useFooterLinks from '@edx/frontend-component-footer/components/data/fetchFooterLinks';
4+
import { PluginSlot } from '@openedx/frontend-plugin-framework/src/index';
5+
6+
import { LinkComponent } from './LinkComponent';
7+
8+
const FooterLinks = () => {
9+
const { data, loading } = useFooterLinks();
10+
11+
if (loading) { return (<div>Loading...</div>); }
12+
13+
return (
14+
<div className="footer-links-container">
15+
<div className="footer-navigation-container">
16+
<PluginSlot id="footer-links">
17+
<LinkComponent data={data} />
18+
</PluginSlot>
19+
</div>
20+
</div>
21+
);
22+
};
23+
24+
export default FooterLinks;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/* eslint-disable react/prop-types */
2+
/* eslint-disable react/forbid-prop-types */
3+
import React from 'react';
4+
import PropTypes from 'prop-types';
5+
6+
const LinkComponent = ({ data }) => (
7+
<ul className="nav nav-list">
8+
{
9+
data.navigationLinks?.map((link) => (
10+
<li className="nav-item" key={link.name}>
11+
<a className="nav-link" href={link.url}>{link.title}</a>
12+
</li>
13+
))
14+
}
15+
{
16+
data.legalLinks?.map((link) => (
17+
<li className="nav-item" key={link.name}>
18+
<a className="nav-link" href={link.url}>{link.title}</a>
19+
</li>
20+
))
21+
}
22+
</ul>
23+
);
24+
25+
LinkComponent.propTypes = {
26+
data: PropTypes.objectOf(PropTypes.shape({
27+
businessLinks: PropTypes.array,
28+
connectLinks: PropTypes.array,
29+
copyright: PropTypes.string,
30+
edxOrgLink: PropTypes.objectOf(PropTypes.shape({
31+
text: PropTypes.string,
32+
url: PropTypes.string,
33+
})),
34+
legalLinks: PropTypes.arrayOf(PropTypes.shape({
35+
name: PropTypes.string,
36+
title: PropTypes.string,
37+
url: PropTypes.string,
38+
})),
39+
logoImage: PropTypes.string,
40+
mobileLinks: PropTypes.array,
41+
moreInfoLinks: PropTypes.array,
42+
navigationLinks: PropTypes.arrayOf(PropTypes.shape({
43+
name: PropTypes.string,
44+
title: PropTypes.string,
45+
url: PropTypes.string,
46+
})),
47+
openedxLink: PropTypes.objectOf(PropTypes.shape({
48+
image: PropTypes.string,
49+
title: PropTypes.string,
50+
url: PropTypes.string,
51+
})),
52+
socialLinks: PropTypes.array,
53+
})),
54+
};
55+
56+
LinkComponent.defaultProps = {
57+
data: {
58+
navigationLinks: [],
59+
legalLinks: [],
60+
},
61+
};
62+
63+
// eslint-disable-next-line import/prefer-default-export
64+
export { LinkComponent };

src/plugins/footer-links/index.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import FooterLinks from './footerLinks';
2+
3+
export default FooterLinks;

src/plugins/footer-links/package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "@openedx-plugins/footer-links",
3+
"version": "0.1.0",
4+
"description": "Footer Links configuration",
5+
"peerDependencies": {
6+
"@edx/frontend-component-footer": "*",
7+
"@edx/frontend-platform": "*",
8+
"@edx/paragon": "*",
9+
"@openedx/frontend-plugin-framework": "*",
10+
"prop-types": "*",
11+
"react": "*"
12+
},
13+
"peerDependenciesMeta": {
14+
"@edx/frontend-component-footer": {
15+
"optional": true
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)