import React from "react"; import { useTranslation, Trans } from "react-i18next"; import styled from "styled-components"; import { useQuery } from "react-query"; import { NavLink } from "react-router-dom"; import SliderRange from "../ui/SliderRange"; import Spinner from "../ui/Spinner"; import playerSVG from "../images/player.svg"; import languageSVG from "../images/language.svg"; import clockSVG from "../images/clock.svg"; import { getGames } from "../utils/api"; import { search } from "../utils"; import GameListItem from "./GameListItem"; import { StyledGameList } from "./StyledGameList"; const Header = styled.header` background-color: var(--bg-color); position: relative; background: linear-gradient( 180deg, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.6) 40%, rgba(0, 0, 0, 0.6) 60%, rgba(0, 0, 0, 1) 100% ), 100% 50% / contain no-repeat url(/hero.png); padding: 14vh 5%; margin-bottom: 20px; & .baseline { padding: 2px; font-weigth: 800; font-size: 3.2vw; line-height: 1.2em; } & .subbaseline { padding: 2px; color: var(--font-color2); font-size: 1.4vw; } @media screen and (max-width: 1024px) { & { padding: 1em 5%; } & .baseline { display: inline-block; background-color: #00000088; font-size: 32px; } & .subbaseline { display: inline-block; background-color: #00000088; font-size: 16px; } } @media screen and (max-width: 640px) { & { display: none; } } `; const Filter = styled.div` text-align: center; & .incentive { width: 100%; font-size: 3.5vw; padding: 0.5em; padding-bottom: 0; margin: 0; line-height: 1em; } & .subincentive { font-size: 1.3em; } @media screen and (max-width: 1024px) { & .incentive { font-size: 32px; } } input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="color"]):not([type="button"]):not([type="reset"]) { background-color: #1c1c1c; color: var(--font-color2); max-width: 30rem; display: inline; margin: 2rem; &::placeholder { color: var(--font-color2); } } `; const StyledGameFilters = styled.ul` list-style: none; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; padding: 0; > li { flex: auto; max-width: 25rem; margin: 1rem; padding: 1.5rem 1rem 1rem; text-align: center; border-radius: 0.5rem; .filter-title { text-transform: uppercase; color: var(--font-color2); font-size: 1.3rem; } &.small-filter { max-width: 20rem; } } .language-filter { background: url(${languageSVG}) #1d1d1d no-repeat -35% -25%; ul { text-align: left; list-style: none; padding: 0; color: var(--font-color2); } } .player-filter { background: url(${playerSVG}) #1d1d1d no-repeat -35% -25%; } .duration-filter { background: url(${clockSVG}) #1d1d1d no-repeat -40% -40%; } `; const StyledGameResultNumber = styled.p` text-align: center; `; const Content = styled.div` background-color: var(--bg-secondary-color); `; const hasIntervalOverlap = (interval1, interval2) => { return interval1[0] <= interval2[1] && interval1[1] >= interval2[0]; }; const hasRequestedValues = (filterValue, gameSettings) => { if (!filterValue?.length || !gameSettings?.length) { return true; } return hasIntervalOverlap(filterValue, gameSettings); }; const hasAllowedMaterialLanguage = (filterCriteria, game) => { const MULTI_LANG_KEYWORD = "Multi-lang"; return ( !game.materialLanguage || game.materialLanguage === MULTI_LANG_KEYWORD || filterCriteria.languages.includes(game.materialLanguage) ); }; const GameListView = () => { const { t } = useTranslation(); const NULL_SEARCH_TERM = ""; const [filterCriteria, setFilterCriteria] = React.useState({ searchTerm: NULL_SEARCH_TERM, nbOfPlayers: [1, 9], durations: [15, 90], languages: ["fr", "en"], }); const { isLoading, data: gameList } = useQuery("games", async () => (await getGames()) .filter((game) => game.published) .sort((a, b) => { const [nameA, nameB] = [ a.board.defaultName || a.board.name, b.board.defaultName || b.board.name, ]; if (nameA < nameB) { return -1; } if (nameA > nameB) { return 1; } return 0; }) ); const filteredGameList = React.useMemo(() => { if (gameList) { return gameList.filter( (game) => (filterCriteria.searchTerm === NULL_SEARCH_TERM || search(filterCriteria.searchTerm, game.defaultName)) && hasRequestedValues(filterCriteria.nbOfPlayers, game.playerCount) && hasRequestedValues(filterCriteria.durations, game.duration) && hasAllowedMaterialLanguage(filterCriteria, game) ); } return []; }, [gameList, filterCriteria]); const onChangeNbOfPlayersSlider = (values) => { setFilterCriteria({ ...filterCriteria, nbOfPlayers: values, }); }; const onChangeDurationSlider = (values) => { setFilterCriteria({ ...filterCriteria, durations: values, }); }; const onChangeSearchTerm = (event) => { setFilterCriteria({ ...filterCriteria, searchTerm: event.target.value, }); }; const toggleLang = (lang) => { if (filterCriteria.languages.includes(lang)) { return filterCriteria.languages.filter((language) => language !== lang); } else { return [...filterCriteria.languages, lang]; } }; const onChangelanguageFilter = (lang) => { setFilterCriteria({ ...filterCriteria, languages: toggleLang(lang), }); }; return ( <>

Play board games online
with your friends - for free!

Choose from our selection or create your own.
No need to sign up. Just start a game and share the link with your friends.

{t("Start a game now")}

{t("Or")}{" "} {t("start a multi room session")}

  • {t("Number of players")}
  • {t("Duration (mins)")}
  • {t("Language")}
    • onChangelanguageFilter("fr")} />
    • onChangelanguageFilter("en")} data-lang="en" />
  • {t("games-available", { nbOfGames: `${filteredGameList.length}` })}
    {!isLoading && ( {filteredGameList.map((game) => ( ))} )} {isLoading && (
    )}
    ); }; export default GameListView;