diff options
author | lonkaars <l.leblansch@gmail.com> | 2021-04-21 16:08:35 +0200 |
---|---|---|
committer | lonkaars <l.leblansch@gmail.com> | 2021-04-21 16:08:35 +0200 |
commit | da2fba59ddaee800eceee984198da0228fcb5b80 (patch) | |
tree | 41cd7664e8c9b3e6db8cab8c33d46157b7ec3999 | |
parent | 4254f328f9e85fcb838815bbee1ccedbcb41daf4 (diff) |
added search in new game dialog (not finished)
-rw-r--r-- | components/ui.tsx | 17 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | pages/game.tsx | 47 | ||||
-rw-r--r-- | styles/game.css | 20 | ||||
-rw-r--r-- | yarn.lock | 5 |
5 files changed, 86 insertions, 4 deletions
diff --git a/components/ui.tsx b/components/ui.tsx index 7474240..1e9997a 100644 --- a/components/ui.tsx +++ b/components/ui.tsx @@ -1,4 +1,5 @@ import { ReactNode, useEffect, useState } from 'react'; +import { v4 as uuid } from 'uuid'; import CheckBoxIcon from '@material-ui/icons/CheckBox'; import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; @@ -79,6 +80,7 @@ export function Input(props: { autocomplete?: string; autofocus?: boolean; className?: string; + onChange?: () => void; }) { return <input id={props.id} @@ -91,16 +93,25 @@ export function Input(props: { className={'input' + ' ' + (props.dark ? 'dark' : 'light') + ' ' + props.className} autoComplete={props.autocomplete} autoFocus={props.autofocus} + onChange={props.onChange} />; } -export function SearchBar(props: { label?: string; }) { - return <div className='searchBar round-t fullwidth'> +export function SearchBar(props: { + label?: string; + search?: (query: string) => void; +}) { + var id = uuid(); + + var getQuery = () => (document.getElementById(id).children[0] as HTMLInputElement).value; + + return <div className='searchBar round-t fullwidth' id={id}> <Input label={props.label} className='pad-m bg-700' + onChange={() => props.search && props.search(getQuery())} /> - <Button className='dispinbl valigntop'> + <Button className='dispinbl valigntop' onclick={() => props.search && props.search(getQuery())}> <SearchIcon className='icon' /> </Button> </div>; diff --git a/package.json b/package.json index 75fa8b1..d0e01e0 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "copy-to-clipboard": "^3.3.1", "email-validator": "^2.0.4", "friendly-time": "^1.1.1", + "fuse.js": "^6.4.6", "image-blob-reduce": "^2.2.2", "micromark": "^2.11.4", "next": "^10.0.5", diff --git a/pages/game.tsx b/pages/game.tsx index de2c089..f6c6f5b 100644 --- a/pages/game.tsx +++ b/pages/game.tsx @@ -1,11 +1,13 @@ import Icon from '@mdi/react'; import axios from 'axios'; import copy from 'copy-to-clipboard'; +import Fuse from 'fuse.js'; import { useContext, useEffect, useState } from 'react'; import * as cookies from 'react-cookies'; import { Socket } from 'socket.io-client'; import { SocketContext } from '../components/socketContext'; +import { userInfo } from '../api/api'; import { DialogBox } from '../components/dialogBox'; import { GameBar } from '../components/gameBar'; import { CurrentGameSettings } from '../components/gameSettings'; @@ -15,11 +17,13 @@ import { ToastContext, toastType } from '../components/toast'; import { Button, IconLabelButton, SearchBar } from '../components/ui'; import { VoerBord } from '../components/voerBord'; +import AddIcon from '@material-ui/icons/Add'; import FlagOutlinedIcon from '@material-ui/icons/FlagOutlined'; import LinkRoundedIcon from '@material-ui/icons/LinkRounded'; import RefreshIcon from '@material-ui/icons/Refresh'; import WifiTetheringRoundedIcon from '@material-ui/icons/WifiTetheringRounded'; import { mdiContentCopy } from '@mdi/js'; +import { AccountAvatar } from '../components/account'; function VoerGame(props: { gameID: string; @@ -139,11 +143,28 @@ function GameOutcomeDialog(props: { </DialogBox>; } +function InviteableFriend(props: { user?: userInfo; }) { + return <div className='round-t bg-700 inviteableFriend drop-1 posrel'> + <AccountAvatar size={44} id={props.user?.id} /> + <span className='username nosel posabs abscenterv pad-m'>{props.user?.username}</span> + <Button className='floatr dispinbl' children={<AddIcon />} /> + </div>; +} + export default function GamePage() { var [gameID, setGameID] = useState(''); var [player1, setPlayer1] = useState(true); var [active, setActive] = useState(false); var [gameIDUrl, setGameIDUrl] = useState(''); + var [friendList, setFriendList] = useState<userInfo[]>([]); + + var [query, setQuery] = useState(''); + var [visibleFriends, setVisibleFriends] = useState<userInfo[]>([]); + + var fuse = new Fuse(friendList, { + keys: ['username'], + isCaseSensitive: false, + }); var { io } = useContext(SocketContext); var { toast } = useContext(ToastContext); @@ -174,6 +195,27 @@ export default function GamePage() { }, []); useEffect(() => { + axios.request<{ friends: Array<userInfo>; }>({ + method: 'get', + url: '/api/social/list/friends', + }) + .then(response => { + console.log(response.data.friends); + setFriendList(response.data.friends); + }) + .catch(err => { + toast({ message: 'error', type: 'error', description: err.toString() }); + }); + }, []); + + useEffect(() => { + var fuseSearch = fuse.search(query); + var results = fuseSearch.map(res => res.item).slice(0, 5); + + setVisibleFriends(results); + }, [query]); + + useEffect(() => { io.on('gameStart', () => setActive(true)); }, []); @@ -246,7 +288,10 @@ export default function GamePage() { <h2 className='label center posabs abscenterh nosel'>Uitnodigen via link</h2> </Button> </div> - <SearchBar label='Zoeken in vriendenlijst' /> + <div className='inviteFromFriendsList'> + <SearchBar label='Zoeken in vriendenlijst' search={q => setQuery(q)} /> + {visibleFriends.map(user => <InviteableFriend user={user} />)} + </div> </DialogBox> </CenteredPage> </div>; diff --git a/styles/game.css b/styles/game.css index d482f9b..5954991 100644 --- a/styles/game.css +++ b/styles/game.css @@ -74,3 +74,23 @@ html.dark .newGameDialog .inviteButton.random .icon { color: var(--confirm); } html.dark .newGameDialog .inviteButton.link .icon { color: var(--error); } html.dark .newGameDialog .searchBar .input { background-color: var(--gray-800); } +.inviteFromFriendsList { + overflow-y: visible; + height: 44px; +} + +html.dark .inviteFromFriendsList .inviteableFriend { + background-color: var(--gray-800); +} +.inviteFromFriendsList .inviteableFriend { + margin-top: var(--spacing-small); + overflow: hidden; + cursor: pointer; +} + +.inviteFromFriendsList .inviteableFriend .button { + background-color: transparent; + color: var(--foreground); + padding: 10px; +} + @@ -5922,6 +5922,11 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +fuse.js@^6.4.6: + version "6.4.6" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-6.4.6.tgz#62f216c110e5aa22486aff20be7896d19a059b79" + integrity sha512-/gYxR/0VpXmWSfZOIPS3rWwU8SHgsRTwWuXhyb2O6s7aRuVtHtxCkR33bNYu3wyLyNx/Wpv0vU7FZy8Vj53VNw== + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" |