Created "sign-up" form

This commit is contained in:
martin 2023-07-02 17:59:39 +02:00
parent d6a49dee6a
commit dd21f82734
12 changed files with 155 additions and 21 deletions

View File

@ -0,0 +1,24 @@
import React, {forwardRef, ReactEventHandler} from "react";
export interface DropdownProps extends ComponentProps {
options?: string[],
onSelect?: ReactEventHandler<HTMLSelectElement>,
}
const Dropdown: FRComponent<DropdownProps, HTMLSelectElement> = forwardRef((
{
className,
options,
onSelect
}, ref) => (
<select ref={ref} className={"border-2 border-gray-300 rounded-md py-1 px-2 bg-white " + className}
onSelect={onSelect}>
{
options?.map((option, index) => (
<option key={index}>{option}</option>
))
}
</select>
));
export default Dropdown;

View File

@ -7,12 +7,13 @@ import WebSocketService from "../websockets/WebSocketService";
import {testMap} from "../game/map";
import {TileType} from "../game/tileType";
import Player, {State} from "../game/player";
import {Colour} from "../game/colour";
const wsService = new WebSocketService(import.meta.env.VITE_API);
const ghosts = [
new Ghost({Colour: "purple"}),
new Ghost({Colour: "purple"})
new Ghost({Colour: Colour.Purple}),
new Ghost({Colour: Colour.Purple}),
];
export const GameComponent: Component<{ player: Player }> = (
@ -65,6 +66,14 @@ export const GameComponent: Component<{ player: Player }> = (
// TODO find spawn points
setCharacters([...pacMen, ...ghosts]);
break;
case GameAction.ready:
const isReady = parsed.Data.AllReady as boolean;
if (isReady) {
setCurrentPlayer(parsed.Data.Starter as Player);
} else {
// TODO update player states
}
break;
}
}
@ -124,8 +133,7 @@ export const GameComponent: Component<{ player: Player }> = (
}
return (
<div>
<h1 className={"w-fit mx-auto"}>Pac-Man The Board Game</h1>
<>
<div className={"flex-center"}>
{
player.State === State.waitingForPlayers ?
@ -136,6 +144,7 @@ export const GameComponent: Component<{ player: Player }> = (
<AllDice values={dice} onclick={handleDiceClick} selectedDiceIndex={selectedDice?.index}/>
{
(characters?.filter(c => c.isPacMan()) as PacMan[] | undefined)?.map(c =>
/*TODO use PlayerStats instead*/
<div key={c.Colour} className={"mx-auto w-fit m-2"}>
<p className={currentPlayer === player ? "underline" : ""}>Player: {player.Colour}</p>
<p>Pellets: {player.Box.count}</p>
@ -148,6 +157,6 @@ export const GameComponent: Component<{ player: Player }> = (
selectedDice={selectedDice}
onMove={onCharacterMove} map={testMap}/>
}
</div>
</>
);
};

View File

@ -0,0 +1,19 @@
import React, {forwardRef} from "react";
const Input: FRComponent<InputProps, HTMLInputElement> = forwardRef((
{
type = "text",
className,
id,
placeholder,
required = false,
}, ref) => (
<input type={type}
ref={ref}
id={id}
className={"border-2 border-gray-300 rounded-md p-1 " + className}
placeholder={placeholder}
required={required}/>
));
export default Input;

View File

@ -1,4 +1,5 @@
import Pellet from "./pellet";
import {Colour} from "./colour";
export default class Box {
public Pellets: Pellet[];

View File

@ -1,4 +1,5 @@
import {Direction} from "./direction";
import {Colour} from "./colour";
export enum CharacterType {
pacMan,
@ -79,7 +80,7 @@ export class Dummy extends Character {
public constructor(position: Path) { // TODO see-through
super({
Colour: "grey",
Colour: Colour.Grey,
Position: position,
IsEatable: false,
SpawnPosition: {At: {x: 0, y: 0}, Direction: Direction.up},

View File

@ -0,0 +1,11 @@
export enum Colour {
White = "white",
Red = "red",
Blue = "blue",
Yellow = "yellow",
Green = "green",
Purple = "purple",
Grey = "grey",
}
export const getColours = (): Colour[] => Object.values(Colour);

View File

@ -1,5 +1,6 @@
import {Character, CharacterType} from "./character";
import Box from "./box";
import {Colour} from "./colour";
export enum State {
waitingForPlayers,

View File

@ -0,0 +1,28 @@
import React from "react";
import Player, {State} from "./player";
export interface PlayerStatsProps extends ComponentProps {
player: Player,
isCurrentPlayer?: boolean,
}
const PlayerStats: Component<PlayerStatsProps> = (
{
player,
isCurrentPlayer = false,
className,
id
}) => (
<div key={player.Colour} className={`mx-auto w-fit m-2 ${className}`} id={id}>
<p className={isCurrentPlayer ? "underline" : ""}>Player: {player.Name}</p>
{player.State === State.inGame ?
<>
<p>Pellets: {player.Box.count}</p>
<p>PowerPellets: {player.Box.countPowerPellets}</p>
</> :
<p>{player.State === State.waitingForPlayers ? "Waiting" : "Ready"}</p>}
</div>
);
export default PlayerStats;

View File

@ -19,6 +19,10 @@ h1 {
@apply text-4xl;
}
button {
br {
@apply my-2;
}
button, button[type=submit], input[type=button], input[type=submit] {
@apply bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded;
}

View File

@ -1,14 +1,44 @@
import React from "react";
import React, {FormEvent, useRef, useState} from "react";
import {GameComponent} from "../components/gameComponent";
import Player from "../game/player";
import Input from "../components/input";
import Dropdown from "../components/dropdown";
import {Colour, getColours} from "../game/colour";
const Home: Component = () => (
<div>
<GameComponent player={new Player({
Name: "Martin",
Colour: "yellow",
})}/>
</div>
);
const Home: Component = () => {
const [player, setPlayer] = useState<Player>();
const input = useRef<HTMLInputElement>(null);
const dropdown = useRef<HTMLSelectElement>(null);
function formHandler(e: FormEvent): void {
e.preventDefault();
if (!input.current || !dropdown.current) return;
setPlayer(new Player({
Name: input.current.value,
Colour: dropdown.current.value as Colour,
}));
}
return (
<>
<h1 className={"w-fit mx-auto"}>Pac-Man The Board Game</h1>
{
player ?
/*TODO move to own page*/
<GameComponent player={player}/>
:
<form className={"flex flex-col items-center"} onSubmit={formHandler}>
<p>Enter your name:</p>
<Input ref={input} required/>
<p>Choose a colour:</p>
<Dropdown ref={dropdown} options={getColours()}/>
<br/>
<button type={"submit"}>Find game</button>
</form>
}
</>
);
};
export default Home;

View File

@ -1,5 +1,7 @@
type Component<T = ComponentProps> = (props: T) => React.JSX.Element | null;
type FRComponent<T = ComponentProps, HTML extends HTMLElement = HTMLElement> = React.ForwardRefExoticComponent<React.PropsWithoutRef<T> & React.RefAttributes<HTML>>;
interface ComponentProps {
className?: string,
style?: React.CSSProperties,
@ -11,8 +13,14 @@ interface ChildProps extends ComponentProps {
children?: React.JSX.Element,
}
interface InputProps extends ComponentProps {
type?: string,
placeholder?: string,
required?: boolean,
}
interface CharacterProps {
Colour: Colour,
Colour: import("../game/colour").Colour,
Position?: Path | null,
IsEatable?: boolean,
SpawnPosition?: DirectionalPosition | null,
@ -21,13 +29,13 @@ interface CharacterProps {
interface BoxProps {
pellets?: import("../game/pellet").default[],
readonly colour: Colour,
readonly colour: import("../game/colour").Colour,
}
interface PlayerProps {
readonly Name: string,
readonly PacMan?: CharacterProps,
readonly Colour: Colour,
readonly Colour: import("../game/colour").Colour,
readonly Box?: BoxProps,
State?: import("../game/player").State,
}

View File

@ -34,5 +34,3 @@ type Path = {
End: Position,
Direction: import("../game/direction").Direction
}
type Colour = "white" | "red" | "blue" | "yellow" | "green" | "purple" | "grey";