From 40a92448335c0f5bd224ee2bbf901b3782fb0053 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Sat, 20 Apr 2024 12:18:33 +0200 Subject: [PATCH 01/16] working - now the language selector is on the header - now the volume slider is on the header --- .../components/AudioButton/AudioButton.css | 31 ++++++++ .../src/components/AudioButton/AudioButton.js | 60 ++++++++++----- webapp/src/components/Header/Header.css | 77 +++++++++++++++++++ webapp/src/components/Header/Header.js | 52 +++++++++++-- .../LanguageSelector/LanguageSelector.js | 41 +++++++--- webapp/src/pages/Settings/Settings.js | 14 ---- 6 files changed, 224 insertions(+), 51 deletions(-) diff --git a/webapp/src/components/AudioButton/AudioButton.css b/webapp/src/components/AudioButton/AudioButton.css index b9eb6cff..b334e426 100644 --- a/webapp/src/components/AudioButton/AudioButton.css +++ b/webapp/src/components/AudioButton/AudioButton.css @@ -4,4 +4,35 @@ .play-btn { background-image: url("../../assets/mute.svg") +} + +.audio-button-container { + position: relative; /* Asegúrate de que el contenedor del botón de audio tiene position: relative */ +} + +.volume-slider-container { + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-80%); + width: auto; + max-width: calc(100vw - 20px); + min-width: 100px; + background: #fff; + border: 1px solid #ccc; + padding: 10px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + z-index: 1000; + opacity: 0; + visibility: hidden; + transition: visibility 1s, opacity 1s linear; + border-radius: 1em; +} + +.audio-button-container:hover .volume-slider-container, +.volume-slider-container:hover { + opacity: 1; + transform: translateX(-80%) translateY(0); + visibility: visible; + transition: visibility 1s, opacity 1s linear; } \ No newline at end of file diff --git a/webapp/src/components/AudioButton/AudioButton.js b/webapp/src/components/AudioButton/AudioButton.js index ca97591b..fd1e5287 100644 --- a/webapp/src/components/AudioButton/AudioButton.js +++ b/webapp/src/components/AudioButton/AudioButton.js @@ -4,24 +4,20 @@ import { ReactComponent as MuteIcon } from "../../assets/mute.svg"; import "./AudioButton.css"; import "../Header/Header.css"; import song from "../../assets/music.mp3"; +import Slider from "../../components/Slider/ContinuousSlider"; -const AudioButton = ({ volume }) => { +const AudioButton = () => { const [playing, setPlaying] = useState(false); - const [audio, setAudio] = useState(null); + const [audio, setAudio] = useState(new Audio(song)); + const [volume, setVolume] = useState(30); + const [showVolumeSlider, setShowVolumeSlider] = useState(false); + const [hideTimeout, setHideTimeout] = useState(null); useEffect(() => { - const audioElement = new Audio(song); - audioElement.loop = true; - audioElement.volume = volume / 100; - setAudio(audioElement); + audio.loop = true; + audio.volume = volume / 100; }, [volume]); - useEffect(() => { - if (audio) { - audio.volume = volume / 100; - } - }, [audio, volume]); - const play = () => { audio.play(); }; @@ -37,18 +33,42 @@ const AudioButton = ({ volume }) => { play(); } setPlaying(!playing); - //onChangeSound(!playing); + }; + + const handleMouseEnter = () => { + clearTimeout(hideTimeout); + setShowVolumeSlider(true); + }; + + const handleMouseLeave = () => { + setHideTimeout(setTimeout(() => { + setShowVolumeSlider(false); + }, 500)); + }; + + const handleVolumeChange = (event, newValue) => { + setVolume(newValue); }; return ( -
{ - if (event.key === 'Enter' || event.key === ' ') { - toggleAudio(); - } - }}> - {playing ? : } +
+
{ + if (event.key === 'Enter' || event.key === ' ') { + toggleAudio(); + } + }}> + {playing ? : } +
+ {showVolumeSlider && ( +
+ +
+ )}
); }; + export default AudioButton; \ No newline at end of file diff --git a/webapp/src/components/Header/Header.css b/webapp/src/components/Header/Header.css index 52d0e9b7..444e2e91 100644 --- a/webapp/src/components/Header/Header.css +++ b/webapp/src/components/Header/Header.css @@ -71,4 +71,81 @@ img { border-radius: 50%; cursor: pointer; color: #717bee; +} + +.options { + display: flex; +} + +/* Estilo para el contenedor del selector de idioma */ +.language-selector { + position: relative; + display: inline-block; + margin-left: auto; + margin-right: 1em; +} + +/* Estilo para el selector de idioma */ +.language-selector select { + position: relative; + padding: 10px; + font-size: 16px; + border: none; + border-radius: 4px; + background-color: #fff; + color: #717bee; + cursor: pointer; +} + +/* Estilo para el selector de idioma */ +.selected-language { + position: relative; + padding: 10px; + font-size: 16px; + border: none; + border-radius: 4px; + background-color: #fff; + color: #717bee; + cursor: pointer; + width: 8rem; + align-items: center; + align-content: center; +} + +/* Estilo para la flecha del desplegable */ +.selected-language::after { + content: '▼'; + position: absolute; + top: 50%; + transform: translateY(-50%); + pointer-events: none; +} + +.flag { + width: 1rem; + height: auto; + margin: 0rem; + margin-left: 0.5rem; +} + +.language-options { + position: absolute; + background-color: #fff; + width: 100%; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + z-index: 1; + top: 100%; +} + +.language-options div { + padding: 10px; + cursor: pointer; +} + +.language-options div:hover { + background-color: #f1f1f1; +} + +.homeButton { + align-items: center; } \ No newline at end of file diff --git a/webapp/src/components/Header/Header.js b/webapp/src/components/Header/Header.js index 41ef28c2..ac88d7f6 100644 --- a/webapp/src/components/Header/Header.js +++ b/webapp/src/components/Header/Header.js @@ -1,17 +1,42 @@ -import "./Header.css"; -import { Link } from 'react-router-dom' +import React, { useState } from 'react'; +import { Link } from 'react-router-dom'; import { ReactComponent as BarIcon } from "../../assets/bars-solid.svg"; import { ReactComponent as SunIcon } from "../../assets/sun-solid.svg"; import { ReactComponent as MoonIcon } from "../../assets/moon-solid.svg"; import AudioButton from "../AudioButton/AudioButton"; +import Slider from "../../components/Slider/ContinuousSlider"; +import "./Header.css"; +import LanguageSelector from '../../components/LanguageSelector/LanguageSelector'; const Header = props => { + const languages = [ + { + code: 'en', + name: 'English', + country_code: 'GB' + }, + { + code: 'es', + name: 'Español', + country_code: 'ES' + }, + { + code: 'fr', + name: 'Français', + country_code: 'FR' + } + ]; + + const [selectedLanguage, setSelectedLanguage] = useState(languages[0]); + const [showOptions, setShowOptions] = useState(false); + const [showVolumeSlider, setShowVolumeSlider] = useState(false); + return (
- + Logo of Know and Win APP - +
{ @@ -22,7 +47,18 @@ const Header = props => { {props.theme === "light" ? : }
- + setShowVolumeSlider(true)} + onMouseLeave={() => setShowVolumeSlider(false)} + /> + + {showVolumeSlider && ( +
+ +
+ )}
{ @@ -34,7 +70,7 @@ const Header = props => {
- ) -} + ); +}; -export default Header +export default Header; \ No newline at end of file diff --git a/webapp/src/components/LanguageSelector/LanguageSelector.js b/webapp/src/components/LanguageSelector/LanguageSelector.js index ccbf3b62..ed8fdb40 100644 --- a/webapp/src/components/LanguageSelector/LanguageSelector.js +++ b/webapp/src/components/LanguageSelector/LanguageSelector.js @@ -1,20 +1,43 @@ -import React from 'react'; +import React, { useState } from 'react'; import './LanguageSelector.css'; import i18next from 'i18next'; const LanguageSelector = ({ languages }) => { + const [showOptions, setShowOptions] = useState(false); + const [selectedLanguage, setSelectedLanguage] = useState(languages.find(lang => lang.code === i18next.language)); + + const handleLanguageChange = (language) => { + i18next.changeLanguage(language.code); + setSelectedLanguage(language); + setShowOptions(false); + }; return (
- +
setShowOptions(!showOptions)}> + {selectedLanguage.name} + {selectedLanguage.name} +
+ {showOptions && ( +
+ {languages.map(language => ( +
handleLanguageChange(language)}> + {language.name} + {language.name} +
+ ))} +
+ )}
); }; -export default LanguageSelector; +export default LanguageSelector; \ No newline at end of file diff --git a/webapp/src/pages/Settings/Settings.js b/webapp/src/pages/Settings/Settings.js index 52adc306..6e4e8ab8 100644 --- a/webapp/src/pages/Settings/Settings.js +++ b/webapp/src/pages/Settings/Settings.js @@ -31,20 +31,6 @@ const Settings = (props) => { return (

{t("settings.title")}

- -
- - -
- -
- -
- -
); } From 89f66f4ad1834a3d94e7e799926fac2b9780c19c Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Sat, 20 Apr 2024 13:51:43 +0200 Subject: [PATCH 02/16] Animation polish - Now language selector has an animation for opening and closing - Now language selector will be closed when you click in any other part of the app even if you didn't explicitly close it or choose a different language - Now the volume slider floaating window have a new animation for appearing or dissapearing --- .../components/AudioButton/AudioButton.css | 35 ++++++++++--- .../src/components/AudioButton/AudioButton.js | 30 ++++++----- .../LanguageSelector/LanguageSelector.css | 29 ++++++----- .../LanguageSelector/LanguageSelector.js | 50 +++++++++++++------ 4 files changed, 92 insertions(+), 52 deletions(-) diff --git a/webapp/src/components/AudioButton/AudioButton.css b/webapp/src/components/AudioButton/AudioButton.css index b334e426..bb9f31ec 100644 --- a/webapp/src/components/AudioButton/AudioButton.css +++ b/webapp/src/components/AudioButton/AudioButton.css @@ -1,3 +1,25 @@ +@keyframes expand { + 0% { + transform: translateX(-80%) scaleX(0) scaleY(0); + opacity: 0; + } + 100% { + transform: translateX(-80%) scaleX(1) scaleY(1); + opacity: 1; + } +} + +@keyframes collapse { + 0% { + transform: translateX(-80%) scaleX(1) scaleY(1); + opacity: 1; + } + 100% { + transform: translateX(-80%) scaleX(0) scaleY(0); + opacity: 0; + } +} + .pause-btn { background-image: url("../../assets/sound.svg"); } @@ -7,14 +29,15 @@ } .audio-button-container { - position: relative; /* Asegúrate de que el contenedor del botón de audio tiene position: relative */ + position: relative; } .volume-slider-container { position: absolute; top: 100%; left: 50%; - transform: translateX(-80%); + transform: translateX(-80%) scaleX(0) scaleY(0); + transform-origin: 80% top; width: auto; max-width: calc(100vw - 20px); min-width: 100px; @@ -24,15 +47,11 @@ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); z-index: 1000; opacity: 0; - visibility: hidden; - transition: visibility 1s, opacity 1s linear; + animation: collapse 0.5s forwards; border-radius: 1em; } .audio-button-container:hover .volume-slider-container, .volume-slider-container:hover { - opacity: 1; - transform: translateX(-80%) translateY(0); - visibility: visible; - transition: visibility 1s, opacity 1s linear; + animation: expand 0.5s forwards; } \ No newline at end of file diff --git a/webapp/src/components/AudioButton/AudioButton.js b/webapp/src/components/AudioButton/AudioButton.js index fd1e5287..2a7a54a0 100644 --- a/webapp/src/components/AudioButton/AudioButton.js +++ b/webapp/src/components/AudioButton/AudioButton.js @@ -51,23 +51,21 @@ const AudioButton = () => { }; return ( -
-
{ - if (event.key === 'Enter' || event.key === ' ') { - toggleAudio(); - } - }}> - {playing ? : } -
- {showVolumeSlider && ( -
- -
- )} +
+
{ + if (event.key === 'Enter' || event.key === ' ') { + toggleAudio(); + } + }}> + {playing ? : }
+
+ +
+
); }; diff --git a/webapp/src/components/LanguageSelector/LanguageSelector.css b/webapp/src/components/LanguageSelector/LanguageSelector.css index ea5848e7..555e8bcc 100644 --- a/webapp/src/components/LanguageSelector/LanguageSelector.css +++ b/webapp/src/components/LanguageSelector/LanguageSelector.css @@ -1,17 +1,22 @@ -.language-selector select { - padding: 8px; - font-size: 16px; - border-radius: 5px; - border: 1px solid #ccc; - background-color: #fff; - outline: none; - cursor: pointer; +@keyframes openAnimation { + 0% { max-height: 0; } + 100% { max-height: 100vh; } } -.language-selector select:hover { - border-color: #999; +@keyframes closeAnimation { + 0% { max-height: 100vh; } + 100% { max-height: 0; } } -.language-selector select:focus { - border-color: #555; +.language-options { + overflow: hidden; + transition: max-height 0.3s ease-in-out; +} + +.language-options.open { + animation: openAnimation 0.3s forwards; +} + +.language-options.close { + animation: closeAnimation 0.3s forwards; } \ No newline at end of file diff --git a/webapp/src/components/LanguageSelector/LanguageSelector.js b/webapp/src/components/LanguageSelector/LanguageSelector.js index ed8fdb40..18d25406 100644 --- a/webapp/src/components/LanguageSelector/LanguageSelector.js +++ b/webapp/src/components/LanguageSelector/LanguageSelector.js @@ -1,10 +1,11 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import './LanguageSelector.css'; import i18next from 'i18next'; const LanguageSelector = ({ languages }) => { const [showOptions, setShowOptions] = useState(false); const [selectedLanguage, setSelectedLanguage] = useState(languages.find(lang => lang.code === i18next.language)); + const languageSelectorRef = useRef(null); const handleLanguageChange = (language) => { i18next.changeLanguage(language.code); @@ -12,8 +13,21 @@ const LanguageSelector = ({ languages }) => { setShowOptions(false); }; + const handleClickOutside = (event) => { + if (languageSelectorRef.current && !languageSelectorRef.current.contains(event.target)) { + setShowOptions(false); + } + }; + + useEffect(() => { + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); + return ( -
+
setShowOptions(!showOptions)}> { /> {selectedLanguage.name}
- {showOptions && ( -
- {languages.map(language => ( -
handleLanguageChange(language)}> - {language.name} - {language.name} -
- ))} -
- )} +
+ {languages.map((language, index) => ( +
handleLanguageChange(language)} + className="language-option" + style={{ animationDelay: `${index * 0.1}s` }} + > + {language.name} + {language.name} +
+ ))} +
); }; From 3c5b318d93df55911189ca1dc667ebd9a56a0383 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Sat, 20 Apr 2024 15:31:58 +0200 Subject: [PATCH 03/16] fix - Dark mode is now supported for the new elements on the header --- webapp/src/components/AudioButton/AudioButton.css | 1 + webapp/src/components/Header/Header.css | 5 ++--- webapp/src/components/Slider/ContinuousSlider.js | 7 ++++++- webapp/src/index.css | 12 ++++++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/webapp/src/components/AudioButton/AudioButton.css b/webapp/src/components/AudioButton/AudioButton.css index bb9f31ec..4f89157a 100644 --- a/webapp/src/components/AudioButton/AudioButton.css +++ b/webapp/src/components/AudioButton/AudioButton.css @@ -49,6 +49,7 @@ opacity: 0; animation: collapse 0.5s forwards; border-radius: 1em; + align-items: center; } .audio-button-container:hover .volume-slider-container, diff --git a/webapp/src/components/Header/Header.css b/webapp/src/components/Header/Header.css index 444e2e91..a525fdd7 100644 --- a/webapp/src/components/Header/Header.css +++ b/webapp/src/components/Header/Header.css @@ -92,7 +92,7 @@ img { font-size: 16px; border: none; border-radius: 4px; - background-color: #fff; + background-color: inherit; color: #717bee; cursor: pointer; } @@ -105,7 +105,6 @@ img { border: none; border-radius: 4px; background-color: #fff; - color: #717bee; cursor: pointer; width: 8rem; align-items: center; @@ -143,7 +142,7 @@ img { } .language-options div:hover { - background-color: #f1f1f1; + background-color: #717bee; } .homeButton { diff --git a/webapp/src/components/Slider/ContinuousSlider.js b/webapp/src/components/Slider/ContinuousSlider.js index 865a9a9c..25f098ef 100644 --- a/webapp/src/components/Slider/ContinuousSlider.js +++ b/webapp/src/components/Slider/ContinuousSlider.js @@ -9,7 +9,12 @@ const ContinuousSlider = ({ volume, handleVolumeChange }) => { return ( - + diff --git a/webapp/src/index.css b/webapp/src/index.css index 4b344c88..4590fecb 100644 --- a/webapp/src/index.css +++ b/webapp/src/index.css @@ -44,6 +44,18 @@ main { background-color: var(--dark-gray); } +.dark .selected-language{ + background-color: var(--dark-gray); +} + +.dark .language-options { + background-color: var(--dark-gray); +} + +.dark .volume-slider-container { + background-color: var(--dark-gray); +} + .dark .nav-link { color: #fff; } From ae120570f1aa976635139082c54d78515e898fc3 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Thu, 25 Apr 2024 12:52:05 +0200 Subject: [PATCH 04/16] Removed Settings Tab --- webapp/src/components/Nav/Nav.js | 9 ---- webapp/src/components/test/Settings.test.js | 60 --------------------- webapp/src/pages/Settings/Settings.css | 26 --------- webapp/src/pages/Settings/Settings.js | 43 --------------- 4 files changed, 138 deletions(-) delete mode 100644 webapp/src/components/test/Settings.test.js delete mode 100644 webapp/src/pages/Settings/Settings.css delete mode 100644 webapp/src/pages/Settings/Settings.js diff --git a/webapp/src/components/Nav/Nav.js b/webapp/src/components/Nav/Nav.js index a5f68a4e..e8eaa1eb 100644 --- a/webapp/src/components/Nav/Nav.js +++ b/webapp/src/components/Nav/Nav.js @@ -97,15 +97,6 @@ const Nav = (props) => { {t("leaderboard.title")} - {user && ( - -
- -
- {t("settings.title")} - - )} -
{user ? : } diff --git a/webapp/src/components/test/Settings.test.js b/webapp/src/components/test/Settings.test.js deleted file mode 100644 index 5aa88390..00000000 --- a/webapp/src/components/test/Settings.test.js +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import Settings from '../../pages/Settings/Settings'; -import '@testing-library/jest-dom' -import { runI18n } from './utils/i18n.test-utils'; - - -describe('Settings component', () => { - beforeAll(() => { - runI18n() - }) - - it('renders without crashing', () => { - const onChangeTimerValue = jest.fn(); - const timerValue = 30; - - render(); - }); - - it('renders language options correctly', () => { - const onChangeTimerValue = jest.fn(); - const timerValue = 30; - - render(); - expect(screen.getByText('English')).toBeTruthy(); - expect(screen.getByText('Español')).toBeTruthy(); - expect(screen.getByText('Français')).toBeTruthy(); - }); - - it('renders the title correctly', () => { - const onChangeTimerValue = jest.fn(); - const timerValue = 30; - - render(); - - const titleElement = screen.getByRole('heading'); - expect(titleElement).toBeInTheDocument(); - - expect(titleElement.textContent).toBe('settings.title'); - }); - - it('renders the volume slider', () => { - const onChangeTimerValue = jest.fn(); - const timerValue = 30; - - render(); - expect(screen.getByRole('slider')).toBeTruthy(); - }); - - it('passes props to volume slider', () => { - const onChangeTimerValue = jest.fn(); - const timerValue = 30; - const volume = 50; - - render(); - const slider = screen.getByRole('slider'); - expect(slider).toHaveAttribute('aria-valuenow', '50'); - }); - -}); diff --git a/webapp/src/pages/Settings/Settings.css b/webapp/src/pages/Settings/Settings.css deleted file mode 100644 index 6ad7550c..00000000 --- a/webapp/src/pages/Settings/Settings.css +++ /dev/null @@ -1,26 +0,0 @@ -.settings { - margin-top: 1rem; - display: flex; - flex-direction: column; - align-items: center; -} - -.settings h1 { - margin-bottom: 50px; -} - -.settings label { - margin-right: 0.5rem; - margin-bottom: 10px; - display: inline-block; -} - -.settings select { - display: block; - padding: 5px; -} - -.settings-option { - display: flex; - align-items: first baseline; -} \ No newline at end of file diff --git a/webapp/src/pages/Settings/Settings.js b/webapp/src/pages/Settings/Settings.js deleted file mode 100644 index eabc6ac9..00000000 --- a/webapp/src/pages/Settings/Settings.js +++ /dev/null @@ -1,43 +0,0 @@ -import "./Settings.css"; -import LanguageSelector from "../../components/LanguageSelector/LanguageSelector"; -import Slider from "../../components/Slider/ContinuousSlider"; -import React from 'react'; -import { useTranslation } from "react-i18next"; -import './Settings.css' - -const Settings = (props) => { - - //Translation - const { t } = useTranslation(); - - const languages = [ - { - code: 'en', - name: 'English', - country_code: 'gb' - }, - { - code: 'es', - name: 'Español', - country_code: 'es' - }, - { - code: 'fr', - name: 'Français', - country_code: 'fr' - }, - { - code: 'uk', - name: 'Українська', - country_code: 'uk' - } - ] - - return ( -
-

{t("settings.title")}

-
- ); -} - -export default Settings; From 1758079743e1135b7f21f396154001dd8e379303 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Thu, 25 Apr 2024 13:01:53 +0200 Subject: [PATCH 05/16] Update App.js --- webapp/src/App.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/webapp/src/App.js b/webapp/src/App.js index 0fc51e88..937ebb52 100644 --- a/webapp/src/App.js +++ b/webapp/src/App.js @@ -5,7 +5,6 @@ import Profile from './pages/Profile/Profile' import Leaderboard from './pages/Leaderboard/Leaderboard' import Home from './pages/Home/Home' import AppLayout from './pages/AppLayout' -import Settings from './pages/Settings/Settings' import Login from './pages/Login/Login' import Logout from './pages/Logout/Logout' import Register from './pages/Register/Register' @@ -45,7 +44,6 @@ function App() { > } /> }> - }> From 3bca0971cf9af553156a4b7369eb23c196e43932 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Thu, 25 Apr 2024 13:30:17 +0200 Subject: [PATCH 06/16] Fix - Test for language selector now working --- .../LanguageSelector/LanguageSelector.js | 3 ++- webapp/src/components/test/Header.test.js | 13 +++++++++++ .../components/test/LanguageSelector.test.js | 22 +++++++++++++++---- webapp/src/components/test/Nav.test.js | 1 - webapp/src/components/test/index.test.js | 13 +++++++++++ 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/webapp/src/components/LanguageSelector/LanguageSelector.js b/webapp/src/components/LanguageSelector/LanguageSelector.js index 18d25406..104bf116 100644 --- a/webapp/src/components/LanguageSelector/LanguageSelector.js +++ b/webapp/src/components/LanguageSelector/LanguageSelector.js @@ -28,7 +28,7 @@ const LanguageSelector = ({ languages }) => { return (
-
setShowOptions(!showOptions)}> +
setShowOptions(!showOptions)}> {selectedLanguage.name} { > {language.name} { const ActualReact = jest.requireActual('react'); @@ -14,6 +15,18 @@ jest.mock('react', () => { }; }); +i18n.init({ + lng: 'en', + fallbackLng: 'en', + resources: { + en: { + translation: { + + }, + }, + }, + }) + describe('Header component', () => { it('renders without crashing', () => { render( diff --git a/webapp/src/components/test/LanguageSelector.test.js b/webapp/src/components/test/LanguageSelector.test.js index 38184a48..7b93e5ee 100644 --- a/webapp/src/components/test/LanguageSelector.test.js +++ b/webapp/src/components/test/LanguageSelector.test.js @@ -1,6 +1,21 @@ import React from 'react'; import { render } from '@testing-library/react'; +import {screen} from '@testing-library/dom' import LanguageSelector from '../../components/LanguageSelector/LanguageSelector'; +import i18n from 'i18next' + +i18n.init({ + lng: 'en', + fallbackLng: 'en', + resources: { + en: { + translation: { + 'languageSelector.language': 'English', + }, + }, + }, + }) + const languages = [ { code: 'en', @@ -23,12 +38,11 @@ test('renders LanguageSelector component with language options', () => { const { getByText } = render(); - const languageSelector = getByText(/English/i); - expect(languageSelector).toBeTruthy(); + expect(screen.queryByTestId('selectedLanguage')).toBeTruthy(); languages.forEach(language => { - const option = getByText(language.name); - expect(option).toBeTruthy(); + let lang = `flag${language.code}`; + expect(screen.queryByTestId(lang)).toBeTruthy(); }); }); diff --git a/webapp/src/components/test/Nav.test.js b/webapp/src/components/test/Nav.test.js index 200ba5c2..fa59a61a 100644 --- a/webapp/src/components/test/Nav.test.js +++ b/webapp/src/components/test/Nav.test.js @@ -30,7 +30,6 @@ describe('Nav component', () => { expect(screen.getByText(/Play/i)).toBeInTheDocument(); expect(screen.getByText(/Profile/i)).toBeInTheDocument(); expect(screen.getByText(/Leaderboard/i)).toBeInTheDocument(); - expect(screen.getByText(/Settings/i)).toBeInTheDocument(); // Simulate navigation toggle const closeButton = document.querySelector('.close-button'); diff --git a/webapp/src/components/test/index.test.js b/webapp/src/components/test/index.test.js index d728f709..32621996 100644 --- a/webapp/src/components/test/index.test.js +++ b/webapp/src/components/test/index.test.js @@ -3,6 +3,19 @@ import { BrowserRouter } from 'react-router-dom' import { render } from '@testing-library/react' import App from '../../App' import { runI18n } from './utils/i18n.test-utils' +import i18n from 'i18next' + +i18n.init({ + lng: 'en', + fallbackLng: 'en', + resources: { + en: { + translation: { + + }, + }, + }, +}) it('renders without crashing', () => { runI18n() From b28ede2151e4c4467fbb14d2f5c997bfdd587b57 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Thu, 25 Apr 2024 13:39:38 +0200 Subject: [PATCH 07/16] removed unused things --- webapp/src/App.js | 4 ---- webapp/src/components/AudioButton/AudioButton.js | 2 +- webapp/src/components/Header/Header.js | 2 -- webapp/src/components/Nav/Nav.js | 1 - 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/webapp/src/App.js b/webapp/src/App.js index 937ebb52..bd43e91e 100644 --- a/webapp/src/App.js +++ b/webapp/src/App.js @@ -21,10 +21,6 @@ function App() { //State for the volume const [volume, setVolume] = useState(10); - const handleVolumeChange = (event, newVolume) => { - setVolume(newVolume); - }; - return ( diff --git a/webapp/src/components/AudioButton/AudioButton.js b/webapp/src/components/AudioButton/AudioButton.js index 2a7a54a0..4f37bce2 100644 --- a/webapp/src/components/AudioButton/AudioButton.js +++ b/webapp/src/components/AudioButton/AudioButton.js @@ -8,7 +8,7 @@ import Slider from "../../components/Slider/ContinuousSlider"; const AudioButton = () => { const [playing, setPlaying] = useState(false); - const [audio, setAudio] = useState(new Audio(song)); + const [audio] = useState(new Audio(song)); const [volume, setVolume] = useState(30); const [showVolumeSlider, setShowVolumeSlider] = useState(false); const [hideTimeout, setHideTimeout] = useState(null); diff --git a/webapp/src/components/Header/Header.js b/webapp/src/components/Header/Header.js index ac88d7f6..cfaeef1c 100644 --- a/webapp/src/components/Header/Header.js +++ b/webapp/src/components/Header/Header.js @@ -27,8 +27,6 @@ const Header = props => { } ]; - const [selectedLanguage, setSelectedLanguage] = useState(languages[0]); - const [showOptions, setShowOptions] = useState(false); const [showVolumeSlider, setShowVolumeSlider] = useState(false); return ( diff --git a/webapp/src/components/Nav/Nav.js b/webapp/src/components/Nav/Nav.js index e8eaa1eb..b5f382c7 100644 --- a/webapp/src/components/Nav/Nav.js +++ b/webapp/src/components/Nav/Nav.js @@ -6,7 +6,6 @@ import { ReactComponent as CloseIcon } from '../../assets/xmark-solid.svg' import { ReactComponent as SquareQuestionIcon } from '../../assets/square-question.svg' import { ReactComponent as UserIcon } from '../../assets/user-solid.svg' import { ReactComponent as AwardIcon } from '../../assets/award-solid.svg' -import { ReactComponent as SettingsIcon } from '../../assets/gear-solid.svg' import { ReactComponent as LoginIcon } from '../../assets/login-solid.svg' import { ReactComponent as LogoutIcon } from '../../assets/logout-solid.svg' import { ReactComponent as SingUpIcon } from '../../assets/signup-solid.svg' From f94fd91a8b39f9b0b08455ba71cc99b4fee52a68 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Thu, 25 Apr 2024 13:42:54 +0200 Subject: [PATCH 08/16] removed unused things --- webapp/src/App.js | 2 +- webapp/src/components/AudioButton/AudioButton.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/src/App.js b/webapp/src/App.js index bd43e91e..9d3c65a6 100644 --- a/webapp/src/App.js +++ b/webapp/src/App.js @@ -19,7 +19,7 @@ import { useState } from 'react' function App() { //State for the volume - const [volume, setVolume] = useState(10); + const [volume] = useState(10); return ( diff --git a/webapp/src/components/AudioButton/AudioButton.js b/webapp/src/components/AudioButton/AudioButton.js index 4f37bce2..2a097b7e 100644 --- a/webapp/src/components/AudioButton/AudioButton.js +++ b/webapp/src/components/AudioButton/AudioButton.js @@ -16,7 +16,7 @@ const AudioButton = () => { useEffect(() => { audio.loop = true; audio.volume = volume / 100; - }, [volume]); + }, [volume, audio]); const play = () => { audio.play(); From 3eaf2cf3affea02849b01eb704a940c57d65e764 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Thu, 25 Apr 2024 13:56:23 +0200 Subject: [PATCH 09/16] Update AudioButton.js --- webapp/src/components/AudioButton/AudioButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/components/AudioButton/AudioButton.js b/webapp/src/components/AudioButton/AudioButton.js index 2a097b7e..44370288 100644 --- a/webapp/src/components/AudioButton/AudioButton.js +++ b/webapp/src/components/AudioButton/AudioButton.js @@ -53,7 +53,7 @@ const AudioButton = () => { return (
+ onMouseLeave={handleMouseLeave} role="button">
{ if (event.key === 'Enter' || event.key === ' ') { From 0ef2693a8eafee9f84e478399a015dc2f0e5100e Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Sun, 28 Apr 2024 16:11:20 +0200 Subject: [PATCH 10/16] Update AudioButton.js --- webapp/src/components/AudioButton/AudioButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/components/AudioButton/AudioButton.js b/webapp/src/components/AudioButton/AudioButton.js index 44370288..2a097b7e 100644 --- a/webapp/src/components/AudioButton/AudioButton.js +++ b/webapp/src/components/AudioButton/AudioButton.js @@ -53,7 +53,7 @@ const AudioButton = () => { return (
+ onMouseLeave={handleMouseLeave}>
{ if (event.key === 'Enter' || event.key === ' ') { From ef3f964ef8f73a04f5890533339dbb129b381216 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Sun, 28 Apr 2024 16:22:21 +0200 Subject: [PATCH 11/16] fixes for sonarcloud --- webapp/src/components/AudioButton/AudioButton.js | 4 +++- webapp/src/components/test/LanguageSelector.test.js | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/webapp/src/components/AudioButton/AudioButton.js b/webapp/src/components/AudioButton/AudioButton.js index 2a097b7e..f194c65e 100644 --- a/webapp/src/components/AudioButton/AudioButton.js +++ b/webapp/src/components/AudioButton/AudioButton.js @@ -59,7 +59,9 @@ const AudioButton = () => { if (event.key === 'Enter' || event.key === ' ') { toggleAudio(); } - }}> + }} + role="button" + aria-label={playing ? 'Mute audio' : 'Play audio'}> {playing ? : }
diff --git a/webapp/src/components/test/LanguageSelector.test.js b/webapp/src/components/test/LanguageSelector.test.js index 7b93e5ee..5b7bf5ec 100644 --- a/webapp/src/components/test/LanguageSelector.test.js +++ b/webapp/src/components/test/LanguageSelector.test.js @@ -35,12 +35,7 @@ const languages = [ ]; test('renders LanguageSelector component with language options', () => { - const { getByText } = render(); - - expect(screen.queryByTestId('selectedLanguage')).toBeTruthy(); - - languages.forEach(language => { let lang = `flag${language.code}`; expect(screen.queryByTestId(lang)).toBeTruthy(); From a0e8c86fae8fb8a209beca257cd0d46153f81a3c Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Sun, 28 Apr 2024 16:30:31 +0200 Subject: [PATCH 12/16] Update LanguageSelector.test.js --- webapp/src/components/test/LanguageSelector.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/src/components/test/LanguageSelector.test.js b/webapp/src/components/test/LanguageSelector.test.js index 5b7bf5ec..3c09e23b 100644 --- a/webapp/src/components/test/LanguageSelector.test.js +++ b/webapp/src/components/test/LanguageSelector.test.js @@ -35,6 +35,7 @@ const languages = [ ]; test('renders LanguageSelector component with language options', () => { + render(); expect(screen.queryByTestId('selectedLanguage')).toBeTruthy(); languages.forEach(language => { let lang = `flag${language.code}`; From 97a4bae62a910dce1b2be707799147456144a27a Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Sun, 28 Apr 2024 16:35:26 +0200 Subject: [PATCH 13/16] fix sonarcloud --- webapp/src/components/AudioButton/AudioButton.css | 4 ++-- webapp/src/components/AudioButton/AudioButton.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/src/components/AudioButton/AudioButton.css b/webapp/src/components/AudioButton/AudioButton.css index 4f89157a..90bbc089 100644 --- a/webapp/src/components/AudioButton/AudioButton.css +++ b/webapp/src/components/AudioButton/AudioButton.css @@ -28,7 +28,7 @@ background-image: url("../../assets/mute.svg") } -.audio-button-container { +.audio-container { position: relative; } @@ -52,7 +52,7 @@ align-items: center; } -.audio-button-container:hover .volume-slider-container, +.audio-container:hover .volume-slider-container, .volume-slider-container:hover { animation: expand 0.5s forwards; } \ No newline at end of file diff --git a/webapp/src/components/AudioButton/AudioButton.js b/webapp/src/components/AudioButton/AudioButton.js index f194c65e..282b027f 100644 --- a/webapp/src/components/AudioButton/AudioButton.js +++ b/webapp/src/components/AudioButton/AudioButton.js @@ -51,7 +51,7 @@ const AudioButton = () => { }; return ( -
Date: Sun, 28 Apr 2024 16:53:18 +0200 Subject: [PATCH 14/16] Update LanguageSelector.js --- .../LanguageSelector/LanguageSelector.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/webapp/src/components/LanguageSelector/LanguageSelector.js b/webapp/src/components/LanguageSelector/LanguageSelector.js index 104bf116..197cab41 100644 --- a/webapp/src/components/LanguageSelector/LanguageSelector.js +++ b/webapp/src/components/LanguageSelector/LanguageSelector.js @@ -28,7 +28,14 @@ const LanguageSelector = ({ languages }) => { return (
-
setShowOptions(!showOptions)}> +
setShowOptions(!showOptions)} + onKeyDown={(event) => { + if (event.key === 'Enter' || event.key === ' ') { + setShowOptions(!showOptions); + } + }} + tabIndex={0} + > {selectedLanguage.name} {
handleLanguageChange(language)} + onKeyDown={(event) => { + if (event.key === 'Enter' || event.key === ' ') { + handleLanguageChange(language); + } + }} className="language-option" style={{ animationDelay: `${index * 0.1}s` }} + tabIndex={0} > Date: Sun, 28 Apr 2024 17:15:03 +0200 Subject: [PATCH 15/16] Update AudioButton.js --- webapp/src/components/AudioButton/AudioButton.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/webapp/src/components/AudioButton/AudioButton.js b/webapp/src/components/AudioButton/AudioButton.js index 282b027f..7b28181a 100644 --- a/webapp/src/components/AudioButton/AudioButton.js +++ b/webapp/src/components/AudioButton/AudioButton.js @@ -59,9 +59,7 @@ const AudioButton = () => { if (event.key === 'Enter' || event.key === ' ') { toggleAudio(); } - }} - role="button" - aria-label={playing ? 'Mute audio' : 'Play audio'}> + }}> {playing ? : }
From 9d24893939e6926a0ca6e4439f69eff575da15e7 Mon Sep 17 00:00:00 2001 From: Veneiro <50624734+Veneiro@users.noreply.github.com> Date: Sun, 28 Apr 2024 18:27:32 +0200 Subject: [PATCH 16/16] Added Ukranian option to language selector --- webapp/src/components/Header/Header.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/webapp/src/components/Header/Header.js b/webapp/src/components/Header/Header.js index cfaeef1c..4e72b6f2 100644 --- a/webapp/src/components/Header/Header.js +++ b/webapp/src/components/Header/Header.js @@ -24,6 +24,11 @@ const Header = props => { code: 'fr', name: 'Français', country_code: 'FR' + }, + { + code: 'uk', + name: 'Ukranian', + country_code: 'UA' } ];