parent
947cda494a
commit
6f3899fb5f
@ -0,0 +1,24 @@
|
|||||||
|
import React, {useRef, useState} from "react";
|
||||||
|
import "../style/title_input.css";
|
||||||
|
|
||||||
|
export default function TitleInput({default_value, on_validated}: {
|
||||||
|
default_value: string,
|
||||||
|
on_validated: (a: string) => void
|
||||||
|
}) {
|
||||||
|
const [value, setValue] = useState(default_value);
|
||||||
|
const ref = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input className="title_input"
|
||||||
|
ref={ref}
|
||||||
|
type="text"
|
||||||
|
value={value}
|
||||||
|
onChange={event => setValue(event.target.value)}
|
||||||
|
onBlur={_ => on_validated(value)}
|
||||||
|
onKeyDown={event => {
|
||||||
|
if (event.key == 'Enter')
|
||||||
|
ref.current?.blur();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--main-color: #ffffff;
|
||||||
|
--second-color: #ccde54;
|
||||||
|
|
||||||
|
--background-color: #d2cdd3;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
@import "colors.css";
|
||||||
|
|
||||||
|
|
||||||
|
#main {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#topbar {
|
||||||
|
display: flex;
|
||||||
|
background-color: var(--main-color);
|
||||||
|
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title_input {
|
||||||
|
width: 25ch;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
.title_input {
|
||||||
|
background: transparent;
|
||||||
|
border-top: none;
|
||||||
|
border-right: none;
|
||||||
|
border-left: none;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
border-bottom-width: 2px;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title_input:focus {
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
border-bottom-color: blueviolet;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
|||||||
|
import React from "react";
|
||||||
|
import "../style/editor.css";
|
||||||
|
import TitleInput from "../components/TitleInput";
|
||||||
|
|
||||||
|
|
||||||
|
export default function Editor({id, name}: { id: number, name: string }) {
|
||||||
|
return (
|
||||||
|
<div id="main">
|
||||||
|
<div id="topbar">
|
||||||
|
<div>LEFT</div>
|
||||||
|
<TitleInput default_value={name} on_validated={name => update_tactic_name(id, name)}/>
|
||||||
|
<div>RIGHT</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_tactic_name(id: number, new_name: string) {
|
||||||
|
//FIXME avoid absolute path as they would not work on staging server
|
||||||
|
fetch(`/api/tactic/${id}/edit/name`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: new_name
|
||||||
|
})
|
||||||
|
}).then(response => {
|
||||||
|
if (!response.ok)
|
||||||
|
alert("could not update tactic name!")
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require "../../config.php";
|
||||||
|
require "../../vendor/autoload.php";
|
||||||
|
require "../../sql/database.php";
|
||||||
|
|
||||||
|
use App\Api\TacticEndpoint;
|
||||||
|
use App\Connexion;
|
||||||
|
use App\Gateway\TacticInfoGateway;
|
||||||
|
|
||||||
|
$con = new Connexion(get_database());
|
||||||
|
|
||||||
|
$router = new AltoRouter();
|
||||||
|
$router->setBasePath("/api");
|
||||||
|
|
||||||
|
$tacticEndpoint = new TacticEndpoint(new TacticInfoGateway($con));
|
||||||
|
$router->map("POST", "/tactic/[i:id]/edit/name", fn(int $id) => $tacticEndpoint->update_name($id));
|
||||||
|
$router->map("GET", "/tactic/[i:id]", fn(int $id) => $tacticEndpoint->get_tactic_info($id));
|
||||||
|
$router->map("POST", "/tactic/new", fn() => $tacticEndpoint->new_tactic());
|
||||||
|
|
||||||
|
$match = $router->match();
|
||||||
|
|
||||||
|
if ($match == null) {
|
||||||
|
echo "404 not found";
|
||||||
|
header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
call_user_func_array($match['target'], $match['params']);
|
@ -1,8 +1,12 @@
|
|||||||
|
|
||||||
-- drop tables here
|
-- drop tables here
|
||||||
DROP TABLE IF EXISTS FormEntries;
|
DROP TABLE IF EXISTS FormEntries;
|
||||||
|
DROP TABLE IF EXISTS TacticInfo;
|
||||||
|
|
||||||
CREATE TABLE FormEntries(name varchar, description varchar);
|
CREATE TABLE FormEntries(name varchar, description varchar);
|
||||||
|
|
||||||
|
CREATE TABLE TacticInfo(
|
||||||
|
id integer PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name varchar,
|
||||||
|
creation_date timestamp
|
||||||
|
);
|
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Api;
|
||||||
|
use App\Gateway\TacticInfoGateway;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API endpoint related to tactics
|
||||||
|
*/
|
||||||
|
class TacticEndpoint {
|
||||||
|
private TacticInfoGateway $tactics;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TacticInfoGateway $tactics
|
||||||
|
*/
|
||||||
|
public function __construct(TacticInfoGateway $tactics) {
|
||||||
|
$this->tactics = $tactics;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function update_name(int $tactic_id) {
|
||||||
|
$request_body = file_get_contents('php://input');
|
||||||
|
$data = json_decode($request_body);
|
||||||
|
|
||||||
|
$new_name = $data->name;
|
||||||
|
|
||||||
|
$this->tactics->update($tactic_id, $new_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function new_tactic() {
|
||||||
|
$request_body = file_get_contents('php://input');
|
||||||
|
$data = json_decode($request_body);
|
||||||
|
|
||||||
|
$initial_name = $data->name;
|
||||||
|
$id = $this->tactics->insert($initial_name)->getId();
|
||||||
|
|
||||||
|
echo "{id: $id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_tactic_info(int $id) {
|
||||||
|
$tactic_info = $this->tactics->get($id);
|
||||||
|
echo json_encode($tactic_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Data\TacticInfo;
|
||||||
|
use App\Gateway\TacticInfoGateway;
|
||||||
|
|
||||||
|
class EditorController {
|
||||||
|
|
||||||
|
const TACTIC_DEFAULT_NAME = "Nouvelle tactique";
|
||||||
|
|
||||||
|
private TacticInfoGateway $tactics;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TacticInfoGateway $tactics
|
||||||
|
*/
|
||||||
|
public function __construct(TacticInfoGateway $tactics) {
|
||||||
|
$this->tactics = $tactics;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function openEditor(TacticInfo $tactic) {
|
||||||
|
send_react_front("views/Editor.tsx", ["name" => $tactic->getName(), "id" => $tactic->getId()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function makeNew() {
|
||||||
|
$info = $this->tactics->insert(self::TACTIC_DEFAULT_NAME);
|
||||||
|
$this->openEditor($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(int $id) {
|
||||||
|
$tactic = $this->tactics->get($id);
|
||||||
|
|
||||||
|
$this->openEditor($tactic);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data;
|
||||||
|
|
||||||
|
class TacticInfo implements \JsonSerializable {
|
||||||
|
private int $id;
|
||||||
|
private string $name;
|
||||||
|
private int $creation_date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $id
|
||||||
|
* @param string $name
|
||||||
|
* @param int $creation_date
|
||||||
|
*/
|
||||||
|
public function __construct(int $id, string $name, int $creation_date) {
|
||||||
|
$this->id = $id;
|
||||||
|
$this->name = $name;
|
||||||
|
$this->creation_date = $creation_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): int {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): string {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCreationDate(): int {
|
||||||
|
return $this->creation_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize() {
|
||||||
|
return get_object_vars($this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Gateway;
|
||||||
|
|
||||||
|
use App\Connexion;
|
||||||
|
use App\Data\TacticInfo;
|
||||||
|
use \PDO;
|
||||||
|
|
||||||
|
class TacticInfoGateway {
|
||||||
|
private Connexion $con;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Connexion $con
|
||||||
|
*/
|
||||||
|
public function __construct(Connexion $con) {
|
||||||
|
$this->con = $con;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(int $id): TacticInfo {
|
||||||
|
$row = $this->con->fetch(
|
||||||
|
"SELECT * FROM TacticInfo WHERE id = :id",
|
||||||
|
[":id" => [$id, PDO::PARAM_INT]]
|
||||||
|
)[0];
|
||||||
|
|
||||||
|
return new TacticInfo($id, $row["name"], strtotime($row["creation_date"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insert(string $name): TacticInfo {
|
||||||
|
$row = $this->con->fetch(
|
||||||
|
"INSERT INTO TacticInfo(name, creation_date) VALUES(:name, CURRENT_TIMESTAMP) RETURNING id, creation_date",
|
||||||
|
[":name" => [$name, PDO::PARAM_STR]]
|
||||||
|
)[0];
|
||||||
|
return new TacticInfo(intval($row["id"]), $name, strtotime($row["creation_date"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(int $id, string $name) {
|
||||||
|
$this->con->exec(
|
||||||
|
"UPDATE TacticInfo SET name = :name WHERE id = :id",
|
||||||
|
[
|
||||||
|
":name" => [$name, PDO::PARAM_STR],
|
||||||
|
":id" => [$id, PDO::PARAM_INT]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in new issue