From b77b15085a88635743426ccfadce046fba4ad60a Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Tue, 18 Jun 2024 13:26:33 +0300 Subject: [PATCH 01/12] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=A2=D0=97=5F=D0=BD=D0=BE=5F=D1=81=D0=B2?= =?UTF-8?q?=D0=B5=D1=82=D1=8F=D1=82=D1=81=D1=8F=5F=D0=BE=D1=88=D0=B8=D0=B1?= =?UTF-8?q?=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 15 +++++++++ docs/mvp-spec.md | 7 ++-- src/components/Cards/Cards.jsx | 14 +++++++- src/components/Cards/Cards.module.css | 9 +++++ src/context/easyMode.jsx | 14 ++++++++ src/context/hooks/useEasyMode.js | 6 ++++ src/index.js | 5 ++- src/pages/SelectLevelPage/SelectLevelPage.jsx | 6 ++++ .../SelectLevelPage.module.css | 33 +++++++++++++++++++ 9 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 src/context/easyMode.jsx create mode 100644 src/context/hooks/useEasyMode.js diff --git a/README.md b/README.md index 9b90842c4..cea80d64a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,18 @@ +# Домашняя работа 1" + +Добавление нового режима: реализовать режим, при котором игра завершается после трех ошибок. + +Включение режима: режим должен включаться с помощью чек-бокса на странице выбора уровня. + +Счетчик ошибок: нужно добавить вывод количества оставшихся попыток на игровой экран («Осталось 3 попытки» и так далее). + +Отображение: внешний вид и расположение элементов остаются на ваше усмотрение, но выбор должен быть логически обоснован. + +Конец игры: при достижении трех ошибок должно появляться модальное окно о завершении игры, его можно взять из макета. + +Ожидаемое время выполнения работы: 4 часа +Фактическое время выполнения работы: + # MVP Карточная игра "Мемо" В этом репозитории реализован MVP карточкой игры "Мемо" по [тех.заданию](./docs/mvp-spec.md) diff --git a/docs/mvp-spec.md b/docs/mvp-spec.md index fab47685e..e083d7788 100644 --- a/docs/mvp-spec.md +++ b/docs/mvp-spec.md @@ -14,9 +14,10 @@ Количество карточек для каждого уровня сложности можете назначать и свои или выбрать готовый пресет. Предлагаем следующее пресеты: - - Легкий уровень - 6 карточек (3 пары) - - Средний уровень - 12 карточек (6 пар) - - Сложный уровень - 18 карточек (9 пар) + +- Легкий уровень - 6 карточек (3 пары) +- Средний уровень - 12 карточек (6 пар) +- Сложный уровень - 18 карточек (9 пар) Как только уровень сложности выбран, игроку показывается на игровой поле. diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index 7526a56c8..c2f91827c 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -5,6 +5,7 @@ import styles from "./Cards.module.css"; import { EndGameModal } from "../../components/EndGameModal/EndGameModal"; import { Button } from "../../components/Button/Button"; import { Card } from "../../components/Card/Card"; +import { useEasyMode } from "../../context/hooks/useEasyMode"; // Игра закончилась const STATUS_LOST = "STATUS_LOST"; @@ -41,6 +42,8 @@ function getTimerValue(startDate, endDate) { * previewSeconds - сколько секунд пользователь будет видеть все карты открытыми до начала игры */ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { + const { easyMode } = useEasyMode(); + const [countTry, setCountTry] = useState(null); // В cards лежит игровое поле - массив карт и их состояние открыта\закрыта const [cards, setCards] = useState([]); // Текущий статус игры @@ -63,6 +66,7 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { } function startGame() { const startDate = new Date(); + setCountTry(easyMode ? 3 : 1); setGameEndDate(null); setGameStartDate(startDate); setTimer(getTimerValue(startDate, null)); @@ -123,7 +127,14 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { return false; }); - const playerLost = openCardsWithoutPair.length >= 2; + if (openCardsWithoutPair.length >= 2) { + setTimeout(() => { + openCardsWithoutPair[1].open = false; + openCardsWithoutPair[0].open = false; + }, 1000); + setCountTry(countTry - 1); + + const playerLost = countTry === 0; // "Игрок проиграл", т.к на поле есть две открытые карты без пары if (playerLost) { @@ -183,6 +194,7 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { ) : ( <> +
{easyMode && `Осталось попыток ${countTry}`}
min
{timer.minutes.toString().padStart("2", "0")}
diff --git a/src/components/Cards/Cards.module.css b/src/components/Cards/Cards.module.css index 000c5006c..893c5814c 100644 --- a/src/components/Cards/Cards.module.css +++ b/src/components/Cards/Cards.module.css @@ -70,3 +70,12 @@ margin-bottom: -12px; } + +.count { + color: #fff; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 16px; + font-style: normal; + margin-right: 10px; +} diff --git a/src/context/easyMode.jsx b/src/context/easyMode.jsx new file mode 100644 index 000000000..1d1825497 --- /dev/null +++ b/src/context/easyMode.jsx @@ -0,0 +1,14 @@ +import { createContext, useState } from "react"; + +export const EasyModeContext = createContext(null); +export const EasyModeProvider = ({ children }) => { + const [easyMode, setEasyMode] = useState(false); + const easyModeSelect = () => { + setEasyMode(!easyMode); + console.log(easyMode); + }; + + return ( + {children} + ); +}; diff --git a/src/context/hooks/useEasyMode.js b/src/context/hooks/useEasyMode.js new file mode 100644 index 000000000..18d05bd2c --- /dev/null +++ b/src/context/hooks/useEasyMode.js @@ -0,0 +1,6 @@ +import { useContext } from "react"; +import { EasyModeContext } from "../easyMode"; + +export function useEasyMode() { + return useContext(EasyModeContext); +} diff --git a/src/index.js b/src/index.js index f689c5f0b..af2cce4ec 100644 --- a/src/index.js +++ b/src/index.js @@ -3,10 +3,13 @@ import ReactDOM from "react-dom/client"; import "./index.css"; import { RouterProvider } from "react-router-dom"; import { router } from "./router"; +import { EasyModeContext } from "./context/easyMode"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - + + + , ); diff --git a/src/pages/SelectLevelPage/SelectLevelPage.jsx b/src/pages/SelectLevelPage/SelectLevelPage.jsx index 758942e51..d787d0a02 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.jsx +++ b/src/pages/SelectLevelPage/SelectLevelPage.jsx @@ -1,10 +1,16 @@ import { Link } from "react-router-dom"; import styles from "./SelectLevelPage.module.css"; +import { useEasyMode } from "../../context/hooks/useEasyMode"; export function SelectLevelPage() { + const { easyModeSelect } = useEasyMode(); return (
+
+ + +

Выбери сложность

  • diff --git a/src/pages/SelectLevelPage/SelectLevelPage.module.css b/src/pages/SelectLevelPage/SelectLevelPage.module.css index 390ac0def..27ff66ecf 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.module.css +++ b/src/pages/SelectLevelPage/SelectLevelPage.module.css @@ -62,3 +62,36 @@ .levelLink:visited { color: #0080c1; } + +.toggleSwitch { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 30px; + + input[type="checkbox"] { + position: relative; + width: 24px; + height: 13px; + border-radius: 100px; + background: #eaeef6; + outline: none; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } + input[type="checkbox"]::before { + content: ""; + position: absolute; + top: 1px; + left: 1px; + width: 11px; + height: 11px; + border-radius: 50%; + background-color: #94a6be; + transition: 0.5s; + } + input:checked[type="checkbox"]::before { + left: 12px; + } +} From 2d308c83b45f6c81089f5c0eeb8aa84acc5e940c Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Tue, 18 Jun 2024 18:15:10 +0300 Subject: [PATCH 02/12] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.json | 4 ++-- README.md | 2 +- src/components/Cards/Cards.jsx | 18 +++++++++--------- src/index.js | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index e37e1e072..ef1409393 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,8 +3,8 @@ "plugins": ["prettier"], "rules": { "camelcase": ["error", { "properties": "never" }], - "prettier/prettier": "error", + "prettier/prettier": ["error", { "endOfLine": "auto" }], "eqeqeq": ["error", "always"], "no-unused-vars": ["error"] } -} +} \ No newline at end of file diff --git a/README.md b/README.md index cea80d64a..c5a7e19a7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Конец игры: при достижении трех ошибок должно появляться модальное окно о завершении игры, его можно взять из макета. Ожидаемое время выполнения работы: 4 часа -Фактическое время выполнения работы: +Фактическое время выполнения работы: 6 часов # MVP Карточная игра "Мемо" diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index c2f91827c..a54255060 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -35,7 +35,6 @@ function getTimerValue(startDate, endDate) { seconds, }; } - /** * Основной компонент игры, внутри него находится вся игровая механика и логика. * pairsCount - сколько пар будет в игре @@ -132,17 +131,18 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { openCardsWithoutPair[1].open = false; openCardsWithoutPair[0].open = false; }, 1000); - setCountTry(countTry - 1); + setCountTry(countTry - 1); - const playerLost = countTry === 0; + const playerLost = countTry === 0; - // "Игрок проиграл", т.к на поле есть две открытые карты без пары - if (playerLost) { - finishGame(STATUS_LOST); - return; - } + // "Игрок проиграл", т.к на поле есть две открытые карты без пары + if (playerLost) { + finishGame(STATUS_LOST); + return; + } - // ... игра продолжается + // ... игра продолжается + } }; const isGameEnded = status === STATUS_LOST || status === STATUS_WON; diff --git a/src/index.js b/src/index.js index af2cce4ec..8b227c6da 100644 --- a/src/index.js +++ b/src/index.js @@ -3,13 +3,13 @@ import ReactDOM from "react-dom/client"; import "./index.css"; import { RouterProvider } from "react-router-dom"; import { router } from "./router"; -import { EasyModeContext } from "./context/easyMode"; +import { EasyModeProvider } from "./context/easyMode"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - + - + , ); From 4138172c6ac68dcb2b30faa6e80b33a3afb0d384 Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Thu, 20 Jun 2024 11:35:28 +0300 Subject: [PATCH 03/12] =?UTF-8?q?api=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/api.js diff --git a/src/api.js b/src/api.js new file mode 100644 index 000000000..9b3c3f27b --- /dev/null +++ b/src/api.js @@ -0,0 +1,25 @@ +const baseHost = "https://wedev-api.sky.pro/api/leaderboard"; +//Получаем список лидеров +export async function getLeaders() { + const response = await fetch(baseHost); + if (!response.status === 200) { + throw new Error("Ошибка"); + } + const data = await response.json(); + return data; +} +//Добавляем лидера в список +export async function postLeader({ name, time }) { + const response = await fetch(baseHost, { + method: "POST", + body: JSON.stringify({ + name: name, + time: time, + }), + }); + if (response.status === 400) { + throw new Error("Полученные данные не в формате JSON"); + } + const data = await response.json(); + return data; +} From 0ae6134d3371428feb8db433666441126cf21ddd Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Thu, 20 Jun 2024 12:34:01 +0300 Subject: [PATCH 04/12] =?UTF-8?q?=D0=94/=D0=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/EndGameModal/EndGameModal.jsx | 58 ++++++++++++++++++- .../EndGameModal/EndGameModal.module.css | 2 +- src/context/Leaders.jsx | 8 +++ src/context/hooks/useLeaders.js | 6 ++ src/index.js | 9 ++- src/pages/LeaderboardPage/LeaderboardPage.jsx | 33 +++++++++++ .../LeaderboardPage.module.css | 36 ++++++++++++ src/pages/SelectLevelPage/SelectLevelPage.jsx | 16 ++++- .../SelectLevelPage.module.css | 1 + src/router.js | 5 ++ 10 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 src/context/Leaders.jsx create mode 100644 src/context/hooks/useLeaders.js create mode 100644 src/pages/LeaderboardPage/LeaderboardPage.jsx create mode 100644 src/pages/LeaderboardPage/LeaderboardPage.module.css diff --git a/src/components/EndGameModal/EndGameModal.jsx b/src/components/EndGameModal/EndGameModal.jsx index 722394833..44f91852d 100644 --- a/src/components/EndGameModal/EndGameModal.jsx +++ b/src/components/EndGameModal/EndGameModal.jsx @@ -4,9 +4,44 @@ import { Button } from "../Button/Button"; import deadImageUrl from "./images/dead.png"; import celebrationImageUrl from "./images/celebration.png"; +import { useState } from "react"; +import { postLeader } from "../../api"; +import { useLeaders } from "../../context/hooks/useLeaders"; +import { Link } from "react-router-dom"; export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, onClick }) { - const title = isWon ? "Вы победили!" : "Вы проиграли!"; + const [newLeader, setNewLeader] = useState({ + name: "", + time: gameDurationSeconds, + }); + const { setLeaders, leaders } = useLeaders(); + const [btnDisabled, setBtnDisabled] = useState(false); + setLeaders(leaders.sort((a, b) => +a.time - +b.time)); + + const handleInputChange = e => { + const { name, value } = e.target; + setNewLeader({ + ...newLeader, + [name]: value, + }); + }; + const handleFormSubmit = e => { + e.preventDefault(); + postLeader({ name: newLeader.name, time: newLeader.time }) + .then(leaders => { + setLeaders(leaders.leaders); + setBtnDisabled(!btnDisabled); + }) + .catch(error => { + console.log(error); + alert(error); + }); + }; + let title = isWon ? "Вы победили!" : "Вы проиграли!"; + if (gameDurationMinutes * 60 + gameDurationSeconds < leaders[2].time && isWon) { + title = "Вы попали на лидерборд!"; + } + let isLeader = gameDurationMinutes * 60 + gameDurationSeconds < leaders[2].time && isWon; const imgSrc = isWon ? celebrationImageUrl : deadImageUrl; @@ -16,12 +51,33 @@ export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes,
    {imgAlt}

    {title}

    + {isLeader && ( +
    + + +
    + )}

    Затраченное время:

    {gameDurationMinutes.toString().padStart("2", "0")}.{gameDurationSeconds.toString().padStart("2", "0")}
    +
    + +

    Перейти к лидерборду

    + +
    ); } diff --git a/src/components/EndGameModal/EndGameModal.module.css b/src/components/EndGameModal/EndGameModal.module.css index 9368cb8b5..b2169838c 100644 --- a/src/components/EndGameModal/EndGameModal.module.css +++ b/src/components/EndGameModal/EndGameModal.module.css @@ -19,7 +19,7 @@ color: #004980; font-variant-numeric: lining-nums proportional-nums; font-family: StratosSkyeng; - font-size: 40px; + font-size: 35px; font-style: normal; font-weight: 400; line-height: 48px; diff --git a/src/context/Leaders.jsx b/src/context/Leaders.jsx new file mode 100644 index 000000000..8995a0409 --- /dev/null +++ b/src/context/Leaders.jsx @@ -0,0 +1,8 @@ +import { createContext, useState } from "react"; + +export const LeadersContext = createContext(null); +export const LeadersProvider = ({ children }) => { + const [leaders, setLeaders] = useState(); + + return {children}; +}; diff --git a/src/context/hooks/useLeaders.js b/src/context/hooks/useLeaders.js new file mode 100644 index 000000000..45efa7c68 --- /dev/null +++ b/src/context/hooks/useLeaders.js @@ -0,0 +1,6 @@ +import { useContext } from "react"; +import { LeadersContext } from "../Leaders"; + +export function useLeaders() { + return useContext(LeadersContext); +} diff --git a/src/index.js b/src/index.js index 8b227c6da..c14da6fc5 100644 --- a/src/index.js +++ b/src/index.js @@ -4,12 +4,15 @@ import "./index.css"; import { RouterProvider } from "react-router-dom"; import { router } from "./router"; import { EasyModeProvider } from "./context/easyMode"; +import { LeadersProvider } from "./context/Leaders"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - - - + + + + + , ); diff --git a/src/pages/LeaderboardPage/LeaderboardPage.jsx b/src/pages/LeaderboardPage/LeaderboardPage.jsx new file mode 100644 index 000000000..ccea93082 --- /dev/null +++ b/src/pages/LeaderboardPage/LeaderboardPage.jsx @@ -0,0 +1,33 @@ +import { Link } from "react-router-dom"; +import { Button } from "../../components/Button/Button"; +import styles from "./LeaderboardPage.module.css"; +import { useLeaders } from "../../context/hooks/useLeaders"; + +export function LeaderboardPage() { + const { leaders, setLeaders } = useLeaders(); + setLeaders(leaders.sort((a, b) => +a.time - +b.time)); + return ( +
    +
    +

    Лидерборд

    + + + +
    +
    +
    +

    Позиция

    +

    Пользователь

    +

    Время

    +
    + {leaders.map(leader => ( +
    +

    {leaders.indexOf(leader) + 1}

    +

    {leader.name}

    +

    {leader.time}

    +
    + ))} +
    +
    + ); +} diff --git a/src/pages/LeaderboardPage/LeaderboardPage.module.css b/src/pages/LeaderboardPage/LeaderboardPage.module.css new file mode 100644 index 000000000..8e75c4245 --- /dev/null +++ b/src/pages/LeaderboardPage/LeaderboardPage.module.css @@ -0,0 +1,36 @@ +.title { + font-family: Roboto; + font-size: 24px; + font-weight: 400; + line-height: 32px; + text-align: left; + width: 127px; + height: 32px; + top: 61px; + left: 40px; + gap: 0px; + opacity: 0px; + color: white; + +} + +.header { + display: flex; + justify-content: space-between; + padding: 20px; +} + +.block { + display: flex; + justify-content: space-between; + background-color: white; + border-radius: 12px; + margin: 5px; + height: 30px; + align-items: center; +} + +.name { + padding-left: 50px; + padding-right: 50px; +} \ No newline at end of file diff --git a/src/pages/SelectLevelPage/SelectLevelPage.jsx b/src/pages/SelectLevelPage/SelectLevelPage.jsx index d787d0a02..e5022b6cc 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.jsx +++ b/src/pages/SelectLevelPage/SelectLevelPage.jsx @@ -1,15 +1,24 @@ import { Link } from "react-router-dom"; import styles from "./SelectLevelPage.module.css"; import { useEasyMode } from "../../context/hooks/useEasyMode"; +import { getLeaders } from "../../api"; +import { useLeaders } from "../../context/hooks/useLeaders"; +import { useEffect } from "react"; export function SelectLevelPage() { + const { setLeaders } = useLeaders(); const { easyModeSelect } = useEasyMode(); + useEffect(() => { + getLeaders().then(response => { + setLeaders(response.leaders); + }); + }, [setLeaders]); return (
    - +

    Выбери сложность

      @@ -29,6 +38,11 @@ export function SelectLevelPage() {
    +
    + +

    Перейти к лидерборду

    + +
    ); diff --git a/src/pages/SelectLevelPage/SelectLevelPage.module.css b/src/pages/SelectLevelPage/SelectLevelPage.module.css index 27ff66ecf..b10315eb7 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.module.css +++ b/src/pages/SelectLevelPage/SelectLevelPage.module.css @@ -46,6 +46,7 @@ border-radius: 12px; background: #fff; + cursor: pointer; } .levelLink { diff --git a/src/router.js b/src/router.js index da6e94b51..ecd8d90ae 100644 --- a/src/router.js +++ b/src/router.js @@ -1,6 +1,7 @@ import { createBrowserRouter } from "react-router-dom"; import { GamePage } from "./pages/GamePage/GamePage"; import { SelectLevelPage } from "./pages/SelectLevelPage/SelectLevelPage"; +import { LeaderboardPage } from "./pages/LeaderboardPage/LeaderboardPage"; export const router = createBrowserRouter( [ @@ -12,6 +13,10 @@ export const router = createBrowserRouter( path: "/game/:pairsCount", element: , }, + { + path: "/leaderboard", + element: , + }, ], /** * basename нужен для корректной работы в gh pages From 2a9b013230db1ff17fafaa0398b7b3e3915c700d Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Thu, 20 Jun 2024 12:58:02 +0300 Subject: [PATCH 05/12] README --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index c5a7e19a7..94947698c 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,23 @@ Ожидаемое время выполнения работы: 4 часа Фактическое время выполнения работы: 6 часов + + + +# Домашняя работа 2" +Создание страницы "Лидерборд": Требуется разработать новую страницу в игре, которая будет носить название "Лидерборд". Формат отображения нужно взять из макета. + +Отображение “Лидерборда”: На странице должны отображаться результаты пользователей в порядке возрастания по времени, затраченному на успешное прохождение игры. + +Результат игры: Если результат игры проходит в "Лидерборд по ТОП-3, то в модальном окне нужно запросить имя пользователя и указать затраченное на игру время. Формат отображения нужно взять из макета. + +Если пользователь не проходит в “Лидерборд”, однако он выиграл, то показываем ему модальное окно победы (уже реализовано в приложении). +Отображение модального окна проигрыша остается без изменений. +Страница выбора сложности: На страницу выбора сложности нужно добавить ссылку, которая ведет на страницу лидерборда. Отображение нужно взять из макета. + +Ожидаемое время выполнения работы: 6 часа +Фактическое время выполнения работы: часов + # MVP Карточная игра "Мемо" В этом репозитории реализован MVP карточкой игры "Мемо" по [тех.заданию](./docs/mvp-spec.md) From 51e125d60925ab8997744f77f86b813a3d8cf874 Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Thu, 20 Jun 2024 21:34:48 +0300 Subject: [PATCH 06/12] =?UTF-8?q?=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BD=D0=B0=D1=81=D1=82=D0=B0=D0=B2=D0=BD=D0=B8?= =?UTF-8?q?=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Cards/Cards.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index a54255060..c026899d1 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -133,7 +133,7 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { }, 1000); setCountTry(countTry - 1); - const playerLost = countTry === 0; + const playerLost = countTry === 1; // "Игрок проиграл", т.к на поле есть две открытые карты без пары if (playerLost) { From e259de4dc10447443c793ff1ccc1a1a3f5a626b7 Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Tue, 25 Jun 2024 11:01:32 +0300 Subject: [PATCH 07/12] =?UTF-8?q?=D0=A2=D0=97=20=D0=9A=D1=83=D1=80=D1=81?= =?UTF-8?q?=D0=BE=D0=B2=D0=BE=D0=B9=20(README)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 94947698c..ed2cc1b75 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,18 @@ Страница выбора сложности: На страницу выбора сложности нужно добавить ссылку, которая ведет на страницу лидерборда. Отображение нужно взять из макета. Ожидаемое время выполнения работы: 6 часа +Фактическое время выполнения работы: 8 часов + + + +# Курсовая работа" +Часть 1. Создание суперсил +Нужно создать и внедрить систему суперсил, которые будут действовать как упрощения или подсказки для игрока. Например, если игрок открывает неправильную карту, суперсила будет автоматически открывать соседнюю правильную пару. Подробная информация — в техническом задании. Для зачтения работы достаточно реализовать минимум одну из суперсил. + +Часть 2. Доработка лидерборда +Добавьте к каждой позиции в лидерборде ачивки. Например, если пользователь прошел игру без использования суперсил или в сложном режиме. Подробная информация — в техническом задании. + +Ожидаемое время выполнения работы: 8 часа Фактическое время выполнения работы: часов # MVP Карточная игра "Мемо" From 981bc4d9f42ba48094b031c655d55c4282951089 Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Tue, 25 Jun 2024 12:22:25 +0300 Subject: [PATCH 08/12] =?UTF-8?q?=D0=B4=D0=BE=D1=81=D1=82=D0=B8=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api.js | 5 ++- src/components/Cards/Cards.jsx | 26 ++++++++++-- src/components/Cards/Cards.module.css | 3 +- src/components/Cards/super.png | Bin 0 -> 2872 bytes src/components/EndGameModal/EndGameModal.jsx | 7 ++-- src/pages/LeaderboardPage/LeaderboardPage.jsx | 39 +++++++++++++++--- .../LeaderboardPage.module.css | 6 +++ src/pages/LeaderboardPage/super1.svg | 17 ++++++++ src/pages/LeaderboardPage/super2.svg | 30 ++++++++++++++ src/pages/LeaderboardPage/unsuper1.svg | 15 +++++++ src/pages/LeaderboardPage/unsuper2.svg | 14 +++++++ 11 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 src/components/Cards/super.png create mode 100644 src/pages/LeaderboardPage/super1.svg create mode 100644 src/pages/LeaderboardPage/super2.svg create mode 100644 src/pages/LeaderboardPage/unsuper1.svg create mode 100644 src/pages/LeaderboardPage/unsuper2.svg diff --git a/src/api.js b/src/api.js index 9b3c3f27b..cf670dc7c 100644 --- a/src/api.js +++ b/src/api.js @@ -1,4 +1,4 @@ -const baseHost = "https://wedev-api.sky.pro/api/leaderboard"; +const baseHost = "https://wedev-api.sky.pro/api/v2/leaderboard"; //Получаем список лидеров export async function getLeaders() { const response = await fetch(baseHost); @@ -9,12 +9,13 @@ export async function getLeaders() { return data; } //Добавляем лидера в список -export async function postLeader({ name, time }) { +export async function postLeader({ name, time, achievements }) { const response = await fetch(baseHost, { method: "POST", body: JSON.stringify({ name: name, time: time, + achievements: achievements, }), }); if (response.status === 400) { diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index c026899d1..d32b3ffed 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -6,6 +6,7 @@ import { EndGameModal } from "../../components/EndGameModal/EndGameModal"; import { Button } from "../../components/Button/Button"; import { Card } from "../../components/Card/Card"; import { useEasyMode } from "../../context/hooks/useEasyMode"; +import superImg from "./super.png"; // Игра закончилась const STATUS_LOST = "STATUS_LOST"; @@ -41,6 +42,7 @@ function getTimerValue(startDate, endDate) { * previewSeconds - сколько секунд пользователь будет видеть все карты открытыми до начала игры */ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { + const [achievements, setAchievements] = useState([]); const { easyMode } = useEasyMode(); const [countTry, setCountTry] = useState(null); // В cards лежит игровое поле - массив карт и их состояние открыта\закрыта @@ -85,17 +87,33 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { * - "Игрок проиграл", если на поле есть две открытые карты без пары * - "Игра продолжается", если не случилось первых двух условий */ + + function alohomora() { + if (achievements.includes(1)) { + alert("Подсказкой можно воспользоваться только 1 раз"); + return; + } + let closedCards = cards.filter(card => !card.open); + closedCards = shuffle(closedCards); + closedCards[0].open = true; + closedCards.forEach(card => { + if (card.suit === closedCards[0].suit && card.rank === closedCards[0].rank) { + card.open = true; + } + }); + setAchievements([1]); + } + const openCard = clickedCard => { // Если карта уже открыта, то ничего не делаем if (clickedCard.open) { return; } // Игровое поле после открытия кликнутой карты - const nextCards = cards.map(card => { + let nextCards = cards.map(card => { if (card.id !== clickedCard.id) { return card; } - return { ...card, open: true, @@ -194,7 +212,6 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) {
) : ( <> -
{easyMode && `Осталось попыток ${countTry}`}
min
{timer.minutes.toString().padStart("2", "0")}
@@ -207,6 +224,8 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { )}
+
{easyMode && `Осталось попыток ${countTry}`}
+ {status === STATUS_IN_PROGRESS ? super : null} {status === STATUS_IN_PROGRESS ? : null}
@@ -228,6 +247,7 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { isWon={status === STATUS_WON} gameDurationSeconds={timer.seconds} gameDurationMinutes={timer.minutes} + achievements={achievements} onClick={resetGame} />
diff --git a/src/components/Cards/Cards.module.css b/src/components/Cards/Cards.module.css index 893c5814c..7fffcf0ce 100644 --- a/src/components/Cards/Cards.module.css +++ b/src/components/Cards/Cards.module.css @@ -1,5 +1,5 @@ .container { - width: 672px; + width: 700px; margin: 0 auto; padding: 26px; padding-top: 22px; @@ -11,6 +11,7 @@ flex-direction: row; gap: 10px; flex-wrap: wrap; + justify-content: space-between; } .modalContainer { diff --git a/src/components/Cards/super.png b/src/components/Cards/super.png new file mode 100644 index 0000000000000000000000000000000000000000..597a8a446f81a65960ab80b30e5afac2bf678d41 GIT binary patch literal 2872 zcmV-83&-?{P)2A z9Mu{AcXns*YbQ3oq)Lb*k`gsQ9Hf#85jA}P8qpV!LLU%H^HhNZeSyC80eERuNGla2 zpekzMu}}&1Aqp3%O+}De@?cjYC@6+FMI^r9*xvi>%*{w>7Ki8r9-#vp(8)MmGZfCpyTWW9Xc@4*#<#V7ia1GN0;b>k3Qw3 zMS)n@5;A#UHzQy_9s9{-U=n)4*?&#bTW9_gy5xjL2#7fO@X>X5bu$2|IsN9pX_~!< zfxZcWEqLPO{hLliH$Gsh^wQ~fX>M_a`a#cxz(ySZ*z~um_B?G>z?kDY8@fTCT>et(SSdoF z9eueD^l8MklHf%|BZNf zgbQOIl$1b(L_tQP)uf%Z6}o9?m<9(2DW}FMXBt#!R4HFwrIexbeN1NNno6Adfeb0W zw;~EMfSg_3d^iw5yPzaji&$^@`*EC_x~~cESciqE;0k0~f1Wch63W6G5_o zdO`Arhne@%O0N6iri+@49UBOF;^a>$N+@QFQcS#Y;TSe2g2G3u)uLuh@!SVN=7#ID zf0$(c`UorPL!UFcI-H4PAuWOgFQVhtW| zm`zHj)09jnDZQ=0y@VYgrd%#_F$Yl=;Au=>kK+WKhf7HICf|L9l!yXT=gN*haG3f* znyCVeC0uH@X&FrzH?^>hdjT(i1h`QQLIh*v7?A`658_x{5)`QUt|LUG%Q8qX!Xc%49RpA23w&_0cNP)^F~_?F#3mb~*dPEQRW%cMe~cX=Jqp*H5HJ)3Sr$L! z*x=JTyYQIF2cFKS*~ zgN9iIIAS)qNIThqegPHZu9A5i^}+=h7NWcF=HFSw1UnDUdyFPE;ws4i(QAhgKVzC~ z>NI53Xk>hxq6Ek`UVDww@4wGKo44FT=JU^!varA=W|;IGJm`B4%YLLt7MMEu9sPq6 z@Ge2-Pu8q|bb#7uH{aa(9Q*7uiaq`~(R_REg@xtx!V4^%cE2&)ekA4RgTMjO6=mPV znD5RIKdl`&MF|+x`ki;K|L6St`t7&h_B=kLwP%r}*1Q0`wMF&X2q6FNp&J3&Bu8s+q z4?ak(mtSVZ6!-W75?t>?LV$!!A*jldCENw%9#H{yMBTof8jO_GrAuVqemk`ud4#)M zQGj*|*0^_J#=q4^fCw(6qAM+)WQ0_EBLr~-yadGF=XgZG)e|Quwr3CDmzNm3YOmcu z0lEkSUb+C*y@}3?%sP{B?ae32rkM2V(?r> z9LT_awT8~p{r>C+pkSt41`ReR0zzCdH%D~p)EWU$lX-_O9~Omrfk&Ao9El{zWt@RI?;_!=X`HH>Eo znJ=J5KKmga5yZQZBHnpGruMHcsD~)BO(n1+S|aJLHn{VTKI(lEzwgPKPQZYLlypy1 zh;5$knM6_PeE6YdH^%(S4FX8?R#sLzgI|kOI}V3mLoFSG{Xpk5BZPYyv^2^B z$)2a$*a6jnqy#azHXsH8;krxygmk~khG6vBPy@F^D=89;A0s~jNghzQQYcDKO!ww7>0K*rf~(^4l8Q#4w%pf_o;SfZt+C0eXEXfZcL{Q_g2u|@0aav9kkap*5pChBUuXs(&h z4bvBc<8*akl&%*>Lh&x$V_rvytdxjyK-As_gs81%=d+=NGi!)&quax7$aY_P{aum) zy8oh78+aJ>js)rTkOh{LbYlY{$Zcd)2k}Ulo<`&+tE;Q5k}yx#*)--C%@{3Z!)*e@ zG7_i6)=~DbbPMa{_63-;;oZgMrJmXrfR6iQB=Fu-wyiNWtg^aGEjtuS7TXOhbacDv zj)WjC`OWYD#(PzR+ax9{`i+O>k_vh=y{pypPoCh;Xwvl1(;ev z*sv+fQ~}fu{?3_?ed8;-y8-q1!=KO4jny*sg1(o!Lt3z^;7EYh&M1MT6uHUFto*c! z9U(ppVS;<1@BG6Mx&dO29X%-BDlP*UOe`csEjTP91Y%J=Va9r(%6_g&c$7w=&u58% zg!7DmsgJL)g7CNKfhul5`{&-> { e.preventDefault(); - postLeader({ name: newLeader.name, time: newLeader.time }) + postLeader({ name: newLeader.name, time: newLeader.time, achievements: newLeader.achievements }) .then(leaders => { setLeaders(leaders.leaders); setBtnDisabled(!btnDisabled); diff --git a/src/pages/LeaderboardPage/LeaderboardPage.jsx b/src/pages/LeaderboardPage/LeaderboardPage.jsx index ccea93082..2145fd337 100644 --- a/src/pages/LeaderboardPage/LeaderboardPage.jsx +++ b/src/pages/LeaderboardPage/LeaderboardPage.jsx @@ -2,10 +2,16 @@ import { Link } from "react-router-dom"; import { Button } from "../../components/Button/Button"; import styles from "./LeaderboardPage.module.css"; import { useLeaders } from "../../context/hooks/useLeaders"; +import unsuper1 from "./unsuper1.svg"; +import super1 from "./super1.svg"; +import unsuper2 from "./unsuper2.svg"; +import super2 from "./super2.svg"; export function LeaderboardPage() { const { leaders, setLeaders } = useLeaders(); setLeaders(leaders.sort((a, b) => +a.time - +b.time)); + let leadersAchievments = leaders.map(leader => leader.achievements); + console.log(leadersAchievments); return (
@@ -16,15 +22,36 @@ export function LeaderboardPage() {
-

Позиция

-

Пользователь

-

Время

+
+

Позиция

+
+
+

Пользователь

+
+
+
Достижения
+
+
+

Время

+
{leaders.map(leader => (
-

{leaders.indexOf(leader) + 1}

-

{leader.name}

-

{leader.time}

+
+

{leaders.indexOf(leader) + 1}

+
+
+

{leader.name}

+
+
+
+ {leader.achievements.includes(1) ? : } + {leader.achievements.includes(2) ? : } +
+
+
+

{leader.time}

+
))}
diff --git a/src/pages/LeaderboardPage/LeaderboardPage.module.css b/src/pages/LeaderboardPage/LeaderboardPage.module.css index 8e75c4245..1298923b6 100644 --- a/src/pages/LeaderboardPage/LeaderboardPage.module.css +++ b/src/pages/LeaderboardPage/LeaderboardPage.module.css @@ -33,4 +33,10 @@ .name { padding-left: 50px; padding-right: 50px; +} + +.grid { + width: 300px; + display: flex; + justify-content: space-evenly; } \ No newline at end of file diff --git a/src/pages/LeaderboardPage/super1.svg b/src/pages/LeaderboardPage/super1.svg new file mode 100644 index 000000000..3ee152c69 --- /dev/null +++ b/src/pages/LeaderboardPage/super1.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/pages/LeaderboardPage/super2.svg b/src/pages/LeaderboardPage/super2.svg new file mode 100644 index 000000000..7949f73ed --- /dev/null +++ b/src/pages/LeaderboardPage/super2.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pages/LeaderboardPage/unsuper1.svg b/src/pages/LeaderboardPage/unsuper1.svg new file mode 100644 index 000000000..934c9486e --- /dev/null +++ b/src/pages/LeaderboardPage/unsuper1.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/pages/LeaderboardPage/unsuper2.svg b/src/pages/LeaderboardPage/unsuper2.svg new file mode 100644 index 000000000..f0976a430 --- /dev/null +++ b/src/pages/LeaderboardPage/unsuper2.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From 6f9d3870e734085a2be5d1b94612829dc0e4713e Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Tue, 25 Jun 2024 15:57:43 +0300 Subject: [PATCH 09/12] =?UTF-8?q?=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Achievment/Achievment.jsx | 9 ++++ src/components/Achievment/super1.svg | 17 +++++++ src/components/Achievment/unsuper1.svg | 15 ++++++ src/components/Cards/Cards.jsx | 10 ++-- src/components/EndGameModal/EndGameModal.jsx | 5 +- .../EndGameModal/EndGameModal.module.css | 41 ++++++++++++++++ src/components/ToolTip/ToolTip.module.css | 11 +++++ src/components/ToolTip/ToolTipGame.jsx | 47 +++++++++++++++++++ src/components/ToolTip/ToolTipSuper.jsx | 38 +++++++++++++++ src/components/ToolTip/super1.svg | 17 +++++++ src/components/ToolTip/super2.svg | 30 ++++++++++++ src/components/ToolTip/unsuper1.svg | 15 ++++++ src/components/ToolTip/unsuper2.svg | 14 ++++++ src/pages/LeaderboardPage/LeaderboardPage.jsx | 15 +++--- 14 files changed, 270 insertions(+), 14 deletions(-) create mode 100644 src/components/Achievment/Achievment.jsx create mode 100644 src/components/Achievment/super1.svg create mode 100644 src/components/Achievment/unsuper1.svg create mode 100644 src/components/ToolTip/ToolTip.module.css create mode 100644 src/components/ToolTip/ToolTipGame.jsx create mode 100644 src/components/ToolTip/ToolTipSuper.jsx create mode 100644 src/components/ToolTip/super1.svg create mode 100644 src/components/ToolTip/super2.svg create mode 100644 src/components/ToolTip/unsuper1.svg create mode 100644 src/components/ToolTip/unsuper2.svg diff --git a/src/components/Achievment/Achievment.jsx b/src/components/Achievment/Achievment.jsx new file mode 100644 index 000000000..5ea33c16a --- /dev/null +++ b/src/components/Achievment/Achievment.jsx @@ -0,0 +1,9 @@ +import unsuper1 from "./unsuper1.svg"; +import super1 from "./super1.svg"; + +export default function Achievment(isAchievment) { + console.log(Object.values(isAchievment)[2].isAchievment); + return ( + <>{Object.values(isAchievment)[2].isAchievment ? : } + ); +} diff --git a/src/components/Achievment/super1.svg b/src/components/Achievment/super1.svg new file mode 100644 index 000000000..3ee152c69 --- /dev/null +++ b/src/components/Achievment/super1.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/components/Achievment/unsuper1.svg b/src/components/Achievment/unsuper1.svg new file mode 100644 index 000000000..934c9486e --- /dev/null +++ b/src/components/Achievment/unsuper1.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index d32b3ffed..f1f8ad765 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -224,9 +224,13 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { )}
-
{easyMode && `Осталось попыток ${countTry}`}
- {status === STATUS_IN_PROGRESS ? super : null} - {status === STATUS_IN_PROGRESS ? : null} + {status === STATUS_IN_PROGRESS ? ( + <> +
{easyMode && `Осталось попыток ${countTry}`}
+ super + + + ) : null}
diff --git a/src/components/EndGameModal/EndGameModal.jsx b/src/components/EndGameModal/EndGameModal.jsx index 34f07eb65..d03aa7b1d 100644 --- a/src/components/EndGameModal/EndGameModal.jsx +++ b/src/components/EndGameModal/EndGameModal.jsx @@ -51,8 +51,9 @@ export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, {imgAlt}

{title}

{isLeader && ( -
+
-
diff --git a/src/components/EndGameModal/EndGameModal.module.css b/src/components/EndGameModal/EndGameModal.module.css index b2169838c..b3da4a9ca 100644 --- a/src/components/EndGameModal/EndGameModal.module.css +++ b/src/components/EndGameModal/EndGameModal.module.css @@ -49,3 +49,44 @@ margin-bottom: 40px; } + +.inputDiv { + display: flex; + gap: 5px; + } + + .btnsave { + + width: 150px; + height: 30px; + + border-radius: 12px; + background: #7ac100; + + color: #fff; + text-align: center; + font-variant-numeric: lining-nums proportional-nums; + + /* Pres → Caption S */ + font-family: StratosSkyeng; + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: 32px; /* 133.333% */ + + border: none; + + cursor: pointer; + + + } + + .btnsave:hover { + background: #7ac100cc; + } + + .inputSave{ + border-radius: 8px; + border: #000; + padding-left: 10px; + } \ No newline at end of file diff --git a/src/components/ToolTip/ToolTip.module.css b/src/components/ToolTip/ToolTip.module.css new file mode 100644 index 000000000..0394b7b49 --- /dev/null +++ b/src/components/ToolTip/ToolTip.module.css @@ -0,0 +1,11 @@ +.toolTip{ + display: flex; + position: absolute; + height: 78px; + width: 174px; + color: black; + border-radius: 12px; + background-color: #C2F5FF; + text-align: center; + align-items: center; +} \ No newline at end of file diff --git a/src/components/ToolTip/ToolTipGame.jsx b/src/components/ToolTip/ToolTipGame.jsx new file mode 100644 index 000000000..32570decf --- /dev/null +++ b/src/components/ToolTip/ToolTipGame.jsx @@ -0,0 +1,47 @@ +import { useRef, useState } from "react"; +import styles from "./ToolTip.module.css"; +import unsuper1 from "./unsuper1.svg"; +import super1 from "./super1.svg"; + +export default function ToolTipGame(isAchievment, i) { + const [showToolTip, setShowToolTip] = useState(false); + const refSetTimeout = useRef(); + + const onMouseEnterHandler = () => { + refSetTimeout.current = setTimeout(() => { + setShowToolTip(true); + }, 750); + // console.log(isAchievment); + }; + + const onMouseLeaveHandler = () => { + clearTimeout(refSetTimeout.current); + setShowToolTip(false); + }; + + return ( + <> + {Object.values(isAchievment)[0] ? ( + <> + + {showToolTip && ( +
+ {" "} +

Игра пройдена в сложном режиме

{" "} +
+ )} + + ) : ( + <> + + {showToolTip && ( +
+ {" "} +

Игра пройдена в сложном режиме

{" "} +
+ )} + + )} + + ); +} diff --git a/src/components/ToolTip/ToolTipSuper.jsx b/src/components/ToolTip/ToolTipSuper.jsx new file mode 100644 index 000000000..e9f827b0f --- /dev/null +++ b/src/components/ToolTip/ToolTipSuper.jsx @@ -0,0 +1,38 @@ +import { useRef, useState } from "react"; +import styles from "./ToolTip.module.css"; + +import unsuper2 from "./unsuper2.svg"; +import super2 from "./super2.svg"; + +export default function ToolTipSuper(isAchievment) { + const [showToolTip, setShowToolTip] = useState(false); + const refSetTimeout = useRef(); + + const onMouseEnterHandler = () => { + refSetTimeout.current = setTimeout(() => { + setShowToolTip(true); + }, 750); + console.log(isAchievment); + }; + + const onMouseLeaveHandler = () => { + clearTimeout(refSetTimeout.current); + setShowToolTip(false); + }; + + return ( + <> + {Object.values(isAchievment)[0] ? ( + <> + + {showToolTip &&
Игра пройдена без супер сил
} + + ) : ( + <> + + {showToolTip &&
Игра пройдена без супер сил
} + + )} + + ); +} diff --git a/src/components/ToolTip/super1.svg b/src/components/ToolTip/super1.svg new file mode 100644 index 000000000..3ee152c69 --- /dev/null +++ b/src/components/ToolTip/super1.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/components/ToolTip/super2.svg b/src/components/ToolTip/super2.svg new file mode 100644 index 000000000..7949f73ed --- /dev/null +++ b/src/components/ToolTip/super2.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/ToolTip/unsuper1.svg b/src/components/ToolTip/unsuper1.svg new file mode 100644 index 000000000..934c9486e --- /dev/null +++ b/src/components/ToolTip/unsuper1.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/components/ToolTip/unsuper2.svg b/src/components/ToolTip/unsuper2.svg new file mode 100644 index 000000000..f0976a430 --- /dev/null +++ b/src/components/ToolTip/unsuper2.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/pages/LeaderboardPage/LeaderboardPage.jsx b/src/pages/LeaderboardPage/LeaderboardPage.jsx index 2145fd337..ba98d053c 100644 --- a/src/pages/LeaderboardPage/LeaderboardPage.jsx +++ b/src/pages/LeaderboardPage/LeaderboardPage.jsx @@ -2,15 +2,14 @@ import { Link } from "react-router-dom"; import { Button } from "../../components/Button/Button"; import styles from "./LeaderboardPage.module.css"; import { useLeaders } from "../../context/hooks/useLeaders"; -import unsuper1 from "./unsuper1.svg"; -import super1 from "./super1.svg"; -import unsuper2 from "./unsuper2.svg"; -import super2 from "./super2.svg"; +import ToolTipGame from "../../components/ToolTip/ToolTipGame"; +import ToolTipSuper from "../../components/ToolTip/ToolTipSuper"; export function LeaderboardPage() { const { leaders, setLeaders } = useLeaders(); setLeaders(leaders.sort((a, b) => +a.time - +b.time)); let leadersAchievments = leaders.map(leader => leader.achievements); + console.log(leadersAchievments); return (
@@ -35,7 +34,7 @@ export function LeaderboardPage() {

Время

- {leaders.map(leader => ( + {leaders.map((leader, i) => (

{leaders.indexOf(leader) + 1}

@@ -44,10 +43,8 @@ export function LeaderboardPage() {

{leader.name}

-
- {leader.achievements.includes(1) ? : } - {leader.achievements.includes(2) ? : } -
+ +

{leader.time}

From 575400b305ebc6c0d2df9a9c0ba134dd19d26ea0 Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Tue, 25 Jun 2024 21:33:18 +0300 Subject: [PATCH 10/12] =?UTF-8?q?///=D0=BD=D0=B5=D0=BF=D0=BE=D0=BD=D1=8F?= =?UTF-8?q?=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Cards/Cards.jsx | 2 +- src/components/EndGameModal/EndGameModal.jsx | 9 ++++++--- src/components/ToolTip/ToolTipGame.jsx | 1 - 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index f1f8ad765..a213efbf6 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -36,6 +36,7 @@ function getTimerValue(startDate, endDate) { seconds, }; } + /** * Основной компонент игры, внутри него находится вся игровая механика и логика. * pairsCount - сколько пар будет в игре @@ -87,7 +88,6 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { * - "Игрок проиграл", если на поле есть две открытые карты без пары * - "Игра продолжается", если не случилось первых двух условий */ - function alohomora() { if (achievements.includes(1)) { alert("Подсказкой можно воспользоваться только 1 раз"); diff --git a/src/components/EndGameModal/EndGameModal.jsx b/src/components/EndGameModal/EndGameModal.jsx index d03aa7b1d..35b298504 100644 --- a/src/components/EndGameModal/EndGameModal.jsx +++ b/src/components/EndGameModal/EndGameModal.jsx @@ -2,7 +2,7 @@ import styles from "./EndGameModal.module.css"; import { Button } from "../Button/Button"; import deadImageUrl from "./images/dead.png"; import celebrationImageUrl from "./images/celebration.png"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { postLeader } from "../../api"; import { useLeaders } from "../../context/hooks/useLeaders"; import { Link } from "react-router-dom"; @@ -15,7 +15,10 @@ export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, }); const { setLeaders, leaders } = useLeaders(); const [btnDisabled, setBtnDisabled] = useState(false); - setLeaders(leaders.sort((a, b) => +a.time - +b.time)); + + useEffect(() => { + setLeaders(leaders.sort((a, b) => +a.time - +b.time)); + }, [leaders, setLeaders]); const handleInputChange = e => { const { name, value } = e.target; @@ -72,7 +75,7 @@ export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, {gameDurationMinutes.toString().padStart("2", "0")}.{gameDurationSeconds.toString().padStart("2", "0")}
- +

Перейти к лидерборду

diff --git a/src/components/ToolTip/ToolTipGame.jsx b/src/components/ToolTip/ToolTipGame.jsx index 32570decf..8e36c7cce 100644 --- a/src/components/ToolTip/ToolTipGame.jsx +++ b/src/components/ToolTip/ToolTipGame.jsx @@ -11,7 +11,6 @@ export default function ToolTipGame(isAchievment, i) { refSetTimeout.current = setTimeout(() => { setShowToolTip(true); }, 750); - // console.log(isAchievment); }; const onMouseLeaveHandler = () => { From 1f113e414ed6968c17468ae3f1e4532da1278254 Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Wed, 26 Jun 2024 13:02:12 +0300 Subject: [PATCH 11/12] =?UTF-8?q?=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=5F?= =?UTF-8?q?=D0=BE=D1=87=D0=B8=D1=81=D0=BA=D0=B0=20=D0=BF=D0=BE=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=B2=D0=B2=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/EndGameModal/EndGameModal.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/EndGameModal/EndGameModal.jsx b/src/components/EndGameModal/EndGameModal.jsx index 35b298504..8e08b6100 100644 --- a/src/components/EndGameModal/EndGameModal.jsx +++ b/src/components/EndGameModal/EndGameModal.jsx @@ -33,6 +33,8 @@ export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, .then(leaders => { setLeaders(leaders.leaders); setBtnDisabled(!btnDisabled); + // Добавьте код для очистки поля ввода + setNewLeader({ name: "", time: "", achievements: "" }); }) .catch(error => { console.log(error); From 021836635cfffef95d291baf88ac667134cf4999 Mon Sep 17 00:00:00 2001 From: Elizaveta810 Date: Wed, 26 Jun 2024 13:03:28 +0300 Subject: [PATCH 12/12] ... --- src/components/EndGameModal/EndGameModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EndGameModal/EndGameModal.jsx b/src/components/EndGameModal/EndGameModal.jsx index 8e08b6100..f4e87f89f 100644 --- a/src/components/EndGameModal/EndGameModal.jsx +++ b/src/components/EndGameModal/EndGameModal.jsx @@ -68,7 +68,7 @@ export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, autoFocus="" />
)}