Merge remote-tracking branch 'refs/remotes/origin/player-join'

This commit is contained in:
Vinzenz Schroeter 2024-04-13 17:57:46 +02:00
commit 698271ae9f
7 changed files with 136 additions and 45 deletions

View file

@ -4,7 +4,7 @@
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite --host 0.0.0.0 --port 8543",
"build": "tsc && vite build", "build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview" "preview": "vite preview"

View file

@ -1,4 +1,16 @@
.TankWelcome {
display: flex;
flex-direction: column;
}
.JoinForm { .JoinForm {
display: flex; display: flex;
flex-direction: row; flex-direction: column;
border: 2px solid rgb(76, 76, 76);
border-radius: 4px;
}
.JoinElems {
padding: 8px 8px;
margin: 8px 8px;
} }

View file

@ -1,24 +1,8 @@
import {useEffect, useState} from 'react'; import { useEffect, useState } from 'react';
import './JoinForm.css'; import './JoinForm.css';
import { PlayerResponse, postPlayer } from './serverCalls';
type PlayerResponse = { export default function JoinForm({ onDone }: { onDone: (id: string) => void }) {
readonly name: string;
readonly id: string;
};
export async function fetchPlayer(name: string, options: RequestInit) {
const url = new URL(import.meta.env.VITE_TANK_PLAYER_URL);
url.searchParams.set('name', name);
const response = await fetch(url, options);
if (!response.ok)
return null;
const json = await response.json() as PlayerResponse;
return json.id;
}
export default function JoinForm({onDone}: { onDone: (id: string) => void }) {
const [name, setName] = useState(''); const [name, setName] = useState('');
const [clicked, setClicked] = useState(false); const [clicked, setClicked] = useState(false);
const [data, setData] = useState<PlayerResponse | null>(null); const [data, setData] = useState<PlayerResponse | null>(null);
@ -28,9 +12,10 @@ export default function JoinForm({onDone}: { onDone: (id: string) => void }) {
return; return;
try { try {
fetchPlayer(name, {}).then((value: string | null) => { postPlayer(name)
.then((value: PlayerResponse | null) => {
if (value) if (value)
onDone(value); onDone(value.id);
else else
setClicked(false); setClicked(false);
}); });
@ -41,17 +26,27 @@ export default function JoinForm({onDone}: { onDone: (id: string) => void }) {
}, [clicked, setData, data]); }, [clicked, setData, data]);
const disableButtons = clicked || name.trim() === ''; const disableButtons = clicked || name.trim() === '';
return <div className="JoinForm"> return <div className='TankWelcome'>
<input <h1 className='JoinElems' style={{ "color": "white" }}>
Tanks
</h1>
<p className='JoinElems' style={{ "color": "white" }}> Welcome and have fun!</p>
<div className="JoinForm">
<p className='JoinElems' style={{ "color": "white" }}>
Enter your name to join the game!
</p>
<input className="JoinElems"
type="text" type="text"
value={name} value={name}
placeholder='player name'
onChange={e => setName(e.target.value)} onChange={e => setName(e.target.value)}
/> />
<button <button className="JoinElems"
onClick={() => setClicked(true)} onClick={() => setClicked(true)}
disabled={disableButtons} disabled={disableButtons}
> >
join join
</button> </button>
</div>
</div>; </div>;
} }

View file

@ -0,0 +1,21 @@
.Player {
display: flex;
flex-direction: column;
border: 2px solid rgb(76, 76, 76);
border-radius: 4px;
}
.ScoreForm {
display: flex;
flex-direction: column;
}
.ElemGroup {
display: flex;
flex-direction: row;
}
.Elems {
padding: 8px 8px;
margin: 8px 8px;
}

View file

@ -0,0 +1,38 @@
import { useEffect, useState } from 'react';
import './PlayerInfo.css'
import { PlayerResponse, getPlayer } from './serverCalls';
export default function PlayerInfo({ playerId }: { playerId: string }) {
const [player, setPlayer] = useState<PlayerResponse | null>();
const refresh = () => {
getPlayer(playerId).then(setPlayer);
};
useEffect(() => {
const timer = setInterval(refresh, 5000);
return () => clearInterval(timer);
});
return <div className='TankWelcome'>
<h1 className='Elems' style={{ "color": "white" }}>
Tanks
</h1>
<div className="ScoreForm">
<div className='ElemGroup'>
<p className='Elems' style={{ "color": "white" }}>
name
</p>
<p className='Elems' style={{ "color": "white" }}>
{player?.name}
</p>
</div>
<div className='ElemGroup'></div>
<p className='Elems' style={{ "color": "white" }}>
{JSON.stringify(player)}
</p>
</div>
</div >;
}

View file

@ -1,22 +1,24 @@
import React, {useState} from 'react'; import React, { useState } from 'react';
import './index.css'; import './index.css';
import ClientScreen from './ClientScreen'; import ClientScreen from './ClientScreen';
import Controls from './Controls.tsx'; import Controls from './Controls.tsx';
import JoinForm from './JoinForm.tsx'; import JoinForm from './JoinForm.tsx';
import {createRoot} from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import PlayerInfo from './PlayerInfo.tsx';
function App() { function App() {
const [id, setId] = useState<string | null>(null); const [id, setId] = useState<string | null>(null);
return <> return <>
{id === null && <JoinForm onDone={name => setId(name)}/>} {id === null && <JoinForm onDone={name => setId(name)} />}
<ClientScreen/> {id == null || <PlayerInfo playerId={id} />}
{id == null || <Controls playerId={id}/>} <ClientScreen />
{id == null || <Controls playerId={id} />}
</>; </>;
} }
createRoot(document.getElementById('root')!).render( createRoot(document.getElementById('root')!).render(
<React.StrictMode> <React.StrictMode>
<App/> <App />
</React.StrictMode> </React.StrictMode>
); );

View file

@ -0,0 +1,23 @@
export type PlayerResponse = {
readonly name: string;
readonly id: string;
};
export async function fetchTyped<T>({ url, method }: { url: URL; method: string; }) {
const response = await fetch(url, { method });
if (!response.ok)
return null;
return await response.json() as T;
}
export function postPlayer(name: string) {
const url = new URL(import.meta.env.VITE_TANK_PLAYER_URL);
url.searchParams.set('name', name);
return fetchTyped<PlayerResponse>({ url, method: 'POST' });
}
export function getPlayer(id: string) {
const url = new URL(import.meta.env.VITE_TANK_PLAYER_URL);
url.searchParams.set('id', id);
return fetchTyped<PlayerResponse>({ url, method: 'GET' });
}