diff --git a/front/Fetcher.ts b/front/Fetcher.ts new file mode 100644 index 0000000..59b15c8 --- /dev/null +++ b/front/Fetcher.ts @@ -0,0 +1,13 @@ +import {API} from "./Constants"; + + +export function fetchAPI(url: string, payload: object, method = "POST"): Promise { + return fetch(`${API}/${url}`, { + method, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }) +} diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx index 9f4cb5d..7eab38c 100644 --- a/front/components/editor/BasketCourt.tsx +++ b/front/components/editor/BasketCourt.tsx @@ -1,26 +1,27 @@ -import CourtSvg from "../../assets/basketball_court.svg?react" -import "../../style/basket_court.css" -import { useRef } from "react" -import CourtPlayer from "./CourtPlayer" -import { Player } from "../../data/Player" +import CourtSvg from '../../assets/basketball_court.svg?react'; +import '../../style/basket_court.css'; +import {useRef} from "react"; +import CourtPlayer from "./CourtPlayer"; +import {Player} from "../../tactic/Player"; export interface BasketCourtProps { - players: Player[] - onPlayerRemove: (p: Player) => void + players: Player[], + onPlayerRemove: (p: Player) => void, + onPlayerChange: (p: Player) => void } -export function BasketCourt({ players, onPlayerRemove }: BasketCourtProps) { +export function BasketCourt({players, onPlayerRemove, onPlayerChange}: BasketCourtProps) { + const divRef = useRef(null); + return ( -
- - {players.map((player) => { - return ( - onPlayerRemove(player)} - /> - ) +
+ + {players.map(player => { + return onPlayerRemove(player)} + /> })}
) diff --git a/front/components/editor/CourtPlayer.tsx b/front/components/editor/CourtPlayer.tsx index 9b08e7b..b8ff341 100644 --- a/front/components/editor/CourtPlayer.tsx +++ b/front/components/editor/CourtPlayer.tsx @@ -1,40 +1,52 @@ -import { useRef } from "react" -import "../../style/player.css" -import RemoveIcon from "../../assets/icon/remove.svg?react" -import Draggable from "react-draggable" -import { PlayerPiece } from "./PlayerPiece" -import { Player } from "../../data/Player" + +import {useRef} from "react"; +import "../../style/player.css"; +import RemoveIcon from "../../assets/icon/remove.svg?react"; +import Draggable from "react-draggable"; +import {PlayerPiece} from "./PlayerPiece"; +import {Player} from "../../tactic/Player"; export interface PlayerProps { - player: Player + player: Player, + onChange: (p: Player) => void, onRemove: () => void } /** * A player that is placed on the court, which can be selected, and moved in the associated bounds * */ -export default function CourtPlayer({ player, onRemove }: PlayerProps) { - const ref = useRef(null) + +export default function CourtPlayer({player, onChange, onRemove}: PlayerProps) { const x = player.rightRatio const y = player.bottomRatio return ( - -
-
{ - if (e.key == "Delete") onRemove() - }}> + onChange({ + id: player.id, + rightRatio: player.rightRatio, + bottomRatio: player.bottomRatio, + team: player.team, + role: player.role + })} + > +
+ +
{ + if (e.key == "Delete") + onRemove() + }}>
Promise, + onNameChange: (name: string) => Promise +} + /** * information about a player that is into a rack */ @@ -21,8 +29,21 @@ interface RackedPlayer { key: string } -export default function Editor({ id, name }: { id: number; name: string }) { - const [style, setStyle] = useState({}) +export default function Editor({tactic}: { tactic: Tactic }) { + return ( + fetchAPI(`tactic/${tactic.id}/save`, {content}) + .then((r) => r.ok) + )} + onNameChange={(name: string) => ( + fetchAPI(`tactic/${tactic.id}/edit/name`, {name}) + .then((r) => r.ok) + )}/> +} + +function EditorView({tactic: {name, content}, onContentChange, onNameChange}: EditorViewProps) { + const [style, setStyle] = useState({}); + const positions = ["1", "2", "3", "4", "5"] const [allies, setAllies] = useState( positions.map((key) => ({ team: Team.Allies, key })), @@ -31,8 +52,17 @@ export default function Editor({ id, name }: { id: number; name: string }) { positions.map((key) => ({ team: Team.Opponents, key })), ) - const [players, setPlayers] = useState([]) - const courtDivContentRef = useRef(null) + + const [players, setPlayers] = useState(content.players); + const courtDivContentRef = useRef(null); + + useEffect(() => { + onContentChange({players}) + .then(success => { + if (!success) + alert("error when saving changes.") + }) + }, [players]) const canDetach = (ref: HTMLDivElement) => { const refBounds = ref.getBoundingClientRect() @@ -75,28 +105,15 @@ export default function Editor({ id, name }: { id: number; name: string }) {
LEFT
- { - fetch(`${API}/tactic/${id}/edit/name`, { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/json", - }, - body: JSON.stringify({ - name: new_name, - }), - }).then((response) => { - if (response.ok) { - setStyle({}) - } else { - setStyle(ERROR_STYLE) - } - }) - }} - /> + { + onNameChange(new_name).then(success => { + if (success) { + setStyle({}) + } else { + setStyle(ERROR_STYLE) + } + }) + }}/>
RIGHT
@@ -126,6 +143,12 @@ export default function Editor({ id, name }: { id: number; name: string }) {
{ + setPlayers(players => { + const idx = players.indexOf(player) + return players.toSpliced(idx, 1, player) + }) + }} onPlayerRemove={(player) => { setPlayers((players) => { const idx = players.indexOf(player) diff --git a/public/api/index.php b/public/api/index.php index 6f46638..1033362 100644 --- a/public/api/index.php +++ b/public/api/index.php @@ -29,8 +29,9 @@ function getRoutes(): AltoRouter { $router = new AltoRouter(); $router->setBasePath(get_public_path() . "/api"); - $router->map("POST", "/tactic/[i:id]/edit/name", Action::auth(fn(int $id, Account $acc) => getTacticController()->updateName($id, $acc))); $router->map("POST", "/auth", Action::noAuth(fn() => getAuthController()->authorize())); + $router->map("POST", "/tactic/[i:id]/edit/name", Action::auth(fn(int $id, Account $acc) => getTacticController()->updateName($id, $acc))); + $router->map("POST", "/tactic/[i:id]/save", Action::auth(fn(int $id) => getTacticController()->saveContent($id))); return $router; } diff --git a/src/Api/Controller/APITacticController.php b/src/Api/Controller/APITacticController.php index 04f0a50..0edfbb3 100644 --- a/src/Api/Controller/APITacticController.php +++ b/src/Api/Controller/APITacticController.php @@ -2,7 +2,7 @@ namespace IQBall\Api\Controller; -use IQBall\Core\Route\Control; +use IQBall\App\Control; use IQBall\Core\Data\Account; use IQBall\Core\Http\HttpCodes; use IQBall\Core\Http\HttpRequest; @@ -45,4 +45,13 @@ class APITacticController { return HttpResponse::fromCode(HttpCodes::OK); }); } + + /** + * @param int $id + * @param Account $account + * @return HttpResponse + */ + public function saveContent(int $id, Account $account): HttpResponse { + return HttpResponse::fromCode(HttpCodes::OK); + } } diff --git a/src/App/Control.php b/src/App/Control.php index f3860ec..5c2fe0f 100644 --- a/src/App/Control.php +++ b/src/App/Control.php @@ -1,12 +1,10 @@