Skip to content

Commit

Permalink
feat(curriculum): add reusable footer React lab (freeCodeCamp#57202)
Browse files Browse the repository at this point in the history
Co-authored-by: moT01 <[email protected]>
  • Loading branch information
zairahira and moT01 authored Dec 10, 2024
1 parent 52cef31 commit 674a318
Show file tree
Hide file tree
Showing 5 changed files with 299 additions and 1 deletion.
5 changes: 4 additions & 1 deletion client/i18n/locales/english/intro.json
Original file line number Diff line number Diff line change
Expand Up @@ -3306,7 +3306,10 @@
]
},
"oxiv": { "title": "260", "intro": [] },
"fjvx": { "title": "261", "intro": [] },
"lab-reusable-footer": {
"title": "Build a Reusable Footer",
"intro": ["In this lab, you will use React to build a reusable footer."]
},
"lecture-working-with-data-in-react": {
"title": "Working with Data in React",
"intro": [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: Introduction to the Build a Reusable Footer
block: lab-reusable-footer
superBlock: full-stack-developer
---

## Introduction to the Build a Reusable Footer

In this lab, you will use React to build a reusable footer.
11 changes: 11 additions & 0 deletions curriculum/challenges/_meta/lab-reusable-footer/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "Build a Reusable Footer",
"isUpcomingChange": true,
"usesMultifileEditor": true,
"dashedName": "lab-reusable-footer",
"superBlock": "full-stack-developer",
"challengeOrder": [{ "id": "673b02b03134b04637bf7055", "title": "Build a Reusable Footer" }],
"helpCategory": "HTML-CSS",
"blockLayout": "link",
"blockType": "lab"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
---
id: 673b02b03134b04637bf7055
title: Build a Reusable Footer
challengeType: 14
dashedName: build-a-reusable-footer
demoType: onClick
---

# --description--

**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab.

**User Stories:**

1. You should export a `Footer` component.
2. Your `Footer` component should return a `footer` element that contains all the other elements.
3. Your `footer` element should have:

- At least three unordered lists, each with at least two list items.
- At least one paragraph element with a copyright `©` symbol.
- At least three links with the `href` value set to `#` and the link content set to an icon or text of your choice.

# --hints--

You should export a `Footer` component.

```js
const mockedComponent = Enzyme.mount(React.createElement(window.index.Footer));
assert.lengthOf(mockedComponent.find('Footer'), 1);
```

Your `Footer` component should return a `footer` element.

```js
assert.equal(Enzyme.shallow(React.createElement(window.index.Footer)).type(), 'footer');
```

Your `footer` should have at least three unordered lists.

```js
const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer));
assert.isAtLeast(mockedComponent.find('ul').length, 3);
```

Each of your unordered lists should have at least two list items.

```js
const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer));
const uls = mockedComponent.find('ul');
uls.forEach(ul => {
assert.isAtLeast(ul.find('li').length, 2);
});

assert.isAtLeast(uls.length, 1);
```

Your `footer` should have at least one paragraph element.

```js
const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer));
assert.isAtLeast(mockedComponent.find('p').length, 1);
```

You should have a copyright (`©`) symbol within one of your paragraphs.

```js
const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer));
let hasCopyright = false;
mockedComponent.find('p').forEach(p => {
if(p.text().includes('©')) {
hasCopyright = true;
}
});
assert.isTrue(hasCopyright);
```

Your `footer` should have at least three links with the `href` value set to `#`.

```js
const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer));
assert.isAtLeast(mockedComponent.find('a[href="#"]').length, 3);
```

None of your links should be empty.

```js
const mockedComponent = Enzyme.shallow(React.createElement(window.index.Footer));
mockedComponent.find('a').forEach(a => {
assert.isAtLeast(a.text().length, 1);
});
assert.isAtLeast(mockedComponent.find('a').length, 1);
```

Your `Footer` component should be rendered to the page's `#root` element.

```js
const mockedComponent = Enzyme.mount(React.createElement(window.index.Footer));
assert.equal(mockedComponent.html(), document.getElementById('root').innerHTML);
```

# --seed--

## --seed-contents--

```html
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>Reusable Footer Component</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>

<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { Footer } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<Footer />
);
</script>
</body>

</html>
```

```css

```

```jsx
export const Footer = () => {

};
```

# --solutions--

```html
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>Reusable Footer Component</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>

<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { Footer } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<Footer />
);
</script>
</body>

</html>
```

```css
.footer {
background-color: #e3e1eb;
padding: 20px;
text-align: center;
border-top: 1px solid #e5e7eb;
font-family: Arial, sans-serif;
}

.footer-section {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
justify-content: center;
margin-bottom: 20px;
align-items: center;
}

.footer ul {
list-style: none;
padding: 0;
margin: 0;
}

.footer li {
margin-bottom: 10px;
}

.footer a {
text-decoration: none;
color: #1f2937;
}

.footer a:hover {
color: #6366f1;
}

.footer p {
color: #6b7280;
margin-top: 20px;
}

.footer-icons {
margin-top: 20px;
display: flex;
justify-content: center;
}

.footer-icons a {
margin: 0 10px;
font-size: 24px;
color: #6b7280;
text-decoration: none;
}

.footer-icons a:hover {
color: #6366f1;
}
```

```jsx
export const Footer = () =>
<footer className="footer">
<div className="footer-section">
<ul>
<li><a href="#">Fitness Dashboard</a></li>
<li><a href="#">Services</a></li>
</ul>
<ul>
<li><a href="#">Watch Videos</a></li>
<li><a href="#">Discord</a></li>
</ul>
<ul>
<li><a href="#">Privacy Policy</a></li>
<li><a href="#">Terms & Conditions</a></li>
</ul>
</div>
<p>© 2024 Fitness Dashboard. All Rights Reserved.</p>
<div className="footer-icons">
<a href="#">&#x1F3AE;</a>
<a href="#">&#x1F426;</a>
<a href="#">&#x1F4BB;</a>
<a href="#">&#x1F3C0;</a>
</div>
</footer>
```
1 change: 1 addition & 0 deletions curriculum/superblock-structure/full-stack.json
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@
{
"dashedName": "lecture-introduction-to-javascript-libraries-and-frameworks"
},
{ "dashedName": "lab-reusable-footer" },
{ "dashedName": "lecture-working-with-data-in-react" },
{ "dashedName": "review-react-basics" },
{ "dashedName": "quiz-react-basics" }
Expand Down

0 comments on commit 674a318

Please sign in to comment.