Skip to content

Instantly share code, notes, and snippets.

@codecademydev
Created January 12, 2023 11:37
Show Gist options
  • Save codecademydev/7c2835c2281c47c690e4139d9d3c3f17 to your computer and use it in GitHub Desktop.
Save codecademydev/7c2835c2281c47c690e4139d9d3c3f17 to your computer and use it in GitHub Desktop.
Codecademy export
import "./App.css";
import React from "react";
import { Score } from "./features/score/Score.js";
import { Board } from "./features/board/Board.js";
import { useDispatch } from "react-redux";
import { setBoard, resetCards } from "./features/board/boardSlice.js";
const App = () => {
const dispatch = useDispatch();
const startGameHandler = () => {
dispatch(setBoard());
};
const tryAgainHandler = () => {
dispatch(resetCards());
};
return (
<div className="App">
<Score />
<Board />
<footer className="footer">
<button onClick={startGameHandler} className="start-button">
Start Game
</button>
<button onClick={tryAgainHandler} className="try-new-pair-button">
Try New Pair
</button>
</footer>
</div>
);
};
export default App;
import React from "react";
import { CardRow } from "./cardRow/CardRow.js";
import { useSelector } from "react-redux";
import { selectBoard } from "./boardSlice.js";
export const Board = () => {
const currentBoard = useSelector(selectBoard);
const numberOfCards = currentBoard.length;
const columns = 3;
const rows = Math.floor(numberOfCards / columns);
const getRowCards = (row) => {
const rowCards = [];
for (let j = 0; j < columns; j++) {
const cardIndex = row * columns + j;
rowCards.push(currentBoard[cardIndex]);
}
return rowCards;
};
let content = [];
for (let row = 0; row < rows; row++) {
const rowCards = getRowCards(row);
content.push(<CardRow key={row} cards={rowCards} />);
}
return <div className="cards-container">{content}</div>;
};
const initialState = [
{ id: 0, contents: "Provider", visible: true, matched: true },
{ id: 1, contents: "Provider", visible: true, matched: true },
{ id: 2, contents: "selector", visible: true, matched: true },
{ id: 3, contents: "selector", visible: true, matched: true },
{ id: 4, contents: "useSelector()", visible: true, matched: true },
{ id: 5, contents: "useSelector()", visible: true, matched: true },
{ id: 6, contents: "useDispatch()", visible: true, matched: true },
{ id: 7, contents: "useDispatch()", visible: true, matched: true },
{ id: 8, contents: "Pure Function", visible: true, matched: true },
{ id: 9, contents: "Pure Function", visible: true, matched: true },
{ id: 10, contents: "react-redux", visible: true, matched: true },
{ id: 11, contents: "react-redux", visible: true, matched: true },
];
export const boardReducer = (state = initialState, action) => {
switch (action.type) {
case "board/setBoard":
let setState = [];
action.payload.forEach((element, index) =>
setState.push({
id: index,
contents: element,
visible: false,
matched: false,
})
);
return setState;
case "board/flipCard":
let flipState = [...state];
const cardID = action.payload;
flipState[cardID] = { ...state[cardID], visible: true };
const [index1, index2] = flipState
.filter((card) => card.visible)
.map((card) => card.id);
if (index2 !== undefined) {
const card1 = flipState[index1];
const card2 = flipState[index2];
if (card1.contents === card2.contents) {
flipState[index1] = { ...card1, visible: false, matched: true };
flipState[index2] = { ...card2, visible: false, matched: true };
}
}
return flipState;
case "board/resetCards":
return state.map((card) => ({ ...card, visible: false }));
default:
return state;
}
};
const wordPairs = [
"Provider",
"Provider",
"selector",
"selector",
"useSelector()",
"useSelector()",
"useDispatch()",
"useDispatch()",
"Pure Function",
"Pure Function",
"react-redux",
"react-redux",
];
const randomWords = () => {
let words = [];
let newWordPairs = [...wordPairs];
const reps = newWordPairs.length;
for (let i = 0; i < reps; i++) {
const wordIndex = Math.floor(Math.random() * newWordPairs.length);
words.push(newWordPairs[wordIndex]);
newWordPairs.splice(wordIndex, 1);
}
return words;
};
// action creators
export const setBoard = () => {
const words = randomWords();
return {
type: "board/setBoard",
payload: words,
};
};
export const flipCard = (id) => {
return {
type: "board/flipCard",
payload: id,
};
};
export const resetCards = (indices) => {
return {
type: "board/resetCards",
};
};
export const selectBoard = (state) =>
state.board.map((card) => ({
id: card.id,
contents: card.contents,
}));
export const selectVisibleIDs = (state) =>
state.board.filter((card) => card.visible).map((card) => card.id);
export const selectMatchedIDs = (state) =>
state.board.filter((card) => card.matched).map((card) => card.id);
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import {
selectVisibleIDs,
selectMatchedIDs,
flipCard,
resetCards,
} from "../../boardSlice.js";
let cardLogo =
"https://static-assets.codecademy.com/Courses/Learn-Redux/matching-game/codecademy_logo.png";
export const Card = ({ id, contents }) => {
const visibleIDs = useSelector(selectVisibleIDs);
const matchedIDs = useSelector(selectMatchedIDs);
const dispatch = useDispatch();
const flipHandler = (id) => {
dispatch(flipCard(id));
};
const resetHandler = () => {
dispatch(resetCards());
};
let cardStyle = "resting";
let click = () => flipHandler(id);
let cardText = (
<img src={cardLogo} className="logo-placeholder" alt="Card option" />
);
if (visibleIDs.includes(id) || matchedIDs.includes(id)) {
cardText = contents;
click = () => {};
}
if (matchedIDs.includes(id)) {
cardStyle = "matched";
} else if (visibleIDs.length === 2) {
cardStyle = "no-match";
}
if (visibleIDs.length === 2) {
click = resetHandler;
}
return (
<button onClick={click} className={`card ${cardStyle}`}>
{cardText}
</button>
);
};
import React from "react";
import { Card } from "./card/Card.js";
export const CardRow = ({ cards }) => {
const content = cards.map((card) => (
<Card key={card.id} id={card.id} contents={card.contents} />
));
return <>{content}</>;
};
@import url("https://fonts.googleapis.com/css2?family=Oxygen:wght@700&display=swap");
html,
body {
margin: 0;
}
* {
font-family: "Oxygen", sans-serif;
font-weight: bold;
}
.card {
padding: 20px 0;
text-align: center;
border-radius: 6px;
border: solid 1px #141c3a;
background-color: #141c3a;
color: white;
cursor: pointer;
height: 75px;
font-size: 16px;
}
.card:hover,
.card:focus {
background-color: #2e4085;
}
.cards-container {
display: grid;
grid-template-columns: repeat(3, 138px);
grid-auto-rows: 1fr;
gap: 16px 16px;
margin: 0 auto;
width: fit-content;
padding: 24px 0 33px 0;
}
.card.selected {
background-color: initial;
color: #141c3a;
border: solid 1px #141c3a;
}
.card.matched {
color: #4fe0b0;
}
.card.no-match {
color: #fd4d3f;
}
.logo-placeholder {
width: 120px;
}
.score-container {
background-color: #f2f2f2;
padding: 18px 158px 23px 159px;
text-align: center;
font-size: 32px;
}
.footer > button {
width: 50%;
padding: 19px 40px 19px 40px;
font-size: 20px;
border: none;
color: #ffffff;
cursor: pointer;
}
.start-button {
background-color: #141c3a;
}
.start-button:hover,
.start-button:focus {
background-color: #2c3f81;
}
.try-new-pair-button {
background-color: #6400e4;
}
.try-new-pair-button:hover,
.try-new-pair-button:focus {
background-color: #7d1aff;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="stylesheet" href="./index.css" />
<title>React App</title>
</head>
<body>
<div id="root"></div>
<script src="https://content.codecademy.com/courses/React/react-16-full.min.js"></script>
<script src="./src/index.compiled.js"></script>
</body>
</html>
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { store } from "./app/store.js";
import { Provider } from "react-redux";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
import React from "react";
import { useSelector } from "react-redux";
import { selectMatchedIDs } from "../board/boardSlice.js";
export const Score = () => {
const cardsMatched = useSelector(selectMatchedIDs);
let matches = cardsMatched.length;
return <div className="score-container">Matched: {matches}</div>;
};
import { combineReducers, createStore } from "redux";
import { boardReducer } from "../features/board/boardSlice.js";
const rootReducer = combineReducers({
board: boardReducer,
});
export const store = createStore(rootReducer);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment