From 9734b0a680c6226057a4612672d8de98ef52df1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=B5=20=D0=B8=D0=BC=D1=8F?= <твоя почта> Date: Wed, 10 Apr 2024 22:17:03 +0400 Subject: [PATCH 1/7] =?UTF-8?q?=D0=B4=D0=B7=20=E2=84=961?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.json | 7 ++- .vscode/settings.json | 5 ++ src/components/Cards/Cards.jsx | 52 ++++++++++++++++--- src/components/Cards/Cards.module.css | 16 +++++- src/components/Cards/images/hearts.svg | 3 ++ src/pages/GamePage/GamePage.jsx | 5 +- src/pages/SelectLevelPage/SelectLevelPage.jsx | 12 +++-- .../SelectLevelPage.module.css | 32 ++++++++++++ src/router.js | 2 +- 9 files changed, 121 insertions(+), 13 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/components/Cards/images/hearts.svg diff --git a/.eslintrc.json b/.eslintrc.json index e37e1e072..7814cf6f2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,7 +3,12 @@ "plugins": ["prettier"], "rules": { "camelcase": ["error", { "properties": "never" }], - "prettier/prettier": "error", + "prettier/prettier": [ + "error", + { + "endOfLine": "auto" + } + ], "eqeqeq": ["error", "always"], "no-unused-vars": ["error"] } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..50dba2289 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "закрыта" + ] +} \ No newline at end of file diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index 7526a56c8..41f5b9114 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -40,7 +40,7 @@ function getTimerValue(startDate, endDate) { * pairsCount - сколько пар будет в игре * previewSeconds - сколько секунд пользователь будет видеть все карты открытыми до начала игры */ -export function Cards({ pairsCount = 3, previewSeconds = 5 }) { +export function Cards({ pairsCount = 3, previewSeconds = 5, isGameMode }) { // В cards лежит игровое поле - массив карт и их состояние открыта\закрыта const [cards, setCards] = useState([]); // Текущий статус игры @@ -57,6 +57,13 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { minutes: 0, }); + // Стейт для счетчика попыток + const [numberOfAttempts, setNumberOfAttempts] = useState(2); + const takeAwayTheAttempt = () => { + setNumberOfAttempts(numberOfAttempts - 1); + console.log(numberOfAttempts); + }; + function finishGame(status = STATUS_LOST) { setGameEndDate(new Date()); setStatus(status); @@ -73,6 +80,7 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { setGameEndDate(null); setTimer(getTimerValue(null, null)); setStatus(STATUS_PREVIEW); + setNumberOfAttempts(2); } /** @@ -126,11 +134,25 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { const playerLost = openCardsWithoutPair.length >= 2; // "Игрок проиграл", т.к на поле есть две открытые карты без пары - if (playerLost) { - finishGame(STATUS_LOST); - return; - } + if (isGameMode === "true") { + if (playerLost) { + takeAwayTheAttempt(); + if (numberOfAttempts < 1) { + finishGame(STATUS_LOST); + return; + } else { + setTimeout(() => { + setCards(cards.map(card => (openCardsWithoutPair.includes(card) ? { ...card, open: false } : card))); + }, 1000); + } + } + } else { + if (playerLost) { + finishGame(STATUS_LOST); + return; + } + } // ... игра продолжается }; @@ -195,7 +217,25 @@ export function Cards({ pairsCount = 3, previewSeconds = 5 }) { )} - {status === STATUS_IN_PROGRESS ? : null} + + {status === STATUS_IN_PROGRESS ? ( + <> + {isGameMode === "true" ? ( +
+ + + +
{numberOfAttempts + 1}
+
+ ) : null} + + + ) : null}
diff --git a/src/components/Cards/Cards.module.css b/src/components/Cards/Cards.module.css index 000c5006c..85675d4ae 100644 --- a/src/components/Cards/Cards.module.css +++ b/src/components/Cards/Cards.module.css @@ -67,6 +67,20 @@ font-style: normal; font-weight: 400; line-height: 32px; - margin-bottom: -12px; } + + +.attemptСounter { + display: flex; + gap: 10px; + color: red; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 30px; + font-style: normal; + font-weight: 400; + line-height: 30px; +} + + diff --git a/src/components/Cards/images/hearts.svg b/src/components/Cards/images/hearts.svg new file mode 100644 index 000000000..0e3720b4f --- /dev/null +++ b/src/components/Cards/images/hearts.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/pages/GamePage/GamePage.jsx b/src/pages/GamePage/GamePage.jsx index a4be871db..fa33617ba 100644 --- a/src/pages/GamePage/GamePage.jsx +++ b/src/pages/GamePage/GamePage.jsx @@ -4,10 +4,13 @@ import { Cards } from "../../components/Cards/Cards"; export function GamePage() { const { pairsCount } = useParams(); + const { isGameMode } = useParams(); + console.log(isGameMode); + console.log(pairsCount); return ( <> - + ); } diff --git a/src/pages/SelectLevelPage/SelectLevelPage.jsx b/src/pages/SelectLevelPage/SelectLevelPage.jsx index 758942e51..22ccf6429 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.jsx +++ b/src/pages/SelectLevelPage/SelectLevelPage.jsx @@ -1,28 +1,34 @@ import { Link } from "react-router-dom"; import styles from "./SelectLevelPage.module.css"; +import { useState } from "react"; export function SelectLevelPage() { + const [checked, setChecked] = useState(false); return (

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

  • - + 1
  • - + 2
  • - + 3
+
+ setChecked(!checked)} id="gameMode" /> + +
); diff --git a/src/pages/SelectLevelPage/SelectLevelPage.module.css b/src/pages/SelectLevelPage/SelectLevelPage.module.css index 390ac0def..10fff2fd8 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.module.css +++ b/src/pages/SelectLevelPage/SelectLevelPage.module.css @@ -62,3 +62,35 @@ .levelLink:visited { color: #0080c1; } + +.gameMode { + color: #004980; + text-align: center; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 20px; + font-style: normal; + font-weight: 400; + line-height: 48px; + border-radius: 12px; +} + +.gameMode input { + display: none; +} + +.gameMode label { + background-color: white; + border-radius: 12px; + padding: 10px; +} + +.gameMode input:checked+label { + color: white; + background-color: #004980; +} + +.gameMode:hover { + color: white; + background-color: #004980; +} \ No newline at end of file diff --git a/src/router.js b/src/router.js index da6e94b51..a3429490b 100644 --- a/src/router.js +++ b/src/router.js @@ -9,7 +9,7 @@ export const router = createBrowserRouter( element: , }, { - path: "/game/:pairsCount", + path: "/game/:pairsCount/:isGameMode", element: , }, ], From 85ed9f5c74fa94a11f205a442960e27f398d9249 Mon Sep 17 00:00:00 2001 From: NastyaTsyf <131529051+NastyaTsyf@users.noreply.github.com> Date: Wed, 10 Apr 2024 22:19:29 +0400 Subject: [PATCH 2/7] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9b90842c4..a4c033e73 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,6 @@ https://skypro-web-developer.github.io/react-memo/ Запускает eslint проверку кода, эта же команда запускается перед каждым коммитом. Если не получается закоммитить, попробуйте запустить эту команду и исправить все ошибки и предупреждения. + +Предплагаемое время на выполнение ДЗ №1 5 часов +фактическое время 6.5 часов From a73cc10b0707c5131f0ed7ed4eff8a429505b472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=B5=20=D0=B8=D0=BC=D1=8F?= <твоя почта> Date: Sun, 28 Apr 2024 13:06:25 +0400 Subject: [PATCH 3/7] =?UTF-8?q?=D0=B4=D0=B7=20=E2=84=962?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api.js | 27 +++++++ src/components/EndGameModal/EndGameModal.jsx | 71 ++++++++++++++++++- .../EndGameModal/EndGameModal.module.css | 45 ++++++++++-- src/pages/LeaderboardPage/LeaderboardPage.jsx | 52 ++++++++++++++ .../LeaderboardPage.module.css | 64 +++++++++++++++++ src/pages/SelectLevelPage/SelectLevelPage.jsx | 7 +- .../SelectLevelPage.module.css | 21 +++++- src/router.js | 5 ++ 8 files changed, 283 insertions(+), 9 deletions(-) create mode 100644 src/api.js create mode 100644 src/pages/LeaderboardPage/LeaderboardPage.jsx create mode 100644 src/pages/LeaderboardPage/LeaderboardPage.module.css diff --git a/src/api.js b/src/api.js new file mode 100644 index 000000000..4e982df8b --- /dev/null +++ b/src/api.js @@ -0,0 +1,27 @@ +//Получить список лидеров + +export async function getLeaders() { + const response = await fetch(`https://wedev-api.sky.pro/api/leaderboard`, { method: "GET" }); + if (!response.status === 200) { + throw new Error("Не удалось получить список лидеров"); + } + const data = await response.json(); + return data; +} + +export async function addLeaders({ name, time }) { + const response = await fetch(`https://wedev-api.sky.pro/api/leaderboard`, { + method: "POST", + body: JSON.stringify({ + name, + time, + }), + }); + if (!response.status === 201) { + throw new Error("Не удалось добавить в список лидеров"); + } else if (response.status === 400) { + throw new Error("Введите Ваше имя"); + } + const data = await response.json(); + return data; +} diff --git a/src/components/EndGameModal/EndGameModal.jsx b/src/components/EndGameModal/EndGameModal.jsx index 722394833..14b3a4ef5 100644 --- a/src/components/EndGameModal/EndGameModal.jsx +++ b/src/components/EndGameModal/EndGameModal.jsx @@ -4,9 +4,57 @@ import { Button } from "../Button/Button"; import deadImageUrl from "./images/dead.png"; import celebrationImageUrl from "./images/celebration.png"; +import { useNavigate, useParams } from "react-router-dom"; +import { useState } from "react"; +import { addLeaders } from "../../api"; export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, onClick }) { - const title = isWon ? "Вы победили!" : "Вы проиграли!"; + const { isGameMode } = useParams(); + const { pairsCount } = useParams(); + const navigate = useNavigate(); + const gameSeconds = gameDurationMinutes * 60 + gameDurationSeconds; + console.log(gameSeconds); + const [userData, setuserData] = useState({ + name: " ", + time: gameSeconds, + }); + + const handleInputChange = e => { + const { name, value } = e.target; // Извлекаем имя поля и его значение + + setuserData({ + ...userData, // Копируем текущие данные из состояния + [name]: value, // Обновляем нужное поле + }); + }; + + async function handleAddUser(e) { + e.preventDefault(); + try { + await addLeaders(userData).then(data => { + navigate(`/leaderboard`); + }); + } catch (error) { + alert(error.message); + } + } + async function handleAddUserButton(e) { + e.preventDefault(); + try { + await addLeaders(userData).then(data => { + onClick(); + }); + } catch (error) { + alert(error.message); + } + } + + let title = ""; + if (pairsCount === "9") { + title = isWon ? "Вы попали на лидерборд!" : "Вы проиграли!"; + } else { + title = isWon ? "Вы победили!" : "Вы проиграли!"; + } const imgSrc = isWon ? celebrationImageUrl : deadImageUrl; @@ -16,12 +64,29 @@ export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes,
{imgAlt}

{title}

+ {isGameMode === "false" && pairsCount === "9" && isWon ? ( +
+ +
+ ) : null}

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

{gameDurationMinutes.toString().padStart("2", "0")}.{gameDurationSeconds.toString().padStart("2", "0")}
- - + + {isGameMode === "false" && pairsCount === "9" && isWon ? ( +
+ Перейти к лидерборду +
+ ) : null}
); } diff --git a/src/components/EndGameModal/EndGameModal.module.css b/src/components/EndGameModal/EndGameModal.module.css index 9368cb8b5..593431089 100644 --- a/src/components/EndGameModal/EndGameModal.module.css +++ b/src/components/EndGameModal/EndGameModal.module.css @@ -1,6 +1,7 @@ .modal { width: 480px; - height: 459px; + padding-top: 30px; + padding-bottom: 30px; border-radius: 12px; background: #c2f5ff; display: flex; @@ -23,7 +24,7 @@ font-style: normal; font-weight: 400; line-height: 48px; - + text-align: center; margin-bottom: 28px; } @@ -35,7 +36,6 @@ font-style: normal; font-weight: 400; line-height: 32px; - margin-bottom: 10px; } @@ -46,6 +46,43 @@ font-style: normal; font-weight: 400; line-height: 72px; - margin-bottom: 40px; } + + +.leaderboardLink { + padding-top: 10px; + padding-bottom: 10px; + color: #004980; + text-align: center; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: 32px; + text-decoration:underline +} + +.leaderboardLink:hover { + text-decoration:none +} + +.form{ + padding-top: 10px; + padding-bottom: 20px; +} +.nameInput { + width:276px; + height:45px; + border-radius:10px; + border: none; + color: #999999; + text-align: center; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 24px; + font-style: normal; + font-weight: 400; + line-height: 32px; +} diff --git a/src/pages/LeaderboardPage/LeaderboardPage.jsx b/src/pages/LeaderboardPage/LeaderboardPage.jsx new file mode 100644 index 000000000..4fcf6bf43 --- /dev/null +++ b/src/pages/LeaderboardPage/LeaderboardPage.jsx @@ -0,0 +1,52 @@ +import styles from "./LeaderboardPage.module.css"; +import { useEffect, useState } from "react"; +import { getLeaders } from "../../api"; +import { Button } from "../../components/Button/Button"; +import { useNavigate } from "react-router-dom"; + +export function LeaderboardPage() { + const [leaders, setLeaders] = useState([]); + useEffect(() => { + getLeaders().then(leadersList => { + setLeaders(leadersList.leaders); + }); + }, []); + const navigate = useNavigate(); + const startTheGame = e => { + e.preventDefault(); + navigate(`/`); + }; + + let i = 1; + return ( +
+
+

Лидерборд

+ +
+
    +
    +
    Позиция
    +
    Пользователь
    +
    Время
    +
    + {leaders + .sort((a, b) => +a.time - +b.time) + .map(leader => { + return ( +
  • +
    # {i++}
    +
    {leader.name}
    +
    + {Math.trunc(leader.time / 60) + .toString() + .padStart("2", "0")} + :{(leader.time % 60).toString().padStart("2", "0")} +
    +
  • + ); + })} +
+
+ ); +} diff --git a/src/pages/LeaderboardPage/LeaderboardPage.module.css b/src/pages/LeaderboardPage/LeaderboardPage.module.css new file mode 100644 index 000000000..86c985843 --- /dev/null +++ b/src/pages/LeaderboardPage/LeaderboardPage.module.css @@ -0,0 +1,64 @@ +* { + margin: 0; + padding: 0; +} + +.container { + padding: 40px; +} + +.header{ + display: flex; + justify-content:space-between +} + +.leaderboard { + padding-top: 40px; + display: flex; + flex-direction:column; + gap: 12px; +} + +.headerTitle { + color: #FFFFFF; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 24px; + font-style: normal; + font-weight: 400; + line-height: 32px; + text-align: center; +} + +.leadersItemTitle { + color: #999999; + list-style-type:none; + background-color: #FFFFFF; + padding: 10px 20px; + border-radius: 12px; + display: flex; + justify-content:space-between; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 24px; + font-style: normal; + font-weight: 400; + line-height: 32px; +} + +.leadersItem { + list-style-type:none; + background-color: #FFFFFF; + padding: 10px 20px; + border-radius: 12px; + display: flex; + justify-content:space-between; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 24px; + font-style: normal; + font-weight: 400; + line-height: 32px; +} + + diff --git a/src/pages/SelectLevelPage/SelectLevelPage.jsx b/src/pages/SelectLevelPage/SelectLevelPage.jsx index 22ccf6429..3a6bab369 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.jsx +++ b/src/pages/SelectLevelPage/SelectLevelPage.jsx @@ -27,7 +27,12 @@ export function SelectLevelPage() {
setChecked(!checked)} id="gameMode" /> - + +
+
+ + Перейти к лидерборду +
diff --git a/src/pages/SelectLevelPage/SelectLevelPage.module.css b/src/pages/SelectLevelPage/SelectLevelPage.module.css index 10fff2fd8..4fe631cc3 100644 --- a/src/pages/SelectLevelPage/SelectLevelPage.module.css +++ b/src/pages/SelectLevelPage/SelectLevelPage.module.css @@ -80,7 +80,6 @@ } .gameMode label { - background-color: white; border-radius: 12px; padding: 10px; } @@ -93,4 +92,24 @@ .gameMode:hover { color: white; background-color: #004980; +} + +.leaderboardLinkBox { + padding-top: 10px; + padding-bottom: 10px; +} + +.leaderboardLink { + color: #004980; + text-align: center; + font-variant-numeric: lining-nums proportional-nums; + font-family: StratosSkyeng; + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: 32px; +} + +.leaderboardLink:hover { + text-decoration:none } \ No newline at end of file diff --git a/src/router.js b/src/router.js index a3429490b..b3a22d233 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/:isGameMode", element: , }, + { + path: "/leaderboard", + element: , + }, ], /** * basename нужен для корректной работы в gh pages From 0f8587b61ce2e5f87ece6d0e1d5dd192e561c932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=B5=20=D0=B8=D0=BC=D1=8F?= <твоя почта> Date: Sun, 28 Apr 2024 13:07:39 +0400 Subject: [PATCH 4/7] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BE=D1=86=D0=B5=D0=BD=D0=BA=D0=B0=20=D0=B2?= =?UTF-8?q?=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a4c033e73..6fac7b3ce 100644 --- a/README.md +++ b/README.md @@ -47,3 +47,6 @@ https://skypro-web-developer.github.io/react-memo/ Предплагаемое время на выполнение ДЗ №1 5 часов фактическое время 6.5 часов + +Предплагаемое время на выполнение ДЗ №2 5 часов +фактическое время 5 часов From 21deef63ab2340de6874c72c91ff157325014c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=B5=20=D0=B8=D0=BC=D1=8F?= <твоя почта> Date: Thu, 20 Jun 2024 23:29:41 +0400 Subject: [PATCH 5/7] =?UTF-8?q?=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B0=20=D0=BE=D1=82=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=B0=D1=87=D0=B8=D0=B2=D0=BE=D0=BA=20=D0=B2=20?= =?UTF-8?q?API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api.js | 7 +- src/components/Cards/Cards.jsx | 89 +++++++++- src/components/EndGameModal/EndGameModal.jsx | 7 +- src/lib.jsx | 164 ++++++++++++++++++ src/pages/GamePage/GamePage.jsx | 2 - src/pages/LeaderboardPage/LeaderboardPage.jsx | 12 ++ .../LeaderboardPage.module.css | 5 + 7 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 src/lib.jsx diff --git a/src/api.js b/src/api.js index 4e982df8b..a9d9892ae 100644 --- a/src/api.js +++ b/src/api.js @@ -1,7 +1,7 @@ //Получить список лидеров export async function getLeaders() { - const response = await fetch(`https://wedev-api.sky.pro/api/leaderboard`, { method: "GET" }); + const response = await fetch(`https://wedev-api.sky.pro/api/v2/leaderboard`, { method: "GET" }); if (!response.status === 200) { throw new Error("Не удалось получить список лидеров"); } @@ -9,12 +9,13 @@ export async function getLeaders() { return data; } -export async function addLeaders({ name, time }) { - const response = await fetch(`https://wedev-api.sky.pro/api/leaderboard`, { +export async function addLeaders({ name, time, achievements }) { + const response = await fetch(`https://wedev-api.sky.pro/api/v2/leaderboard`, { method: "POST", body: JSON.stringify({ name, time, + achievements, }), }); if (!response.status === 201) { diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index 41f5b9114..5f78e7c7c 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -61,12 +61,24 @@ export function Cards({ pairsCount = 3, previewSeconds = 5, isGameMode }) { const [numberOfAttempts, setNumberOfAttempts] = useState(2); const takeAwayTheAttempt = () => { setNumberOfAttempts(numberOfAttempts - 1); - console.log(numberOfAttempts); }; + // стейт для массива достижений + const [achievementsArr, setAchievementsArr] = useState([]); + + // стейт чтобы определить были ли использованы суперсилы + const [superPowersUsed, setSuperpowersUsed] = useState(false); function finishGame(status = STATUS_LOST) { setGameEndDate(new Date()); setStatus(status); + if (pairsCount > 8) { + achievementsArr.push(1); + setAchievementsArr(achievementsArr); + } + if (!superPowersUsed) { + achievementsArr.push(2); + setAchievementsArr(achievementsArr); + } } function startGame() { const startDate = new Date(); @@ -81,11 +93,13 @@ export function Cards({ pairsCount = 3, previewSeconds = 5, isGameMode }) { setTimer(getTimerValue(null, null)); setStatus(STATUS_PREVIEW); setNumberOfAttempts(2); + setSuperpowersUsed(false); + setAchievementsArr([]); } /** * Обработка основного действия в игре - открытие карты. - * После открытия карты игра может пепереходит в следующие состояния + * После открытия карты игра может переходит в следующие состояния * - "Игрок выиграл", если на поле открыты все карты * - "Игрок проиграл", если на поле есть две открытые карты без пары * - "Игра продолжается", если не случилось первых двух условий @@ -194,6 +208,23 @@ export function Cards({ pairsCount = 3, previewSeconds = 5, isGameMode }) { }; }, [gameStartDate, gameEndDate]); + // Закрытые карты на игровом поле + const reversedCards = cards.filter(card => !card.open); + + // Cуперсила "алохомора" + function alohomora() { + if (!superPowersUsed & (reversedCards.length > 2)) { + const randomCard = shuffle(reversedCards)[0]; + const randomPair = reversedCards.filter( + sameCard => randomCard.suit === sameCard.suit && randomCard.rank === sameCard.rank, + ); + randomPair[0].open = true; + randomPair[1].open = true; + setSuperpowersUsed(true); + } + return; + } + return (
@@ -220,6 +251,58 @@ export function Cards({ pairsCount = 3, previewSeconds = 5, isGameMode }) { {status === STATUS_IN_PROGRESS ? ( <> +
+
+ + + + + + + + + + + + + +
+
{isGameMode === "true" ? (
@@ -257,6 +340,8 @@ export function Cards({ pairsCount = 3, previewSeconds = 5, isGameMode }) { gameDurationSeconds={timer.seconds} gameDurationMinutes={timer.minutes} onClick={resetGame} + isGameMode + achievementsArr={achievementsArr} />
) : null} diff --git a/src/components/EndGameModal/EndGameModal.jsx b/src/components/EndGameModal/EndGameModal.jsx index 14b3a4ef5..36d847b5e 100644 --- a/src/components/EndGameModal/EndGameModal.jsx +++ b/src/components/EndGameModal/EndGameModal.jsx @@ -8,15 +8,18 @@ import { useNavigate, useParams } from "react-router-dom"; import { useState } from "react"; import { addLeaders } from "../../api"; -export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, onClick }) { +export function EndGameModal({ isWon, gameDurationSeconds, gameDurationMinutes, onClick, achievementsArr }) { + console.log(achievementsArr); + isWon = true; const { isGameMode } = useParams(); const { pairsCount } = useParams(); const navigate = useNavigate(); const gameSeconds = gameDurationMinutes * 60 + gameDurationSeconds; - console.log(gameSeconds); + const [userData, setuserData] = useState({ name: " ", time: gameSeconds, + achievements: achievementsArr, }); const handleInputChange = e => { diff --git a/src/lib.jsx b/src/lib.jsx new file mode 100644 index 000000000..3b9be090d --- /dev/null +++ b/src/lib.jsx @@ -0,0 +1,164 @@ +export const achievementsIcons = { + hardMode: ( + + + + + + + + + + + + + + + + + + ), + hardModeActive: ( + + + + + + + + + + + + + + + + ), + withoutSuperPowers: ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ), + withoutSuperPowersActive: ( + + + + + + + + + + + + + + + ), +}; diff --git a/src/pages/GamePage/GamePage.jsx b/src/pages/GamePage/GamePage.jsx index fa33617ba..4c5404265 100644 --- a/src/pages/GamePage/GamePage.jsx +++ b/src/pages/GamePage/GamePage.jsx @@ -5,8 +5,6 @@ import { Cards } from "../../components/Cards/Cards"; export function GamePage() { const { pairsCount } = useParams(); const { isGameMode } = useParams(); - console.log(isGameMode); - console.log(pairsCount); return ( <> diff --git a/src/pages/LeaderboardPage/LeaderboardPage.jsx b/src/pages/LeaderboardPage/LeaderboardPage.jsx index 4fcf6bf43..cc00e3f74 100644 --- a/src/pages/LeaderboardPage/LeaderboardPage.jsx +++ b/src/pages/LeaderboardPage/LeaderboardPage.jsx @@ -3,6 +3,7 @@ import { useEffect, useState } from "react"; import { getLeaders } from "../../api"; import { Button } from "../../components/Button/Button"; import { useNavigate } from "react-router-dom"; +import { achievementsIcons } from "../../lib"; export function LeaderboardPage() { const [leaders, setLeaders] = useState([]); @@ -28,6 +29,7 @@ export function LeaderboardPage() {
Позиция
Пользователь
+
Достижения
Время
{leaders @@ -37,6 +39,16 @@ export function LeaderboardPage() {
  • # {i++}
    {leader.name}
    +
    +
    + {leader.achievements.includes(1) ? achievementsIcons.hardModeActive : achievementsIcons.hardMode} +
    +
    + {leader.achievements.includes(2) + ? achievementsIcons.withoutSuperPowersActive + : achievementsIcons.withoutSuperPowers} +
    +
    {Math.trunc(leader.time / 60) .toString() diff --git a/src/pages/LeaderboardPage/LeaderboardPage.module.css b/src/pages/LeaderboardPage/LeaderboardPage.module.css index 86c985843..319d71573 100644 --- a/src/pages/LeaderboardPage/LeaderboardPage.module.css +++ b/src/pages/LeaderboardPage/LeaderboardPage.module.css @@ -61,4 +61,9 @@ line-height: 32px; } +.achievementsIcons{ + display: flex; + gap: 6px; +} + From a8b78b5d2861c6aa80e06b7c0f1a498a3b67570e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=B5=20=D0=B8=D0=BC=D1=8F?= <твоя почта> Date: Fri, 21 Jun 2024 13:17:16 +0400 Subject: [PATCH 6/7] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BF=D0=BE=D0=B4=D1=81=D0=BA=D0=B0=D0=B7=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BF=D1=80=D0=B8=20=D0=BD=D0=B0=D0=B2=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Cards/Cards.jsx | 104 +++++++++--------- src/components/Tooltip/Tooltip.jsx | 22 ++++ src/components/Tooltip/Tooltip.module.css | 25 +++++ src/pages/LeaderboardPage/LeaderboardPage.jsx | 23 ++-- 4 files changed, 115 insertions(+), 59 deletions(-) create mode 100644 src/components/Tooltip/Tooltip.jsx create mode 100644 src/components/Tooltip/Tooltip.module.css diff --git a/src/components/Cards/Cards.jsx b/src/components/Cards/Cards.jsx index 5f78e7c7c..dcb983ff1 100644 --- a/src/components/Cards/Cards.jsx +++ b/src/components/Cards/Cards.jsx @@ -5,6 +5,8 @@ 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 { ToolTipComponent } from "../Tooltip/Tooltip"; +import { superPowerData } from "../../lib"; // Игра закончилась const STATUS_LOST = "STATUS_LOST"; @@ -252,56 +254,58 @@ export function Cards({ pairsCount = 3, previewSeconds = 5, isGameMode }) { {status === STATUS_IN_PROGRESS ? ( <>
    -
    - - - - - - - - - - - - - -
    + +
    + + + + + + + + + + + + + +
    +
    {isGameMode === "true" ? (
    diff --git a/src/components/Tooltip/Tooltip.jsx b/src/components/Tooltip/Tooltip.jsx new file mode 100644 index 000000000..89c0daf10 --- /dev/null +++ b/src/components/Tooltip/Tooltip.jsx @@ -0,0 +1,22 @@ +import { useState } from "react"; +import styles from "./Tooltip.module.css"; +export function ToolTipComponent({ children, text, title }) { + const [showToolTip, setShowToolTip] = useState(false); + const onMouseEnterHandler = () => { + setShowToolTip(true); + }; + const onMouseLeaveHandler = () => { + setShowToolTip(false); + }; + return ( +
    + {children} + {showToolTip && ( +
    +

    {title}

    +

    {text}

    +
    + )} +
    + ); +} diff --git a/src/components/Tooltip/Tooltip.module.css b/src/components/Tooltip/Tooltip.module.css new file mode 100644 index 000000000..38e9cd91f --- /dev/null +++ b/src/components/Tooltip/Tooltip.module.css @@ -0,0 +1,25 @@ +.container { + display: flex; + align-items: center; + justify-content: center; + +} + +.tooltip { + margin-top: 170px; + font-family: StratosSkyeng; + font-size: 18px; + font-style: normal; + position: absolute; + padding: 20px; + justify-content: center; + color: #004980; + background-color: #C2F5FF; + border-radius: 12px; + text-align: center; + white-space: pre-line; + font-weight: 400; + pointer-events: none; + z-index: 2; + max-height: 223px; +} \ No newline at end of file diff --git a/src/pages/LeaderboardPage/LeaderboardPage.jsx b/src/pages/LeaderboardPage/LeaderboardPage.jsx index cc00e3f74..4d07b46e4 100644 --- a/src/pages/LeaderboardPage/LeaderboardPage.jsx +++ b/src/pages/LeaderboardPage/LeaderboardPage.jsx @@ -3,7 +3,8 @@ import { useEffect, useState } from "react"; import { getLeaders } from "../../api"; import { Button } from "../../components/Button/Button"; import { useNavigate } from "react-router-dom"; -import { achievementsIcons } from "../../lib"; +import { achievementsIcons, achievementsText } from "../../lib"; +import { ToolTipComponent } from "../../components/Tooltip/Tooltip"; export function LeaderboardPage() { const [leaders, setLeaders] = useState([]); @@ -40,14 +41,18 @@ export function LeaderboardPage() {
    # {i++}
    {leader.name}
    -
    - {leader.achievements.includes(1) ? achievementsIcons.hardModeActive : achievementsIcons.hardMode} -
    -
    - {leader.achievements.includes(2) - ? achievementsIcons.withoutSuperPowersActive - : achievementsIcons.withoutSuperPowers} -
    + +
    + {leader.achievements.includes(1) ? achievementsIcons.hardModeActive : achievementsIcons.hardMode} +
    +
    + +
    + {leader.achievements.includes(2) + ? achievementsIcons.withoutSuperPowersActive + : achievementsIcons.withoutSuperPowers} +
    +
    {Math.trunc(leader.time / 60) From 1661ff94ef536665d8a464ab15f6d44a48b348ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=B5=20=D0=B8=D0=BC=D1=8F?= <твоя почта> Date: Fri, 21 Jun 2024 13:17:54 +0400 Subject: [PATCH 7/7] 1 --- src/lib.jsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib.jsx b/src/lib.jsx index 3b9be090d..335e37b2b 100644 --- a/src/lib.jsx +++ b/src/lib.jsx @@ -1,3 +1,15 @@ +export const superPowerData = { + alohomora: { + title: "Алохомора", + text: "Открывается случайная пара карт", + }, +}; + +export const achievementsText = { + hardMode: "Игра пройдена в сложном режиме", + withoutSuperPowers: "Игра пройдена без супер-сил", +}; + export const achievementsIcons = { hardMode: (