Skip to content

Commit

Permalink
new login form store
Browse files Browse the repository at this point in the history
  • Loading branch information
naueramant committed Aug 16, 2023
1 parent 7557859 commit e6147b2
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 44 deletions.
31 changes: 12 additions & 19 deletions src/views/Login/New/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import ShuffleDialog from "./components/ShuffleDialog";
import { Player } from "../../../models/player";
import Conditional from "../../../components/Conditional";
import TimeAttackSettings from "../components/TimeAttackSettings";
import useNewGameForm from "./stores/new";

const MIN_PLAYERS = 2;
const MAX_PLAYERS = 6;
Expand All @@ -32,16 +33,13 @@ const NewGameView: FunctionComponent = () => {
const theme = useTheme();
const { play, stopAll } = useSounds();

const [numberOfPlayers, setNumberOfPlayers] = useState(4);
const [gameMode, setGameMode] = useState<GameMode>("normal");

const StartGame = useGame((state) => state.Start);

const [players, setPlayers] = useState<Player[]>([]);
const form = useNewGameForm();

const startGame = () => {
StartGame(players, {
offline: gameMode === "offline",
StartGame(form.players, {
offline: form.gameMode === "offline",
numberOfRounds: 13,
sipsInABeer: 14,
});
Expand All @@ -51,12 +49,12 @@ const NewGameView: FunctionComponent = () => {
};

const changeGameMode = (mode: GameMode) => {
setPlayers([]);
form.SetGameMode(mode);
play("click");
};

const changeNumberOfPlayers = (value: number) => {
setNumberOfPlayers(value);
form.SetNumberOfPlayers(value);
play("click");
};

Expand Down Expand Up @@ -113,13 +111,9 @@ const NewGameView: FunctionComponent = () => {
</Tooltip>

<GameModeSelector
value={gameMode}
value={form.gameMode}
onChange={changeGameMode}
/>

<Conditional value={gameMode === "time-attack"}>
<TimeAttackSettings />
</Conditional>
</Stack>

<Stack spacing={1}>
Expand All @@ -128,7 +122,7 @@ const NewGameView: FunctionComponent = () => {
<NumberOfPlayersSelector
min={MIN_PLAYERS}
max={MAX_PLAYERS}
value={numberOfPlayers}
value={form.numberOfPlayers}
onChange={changeNumberOfPlayers}
/>
</Stack>
Expand All @@ -137,13 +131,12 @@ const NewGameView: FunctionComponent = () => {

<Stack spacing={1}>
<Typography variant="body1" sx={{}}>
{gameMode === "offline" ? "Players" : "Player login"}
{form.gameMode === "offline" ? "Players" : "Player login"}
</Typography>

<PlayerList
numberOfPlayers={numberOfPlayers}
usernameOnly={gameMode === "offline"}
onChange={(players) => setPlayers(players)}
numberOfPlayers={form.numberOfPlayers}
usernameOnly={form.gameMode === "offline"}
/>
</Stack>
<Divider />
Expand All @@ -154,7 +147,7 @@ const NewGameView: FunctionComponent = () => {
size="large"
onClick={startGame}
endIcon={<IoPlay size={24} />}
disabled={players.length !== numberOfPlayers}
disabled={!form.ready}
>
Start game
</Button>
Expand Down
90 changes: 90 additions & 0 deletions src/views/Login/New/stores/new.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import create from "zustand";
import { Player } from "../../../../models/player";
import { GameMode } from "../../components/GameModeSelector";

interface NewGameState {
ready: boolean;
numberOfPlayers: number;
gameMode: GameMode;
players: Player[];
playerReady: boolean[];
}

interface NewGameAction {
SetNumberOfPlayers: (value: number) => void;
SetGameMode: (value: GameMode) => void;
SetPlayer(index: number, player: Player): void;
RemovePlayer(index: number): void;
SetPlayerReady(index: number, ready: boolean): void;
}

const initialState: NewGameState = {
ready: false,
numberOfPlayers: 4,
gameMode: "normal",
players: [],
playerReady: [],
};

const useNewGameForm = create<NewGameState & NewGameAction>()(
(set, get) => ({
...initialState,

SetNumberOfPlayers: (value: number) => {
const { players, playerReady } = get();

set((state) => ({ numberOfPlayers: value }));

if (value < players.length) {
set((state) => ({ players: players.slice(0, value) }));
set((state) => ({ playerReady: playerReady.slice(0, value) }));
} else {
set((state) => ({
players: [
...players,
...Array(value - players.length).fill({
name: "",
}),
],
}));
set((state) => ({
playerReady: [
...playerReady,
...Array(value - playerReady.length).fill(false),
],
}));
}
},

SetGameMode: (value: GameMode) => {
set((state) => ({ gameMode: value }));
},

SetPlayer: (index: number, player: Player) => {
set((state) => {
const players = [...state.players];
players[index] = player;
return { players };
});
},

RemovePlayer: (index: number) => {
set((state) => {
const players = [...state.players];
players.splice(index, 1);
return { players };
});
},

SetPlayerReady: (index: number, ready: boolean) => {
set((state) => {
const playerReady = [...state.playerReady];
playerReady[index] = ready;

return { playerReady, ready: playerReady.every((ready) => ready) };
});
},
})
);

export default useNewGameForm;
40 changes: 17 additions & 23 deletions src/views/Login/components/PlayerItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import {
TextField,
useTheme,
} from "@mui/material";
import { FunctionComponent, useState } from "react";
import { FunctionComponent, useEffect, useState } from "react";
import { ImCross } from "react-icons/im";
import * as AuthAPI from "../../../api/endpoints/authentication";
import { useSounds } from "../../../hooks/sounds";
import { Player } from "../../../models/player";

interface PlayerItemProps {
hidePassword?: boolean;
onLogin?: (player: Player) => void;
onReady?: (player: Player) => void;
onRemove?: () => void;
}

Expand All @@ -24,32 +24,29 @@ const PlayerItem: FunctionComponent<PlayerItemProps> = (props) => {

const [image, setImage] = useState<string | null>(null);
const [locked, setLocked] = useState(false);
const [ready, setReady] = useState(false);

const [username, setUsername] = useState(""); // TODO: remove
const [password, setPassword] = useState("");
const [username, setUsername] = useState("player1"); // TODO: remove
const [password, setPassword] = useState("test");

const login = async () => {
if (props.hidePassword) {
if (username === "") {
props.onRemove?.();

return;
}

props.onLogin?.({
useEffect(() => {
if (props.hidePassword && username.length > 0) {
setReady(true);
props.onReady?.({
username: username,
});

return;
}
}, [username, password, props.hidePassword]);

setLocked(true);

const login = async () => {
try {
setLocked(true);

const resp = await AuthAPI.login(username, password);
setImage(resp.image);
setReady(true);

props.onLogin?.({
props.onReady?.({
username: username,
id: resp.id,
token: resp.token,
Expand All @@ -69,6 +66,8 @@ const PlayerItem: FunctionComponent<PlayerItemProps> = (props) => {
setPassword("");
setImage(null);
setLocked(false);
setReady(false);

props.onRemove?.();
};

Expand Down Expand Up @@ -107,11 +106,6 @@ const PlayerItem: FunctionComponent<PlayerItemProps> = (props) => {
login();
}
}}
onBlur={() => {
if (props.hidePassword) {
login();
}
}}
/>

{!props.hidePassword && (
Expand Down
4 changes: 2 additions & 2 deletions src/views/Login/components/PlayerList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import PlayerItem from "./PlayerItem";
interface PlayerListProps {
numberOfPlayers: number;
usernameOnly?: boolean;
onChange?: (players: Player[]) => void;
onPlayerReadyChange?: (index: number, players: Player) => void;
}

const PlayerList: FunctionComponent<PlayerListProps> = (props) => {
Expand Down Expand Up @@ -38,7 +38,7 @@ const PlayerList: FunctionComponent<PlayerListProps> = (props) => {
<PlayerItem
key={i}
hidePassword={props.usernameOnly}
onLogin={(p) => {
onReady={(p) => {
setPlayers((prev) => {
const newPlayers = { ...prev };
newPlayers[i] = p;
Expand Down

0 comments on commit e6147b2

Please sign in to comment.