Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/Wordle/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const WORD_LENGTH = 5;
function Grid({ guesses, currentGuess, getLetterColor, isGameOver, activeIndex, setActiveIndex }) {
return (
<div className={styles.grid}>
<span className={styles.label}>Descubra a palavra do mundo tech</span>
<span className={styles.label}>Descubra a palavra!</span>

{Array.from({ length: MAX_ATTEMPTS }).map((_, rowIndex) => {
const isActiveRow = !isGameOver && rowIndex === guesses.length;
Expand Down
35 changes: 22 additions & 13 deletions src/components/common/FinishModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,49 @@ import Button from "../Button";
import styles from "./styles.module.css";
import confetti from "canvas-confetti";

function FinishModal({ showModal }) {
function FinishModal({ showModal, correctWord, playerWin }) {
const navigate = useNavigate();

const modalClasses = classNames(styles["all"], {
[styles["show"]]: showModal
});

useEffect(() => {
if(showModal) {
if (showModal) {
confetti({ particleCount: 150, spread: 100, origin: { y: 0.6 } });
}
}, [showModal])

return (
const headerText = playerWin ? "Você conseguiu!" : "Não foi dessa vez :(";
const mainTitle = playerWin ? "Parabéns" : "Tente novamente!";
const mainText = playerWin ? (
<>
Você acertou, a palavra era:{" "}
<span className={styles["highlight"]}>{correctWord}</span>
{" "}vamos jogar de novo?
</>
) : (
<>
Você não conseguiu descobrir a palavra, ela era:{" "}
<span className={styles["highlight"]}>{correctWord}</span>
{", tente mais uma vez!"}
</>
);

return (
<div className={modalClasses}>
<div className={styles["content"]}></div>
<div className={styles["modal"]}>
<div className={styles["header"]}>
<h2>Task Finalizada!</h2>
<h2>{headerText}</h2>
</div>
<span className={styles["messageHeader"]}>
Parabéns!
{mainTitle}
</span>
<span className={styles["message"]}>
Você completou sua tarefa, onde você irá em sua jornada expert agora?
{mainText}
</span>
<div className={styles["buttons"]}>
<Button
customStyle={{ height: "100%", aspectRatio: "1/1" }}
size="medium"
icon="bx-home"
type="primary"
onClick={() => navigate("/map")}
/>
<Button
customStyle={{ width: "100%" }}
text="Jogar novamente"
Expand Down
9 changes: 9 additions & 0 deletions src/components/common/FinishModal/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
transition: all 0.5s ease-in-out, opacity 0.5s ease-in-out;
}

.highlight {
color: var(--expert-horizon);
font-size: 1.5rem;
}

.all.show {
bottom: 0;
opacity: 1;
Expand Down Expand Up @@ -148,6 +153,10 @@
font-size: 2.6em !important;
}

.highlight {
font-size: 2.6em !important;
}

.message {
padding-inline: 7vw;
font-size: 2.1em !important;
Expand Down
31 changes: 1 addition & 30 deletions src/components/common/GameHeader/index.jsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,14 @@
import React from "react";
import {useNavigate} from "react-router-dom";

import Modal from "@components/Home/Modal";
import Ticket from "../../../assets/Vector.svg";
import Button from "../Button";
import {useAuthStore} from "@stores/useAuth";

import style from "./style.module.css";

export default function GameHeader({task, ContentHelp, isHelpOpen, setIsHelpOpen}) {
const userData = useAuthStore((state) => state.userData);
const navigate = useNavigate();

const options = [
{label: "Voltar para o mapa", value: "map"},
{label: "Ajuda", value: "help"}
];

const handleSelectOption = (opt) => {
switch (opt.value) {
case "map":
navigate("/map");
break;
case "help":
setIsHelpOpen(true);
break;
default:
break;
}
};

return (
<div className={style.header}>
<Button dropdownOptions={options} onSelectOption={handleSelectOption} type="primary" size="small" icon="bx-menu" />
<span className={style.task}>{task}</span>
<div className={style["tickets"]}>
<img className={style["icon"]} src={Ticket} />
<span className={style.ticket}>{userData?.tickets}</span>
</div>
<Button onClick={() => { setIsHelpOpen(true) }} type="primary" size="small" icon="bx-question-mark" />

<Modal onClose={() => setIsHelpOpen(false)} show={isHelpOpen} title="Ajuda">
<div className={style.modalContent}>
Expand Down
26 changes: 2 additions & 24 deletions src/helpers/Routes.jsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,16 @@
import {createBrowserRouter} from "react-router-dom";

import Frame from "@components/common/Frame";
import ProtectedRoute from "./ProtectedRoute";
import PublicRoute from "./PublicRoute";

import {Home, Map, Wordle, Register, ConfirmEmail, Login, Phrase, Quiz, Memory, NotFoundPage, ErrorPage} from "../pages";
import {Wordle, ErrorPage} from "../pages";

const routes = createBrowserRouter([
{
path: "/",
element: <Frame />,
errorElement: <ErrorPage />,
children: [
{path: "/", element: <Home />},
{path: "*", element: <NotFoundPage />},
{
element: <PublicRoute />,
children: [
{path: "/register", element: <Register />},
{path: "/login", element: <Login />},
{path: "/confirm-email", element: <ConfirmEmail />}
]
},

{
element: <ProtectedRoute />,
children: [
{path: "/map", element: <Map />},
{path: "/wordle", element: <Wordle />},
{path: "/memory", element: <Memory />},
{path: "/phrase", element: <Phrase />},
{path: "/quiz", element: <Quiz />}
]
}
{path: "/", element: <Wordle />},
]
}
]);
Expand Down
63 changes: 39 additions & 24 deletions src/pages/Wordle/index.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import {useState, useCallback, useEffect} from "react";
import { useState, useCallback, useEffect } from "react";

import Grid from "@components/Wordle";
import Keyboard from "@components/Wordle/Keyboard";
import GameHeader from "@components/common/GameHeader";

import {LetterStatusEnum} from "../../constants/wordleConstants";
import {GameRepository} from "../../repositories/games";
import { LetterStatusEnum } from "../../constants/wordleConstants";
import FinishModal from "@components/common/FinishModal";
import Help from "@components/Wordle/Help";
import {useAuthStore} from "@stores/useAuth";
import words from "./words";

import styles from "./style.module.css"

Expand All @@ -18,7 +17,7 @@ const CONFIG = {
SECRET_WORD: "LIVRO"
};

const getDefaultGuess = () => new Array(CONFIG.WORD_LENGTH).fill({char: ""});
const getDefaultGuess = () => new Array(CONFIG.WORD_LENGTH).fill({ char: "" });

const filledCharacterCount = (guess) => guess.reduce((count, item) => (item.char === "" ? count - 1 : count), CONFIG.WORD_LENGTH);

Expand All @@ -30,31 +29,41 @@ const removeGuessCharacter = (guess, index) => {
return guess.map((item, i) => (i === index ? { ...item, char: "" } : item));
};

function selectCorrectWord() {
const i = Math.floor(Math.random() * words.length);
return words[i];
}


export default function Wordle() {
const [activeIndex, setActiveIndex] = useState(0);
const [guesses, setGuesses] = useState([]);
const [currentGuess, setCurrentGuess] = useState(getDefaultGuess());
const [isGameOver, setIsGameOver] = useState(false);
const [isHelpOpen, setIsHelpOpen] = useState(false);
const markLastTaskAsPlayed = useAuthStore((state) => state.markLastTaskAsPlayed);

const {getTermData, termGuess} = GameRepository();

useEffect(() => {
if (isGameOver) {
markLastTaskAsPlayed();
const [correctWord, setCorrectWord] = useState("");
const [playerWin, setPlayerWin] = useState(false);

const checkWord = (word) => {
let result = [];
const correctArr = correctWord.split("");

for (let i = 0; i < word.length; i++) {
const char = word[i];
if (char === correctArr[i]) {
result.push({ char, status: LetterStatusEnum.CORRECT });
} else if (correctArr.includes(char)) {
result.push({ char, status: LetterStatusEnum.INCORRECT_POSITION });
} else {
result.push({ char, status: LetterStatusEnum.DONT_EXIST });
}
}
}, [isGameOver]);
return result;
};

useEffect(() => {
const fetchData = async () => {
const {tries} = await getTermData();
setGuesses(tries);
};

fetchData();
}, []);
setCorrectWord(selectCorrectWord())
}, [isGameOver]);

const handleKeyPress = useCallback(
async (key) => {
Expand All @@ -66,7 +75,7 @@ export default function Wordle() {
if (filledCharacterCount(currentGuess) === CONFIG.WORD_LENGTH) {
const fullWord = currentGuess.reduce((word, item) => word + item.char, "");

const guessResult = await termGuess({guess: fullWord});
const guessResult = checkWord(fullWord);

const newGuesses = [...guesses, guessResult];
setGuesses(newGuesses);
Expand All @@ -76,7 +85,13 @@ export default function Wordle() {
const playerWon = guessResult.every((letter) => letter.status === LetterStatusEnum.CORRECT);
const maxAttemptsReached = newGuesses.length >= CONFIG.MAX_ATTEMPTS;

if (playerWon || maxAttemptsReached) {
if (playerWon) {
setPlayerWin(true)
setIsGameOver(true);
}

if (maxAttemptsReached) {
setPlayerWin(false)
setIsGameOver(true);
}
}
Expand All @@ -100,7 +115,7 @@ export default function Wordle() {

return (
<div className={styles["container"]}>
<GameHeader task="Task #3" isHelpOpen={isHelpOpen} setIsHelpOpen={setIsHelpOpen} ContentHelp={Help} />
<GameHeader isHelpOpen={isHelpOpen} setIsHelpOpen={setIsHelpOpen} ContentHelp={Help} />
<Grid
guesses={guesses}
isGameOver={isGameOver}
Expand All @@ -110,7 +125,7 @@ export default function Wordle() {
setActiveIndex={setActiveIndex}
/>
<Keyboard onKeyPress={handleKeyPress} guesses={guesses} getLetterColor={getColor} />
<FinishModal showModal={isGameOver} />
<FinishModal showModal={isGameOver} correctWord={correctWord} playerWin={playerWin} />
</div>
);
}
4 changes: 4 additions & 0 deletions src/pages/Wordle/words.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default [
"TESTE",
"RODAS"
]