feat(curriculum): adding reusable profile card component workshop (#57400)

Co-authored-by: Dario-DC <105294544+Dario-DC@users.noreply.github.com>
Co-authored-by: Tom <20648924+moT01@users.noreply.github.com>
Co-authored-by: Zaira <33151350+zairahira@users.noreply.github.com>
This commit is contained in:
Kolade Chris
2024-12-13 18:43:45 +01:00
committed by GitHub
parent 144cf138c3
commit 31fdbbc67e
11 changed files with 1116 additions and 1 deletions

View File

@@ -3342,7 +3342,12 @@
"In these lecture videos, you will learn about working with data in React."
]
},
"cdfr": { "title": "263", "intro": [] },
"workshop-reusable-profile-card-component": {
"title": "Build a Reusable Profile Card Component",
"intro": [
"In this workshop, you will learn how to work with props by building a reusable profile card component."
]
},
"lab-mood-board": {
"title": "Build a Mood Board",
"intro": [

View File

@@ -0,0 +1,9 @@
---
title: Introduction to the Reusable Profile Card Component
block: workshop-reusable-profile-card-component
superBlock: full-stack-developer
---
## Introduction to the Reusable Profile Card Component
This is a test for the new project-based curriculum.

View File

@@ -0,0 +1,41 @@
{
"name": "Build a Reusable Profile Card Component",
"isUpcomingChange": true,
"blockType": "workshop",
"blockLayout": "challenge-grid",
"usesMultifileEditor": true,
"hasEditableBoundaries": true,
"dashedName": "workshop-reusable-profile-card-component",
"superBlock": "full-stack-developer",
"challengeOrder": [
{
"id": "674ef11f75254548672d998c",
"title": "Step 1"
},
{
"id": "674ef2d357676e50e4691658",
"title": "Step 2"
},
{
"id": "674ef2d357676e50e4691659",
"title": "Step 3"
},
{
"id": "674ef2d357676e50e469165a",
"title": "Step 4"
},
{
"id": "674ef2d357676e50e469165b",
"title": "Step 5"
},
{
"id": "674ef2d357676e50e469165c",
"title": "Step 6"
},
{
"id": "674ef2d357676e50e469165d",
"title": "Step 7"
}
],
"helpCategory": "JavaScript"
}

View File

@@ -0,0 +1,125 @@
---
id: 674ef11f75254548672d998c
title: Step 1
challengeType: 0
dashedName: step-1
demoType: onLoad
---
# --description--
In this project, you will learn how to work with props by building a reusable profile card component.
Start by using the `export` keyword to create a `Card` functional component with `name`, `title`, and `bio` as the props. Don't forget to make sure they're all wrapped in a curly brace. That way, you destructure them instead of accessing them from `props`.
Also, return a pair of parentheses with an empty string inside of them for now.
# --hints--
You should create and export a `Card` functional component. Don't forget to return an empty string inside it.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.Card)
);
assert.lengthOf(mockedComponent.find('Card'), 1);
```
Your `Card` component should have a `name`, `title`, and `bio` props.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.Card)
);
const componentFunction = mockedComponent.type();
const propsSource = componentFunction.toString();
assert.match(propsSource, /\bname\b/);
assert.match(propsSource, /\btitle\b/);
assert.match(propsSource, /\bbio\b/);
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Reusable Card 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 { App } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
);
</script>
</body>
</html>
```
```css
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.card {
border: 5px solid var(--dark-orange);
border-radius: 10px;
width: 100%;
padding: 20px;
margin: 10px 0;
background-color: var(--light-grey);
}
.card-title {
border-bottom: 4px solid var(--dark-orange);
width: fit-content;
}
@media (min-width: 768px) {
.card {
width: 300px;
}
}
```
```jsx
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,116 @@
---
id: 674ef2d357676e50e4691658
title: Step 2
challengeType: 0
dashedName: step-2
---
# --description--
Inside the return, remove the empty string, then create a `div` element with a `className` of `card`.
# --hints--
You should not have an empty string in your Card component.
```js
assert.notMatch(code, /""/)
```
You should create a `div` element with the `className` `card` at the top level of your `Card` component.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.Card)
);
assert.equal(mockedComponent.childAt(0).type(), 'div');
assert.isTrue(mockedComponent.childAt(0).hasClass('card'));
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Reusable Card 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 { App } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
);
</script>
</body>
</html>
```
```css
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.card {
border: 5px solid var(--dark-orange);
border-radius: 10px;
width: 100%;
padding: 20px;
margin: 10px 0;
background-color: var(--light-grey);
}
.card-title {
border-bottom: 4px solid var(--dark-orange);
width: fit-content;
}
@media (min-width: 768px) {
.card {
width: 300px;
}
}
```
```jsx
export function Card({ name, title, bio }) {
return (
--fcc-editable-region--
""
--fcc-editable-region--
)
}
```

View File

@@ -0,0 +1,166 @@
---
id: 674ef2d357676e50e4691659
title: Step 3
challengeType: 0
dashedName: step-3
---
# --description--
Inside the `div` element, create an `h2` element and interpolate the `name` prop as its text.
Also, inside the `div`, create a paragraph with the `className` of `card-title` to interpolate the `title` prop, and another paragraph to interpolate the `bio` prop.
# --hints--
You should create an `h2` element inside your `div` element.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.Card)
);
const h2Elem = mockedComponent.find('h2');
assert.equal(h2Elem.parent().type(), 'div');
```
Your `h2` element should have `{name}` as its text content.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.Card, { name: 'nameVal' })
);
const h2Elem = mockedComponent.find('h2');
assert.equal(h2Elem.text(), 'nameVal');
```
You should create a `p` tag with the `className` of `card-title` inside your `div` element.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.Card)
);
const pElem = mockedComponent.find('p.card-title');
assert.equal(pElem.parent().type(), 'div');
```
Your `p` element with `className` of `card-title` should have `{title}` as its text content.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.Card, { title: 'titleVal' })
);
const pElem = mockedComponent.find('p.card-title');
assert.equal(pElem.text(), 'titleVal');
assert.equal(pElem.parent().type(), 'div');
```
You should create another `p` element with `{bio}` as its text.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.Card, { bio: 'bioVal' })
);
const secondPElem = mockedComponent.children().childAt(2)
assert.equal(secondPElem.type(), 'p')
assert.equal(secondPElem.text(), 'bioVal');
assert.equal(secondPElem.parent().type(), 'div');
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Reusable Card 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 { App } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
);
</script>
</body>
</html>
```
```css
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.card {
border: 5px solid var(--dark-orange);
border-radius: 10px;
width: 100%;
padding: 20px;
margin: 10px 0;
background-color: var(--light-grey);
}
.card-title {
border-bottom: 4px solid var(--dark-orange);
width: fit-content;
}
@media (min-width: 768px) {
.card {
width: 300px;
}
}
```
```jsx
export function Card({ name, title, bio }) {
return (
--fcc-editable-region--
<div className="card">
</div>
--fcc-editable-region--
)
}
```

View File

@@ -0,0 +1,117 @@
---
id: 674ef2d357676e50e469165a
title: Step 4
challengeType: 0
dashedName: step-4
---
# --description--
To start using the `Card` component, use the `export` keyword to create an `App` functional component.
Inside the `App` component, return a pair of parentheses containing an empty string.
# --hints--
You should export an `App` functional component.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.App)
);
assert.lengthOf(mockedComponent.find('App'), 1);
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Reusable Card 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 { App } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
);
</script>
</body>
</html>
```
```css
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.card {
border: 5px solid var(--dark-orange);
border-radius: 10px;
width: 100%;
padding: 20px;
margin: 10px 0;
background-color: var(--light-grey);
}
.card-title {
border-bottom: 4px solid var(--dark-orange);
width: fit-content;
}
@media (min-width: 768px) {
.card {
width: 300px;
}
}
```
```jsx
export function Card({ name, title, bio }) {
return (
<div className="card">
<h2>{name}</h2>
<p className="card-title">{title}</p>
<p>{bio}</p>
</div>
)
}
--fcc-editable-region--
--fcc-editable-region--
```

View File

@@ -0,0 +1,126 @@
---
id: 674ef2d357676e50e469165b
title: Step 5
challengeType: 0
dashedName: step-5
---
# --description--
Inside your return statement, replace the empty string with a `div` element with a `className` property of `flex-container`.
# --hints--
You should not have an empty string in your Card component.
```js
assert.notMatch(code, /""/)
```
You should create a `div` element with the class `flex-container`.
```js
const mockedComponent = Enzyme.mount(
React.createElement(window.index.App)
);
assert.equal(mockedComponent.childAt(0).type(), 'div');
assert.isTrue(mockedComponent.childAt(0).hasClass('flex-container'));
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Reusable Card 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 { App } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
);
</script>
</body>
</html>
```
```css
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.card {
border: 5px solid var(--dark-orange);
border-radius: 10px;
width: 100%;
padding: 20px;
margin: 10px 0;
background-color: var(--light-grey);
}
.card-title {
border-bottom: 4px solid var(--dark-orange);
width: fit-content;
}
@media (min-width: 768px) {
.card {
width: 300px;
}
}
```
```jsx
export function Card({ name, title, bio }) {
return (
<div className="card">
<h2>{name}</h2>
<p className="card-title">{title}</p>
<p>{bio}</p>
</div>
)
}
export function App() {
return (
--fcc-editable-region--
""
--fcc-editable-region--
);
}
```

View File

@@ -0,0 +1,144 @@
---
id: 674ef2d357676e50e469165c
title: Step 6
challengeType: 0
dashedName: step-6
---
# --description--
Now, use the `Card` component with the `name` prop set to `"Mark"`, the `title` prop set to `"Frontend developer"`, and the `bio` set to `"I like to work with different frontend technologies and play video games."`
# --hints--
You should use the `Card` component as an element with a `name` prop set to `"Mark"`.
```js
const mockedComponent = Enzyme.mount(React.createElement(window.index.App));
const cardItem = mockedComponent.find(window.index.Card);
const cardItemsProps = cardItem.props()
assert.equal(cardItem.props().name, "Mark")
```
You should use the `Card` component as an element with a `title` prop set to `"Frontend developer"`.
```js
const mockedComponent = Enzyme.mount(React.createElement(window.index.App));
const cardItem = mockedComponent.find(window.index.Card);
const cardItemsProps = cardItem.props()
assert.equal(cardItem.props().title, "Frontend developer")
```
You should use the `Card` component as an element with a `bio` prop set to `"I like to work with different frontend technologies and play video games."`.
```js
const mockedComponent = Enzyme.mount(React.createElement(window.index.App));
const cardItem = mockedComponent.find(window.index.Card);
const cardItemsProps = cardItem.props()
assert.equal(cardItem.props().bio, "I like to work with different frontend technologies and play video games.")
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Reusable Card 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 { App } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
);
</script>
</body>
</html>
```
```css
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.card {
border: 5px solid var(--dark-orange);
border-radius: 10px;
width: 100%;
padding: 20px;
margin: 10px 0;
background-color: var(--light-grey);
}
.card-title {
border-bottom: 4px solid var(--dark-orange);
width: fit-content;
}
@media (min-width: 768px) {
.card {
width: 300px;
}
}
```
```jsx
export function Card({ name, title, bio }) {
return (
<div className="card">
<h2>{name}</h2>
<p className="card-title">{title}</p>
<p>{bio}</p>
</div>
)
}
export function App() {
return (
<div className="flex-container">
--fcc-editable-region--
--fcc-editable-region--
</div>
);
}
```

View File

@@ -0,0 +1,265 @@
---
id: 674ef2d357676e50e469165d
title: Step 7
challengeType: 0
dashedName: step-7
---
# --description--
Again, use the `Card` component two more times with the following:
| Props | First Card Values | Second Card Values |
|-------|------------------------------------------------------------|-----------------------------------------------------|
| `name` | `"Tiffany"` | `"Doug"`|
| `title` | `"Engineering manager"` | `"Backend developer"` |
| `bio` | `"I have worked in tech for 15 years and love to help people grow in this industry."` | `"I have been a software developer for over 20 years and I love working with Go and Rust."`|
With that, your reusable profile card component project is complete!
# --hints--
You should use the `Card` component as an element with the appropriate props and first card values.
```js
const mockedComponent = Enzyme.mount(React.createElement(window.index.App));
const cardItems = mockedComponent.find(window.index.Card);
const propsList = cardItems.map(item => item.props());
assert.deepEqual(propsList[1], {
name: 'Tiffany',
title: 'Engineering manager',
bio: 'I have worked in tech for 15 years and love to help people grow in this industry.'
});
```
You should use the `Card` component as an element with the appropriate props and second card values.
```js
const mockedComponent = Enzyme.mount(React.createElement(window.index.App));
const cardItems = mockedComponent.find(window.index.Card);
const propsList = cardItems.map(item => item.props());
assert.deepEqual(propsList[2], {
name: 'Doug',
title: 'Backend developer',
bio: 'I have been a software developer for over 20 years and I love working with Go and Rust.'
});
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Reusable Card 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 { App } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
);
</script>
</body>
</html>
```
```css
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.card {
border: 5px solid var(--dark-orange);
border-radius: 10px;
width: 100%;
padding: 20px;
margin: 10px 0;
background-color: var(--light-grey);
}
.card-title {
border-bottom: 4px solid var(--dark-orange);
width: fit-content;
}
@media (min-width: 768px) {
.card {
width: 300px;
}
}
```
```jsx
export function Card({ name, title, bio }) {
return (
<div className="card">
<h2>{name}</h2>
<p className="card-title">{title}</p>
<p>{bio}</p>
</div>
)
}
export function App() {
return (
<div className="flex-container">
<Card
name="Mark"
title="Frontend developer"
bio="I like to work with different frontend technologies and play video games."
/>
--fcc-editable-region--
--fcc-editable-region--
</div>
);
}
```
# --solutions--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Reusable Card 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 { App } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<App />
);
</script>
</body>
</html>
```
```css
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--dark-orange: #f89808;
}
body {
background-color: var(--dark-grey);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.card {
border: 5px solid var(--dark-orange);
border-radius: 10px;
width: 100%;
padding: 20px;
margin: 10px 0;
background-color: var(--light-grey);
}
.card-title {
border-bottom: 4px solid var(--dark-orange);
width: fit-content;
}
@media (min-width: 768px) {
.card {
width: 300px;
}
}
```
```jsx
export function Card({ name, title, bio }) {
return (
<div className="card">
<h2>{name}</h2>
<p className="card-title">{title}</p>
<p>{bio}</p>
</div>
)
}
export function App() {
return (
<div className="flex-container">
<Card
name="Mark"
title="Frontend developer"
bio="I like to work with different frontend technologies and play video games."
/>
<Card
name="Tiffany"
title="Engineering manager"
bio="I have worked in tech for 15 years and love to help people grow in this industry."
/>
<Card
name="Doug"
title="Backend developer"
bio="I have been a software developer for over 20 years and I love working with Go and Rust."
/>
</div>
);
}
```

View File

@@ -556,6 +556,7 @@
{ "dashedName": "workshop-reusable-mega-navbar" },
{ "dashedName": "lab-reusable-footer" },
{ "dashedName": "lecture-working-with-data-in-react" },
{ "dashedName": "workshop-reusable-profile-card-component" },
{ "dashedName": "lab-mood-board" },
{ "dashedName": "review-react-basics" },
{ "dashedName": "quiz-react-basics" }