home-page #81

Merged
maxime.batista merged 92 commits from home-page into master 1 year ago

1
.gitignore vendored

@ -1,4 +1,5 @@
.vs .vs
.vscode
.idea .idea
.code .code
.vite .vite

@ -11,6 +11,7 @@ const SUPPORTS_FAST_REFRESH = _SUPPORTS_FAST_REFRESH;
* Maps the given relative source uri (relative to the `/front` folder) to its actual location depending on imported profile. * Maps the given relative source uri (relative to the `/front` folder) to its actual location depending on imported profile.
* @param string $assetURI relative uri path from `/front` folder * @param string $assetURI relative uri path from `/front` folder
* @return string valid url that points to the given uri * @return string valid url that points to the given uri
*/ */
function asset(string $assetURI): string { function asset(string $assetURI): string {
return _asset($assetURI); return _asset($assetURI);

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm246-164q-59 0-99.5-40.5T340-580q0-59 40.5-99.5T480-720q59 0 99.5 40.5T620-580q0 59-40.5 99.5T480-440Zm0 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q53 0 100-15.5t86-44.5q-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160Zm0-360q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm0-60Zm0 360Z" fill="#e6edf3"/></svg>

After

Width:  |  Height:  |  Size: 747 B

@ -0,0 +1,63 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="100"
height="50"
viewBox="7.5 18.5 85.5 56"
style="enable-background:new 7.5 18.5 85.5 56;"
xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-miterlimit:10;}
.st1{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.4358,1.4358;}
.st2{fill:none;stroke:#000000;stroke-width:0.5;stroke-miterlimit:10;}
.st3{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.4407,1.4407;}
</style>
<polygon class="st0" points="92.1,72.1 50.1,72.1 8.1,72.1 8.1,21.2 50.1,21.2 92.1,21.2 "/>
<line class="st0" x1="50.1" y1="21.2" x2="50.1" y2="72.1"/>
<circle class="st0" cx="50.1" cy="46.6" r="6.4"/>
<path class="st0" d="M8.1,66h7.2c10.1,0,18.2-8.7,18.2-19.3s-8.2-19.3-18.2-19.3H8.1"/>
<path class="st0" d="M8.1,40.2h19c3.6,0,6.4,2.9,6.4,6.4s-2.9,6.4-6.4,6.4h-19"/>
<line class="st0" x1="27.1" y1="40.2" x2="27.1" y2="53.1"/>
<g>
<g><path class="st0" d="M27.4,40.3c-0.3,0-0.5,0-0.7,0"/>
<path class="st1"
d="M25.3,40.7c-2.5,0.9-4.3,3.3-4.3,6.1c0,3,2.2,5.6,5,6.2"/>
<path
class="st0" d="M26.7,53c0.2,0,0.5,0,0.7,0"/>
</g>
</g>
<line class="st0" x1="16.2" y1="53.1" x2="16.2" y2="54.1"/>
<line class="st2" x1="19.3" y1="53.1" x2="19.3" y2="54.1"/>
<line class="st2" x1="22.4" y1="53.1" x2="22.4" y2="54.1"/>
<line class="st2" x1="25.7" y1="53.1" x2="25.7" y2="54.1"/>
<line class="st0" x1="16.1" y1="39.2" x2="16.1" y2="40.2"/>
<line class="st2" x1="19.2" y1="39.2" x2="19.2" y2="40.2"/>
<line class="st2" x1="22.3" y1="39.2" x2="22.3" y2="40.2"/>
<line class="st2" x1="25.6" y1="39.2" x2="25.6" y2="40.2"/>
<line class="st0" x1="27.1" y1="40.2" x2="27.1" y2="53.1"/>
<path class="st0" d="M92.1,66.1h-7.2c-10.1,0-18.2-8.7-18.2-19.3s8.2-19.3,18.2-19.3h7.2"/>
<path class="st0" d="M92.1,40.3h-19c-3.6,0-6.4,2.9-6.4,6.4s2.9,6.4,6.4,6.4h19"/>
<line class="st0" x1="84" y1="53.2" x2="84" y2="54.1"/>
<line class="st2" x1="80.9" y1="53.2" x2="80.9" y2="54.1"/>
<line class="st2" x1="77.9" y1="53.2" x2="77.9" y2="54.1"/>
<line class="st2" x1="74.5" y1="53.2" x2="74.5" y2="54.1"/>
<line class="st0" x1="84.1" y1="39.3" x2="84.1" y2="40.3"/>
<line class="st2" x1="81" y1="39.3" x2="81" y2="40.3"/>
<line class="st2" x1="77.9" y1="39.3" x2="77.9" y2="40.3"/>
<line class="st2" x1="74.6" y1="39.3" x2="74.6" y2="40.3"/>
<line class="st0" x1="73.1" y1="40.3" x2="73.1" y2="53.2"/>
<line class="st2" x1="36.2" y1="70" x2="36.2" y2="74.1"/>
<line class="st2" x1="63.5" y1="70" x2="63.5" y2="74.1"/>
<line class="st2" x1="36.2" y1="19.1" x2="36.2" y2="23.2"/>
<line class="st2" x1="63.5" y1="19.1" x2="63.5" y2="23.2"/>
<g xmlns="http://www.w3.org/2000/svg">
<g>
<path class="st0" d="M72.9,40.3c0.3,0,0.5,0,0.7,0"/>
<path class="st3"
d="M75,40.7c2.5,0.9,4.3,3.3,4.3,6.1c0,3-2.2,5.6-5.1,6.2"/>
<path
class="st0" d="M73.5,53.1c-0.2,0-0.5,0-0.7,0"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -116,23 +116,26 @@ export default function BendableArrow({
const styleWidth = style?.width ?? ArrowStyleDefaults.width const styleWidth = style?.width ?? ArrowStyleDefaults.width
const computeInternalSegments = useCallback((segments: Segment[]) => { const computeInternalSegments = useCallback(
return segments.map((segment, idx) => { (segments: Segment[]) => {
if (idx == 0) { return segments.map((segment, idx) => {
if (idx == 0) {
return {
start: startPos,
controlPoint: segment.controlPoint ?? null,
end: segment.next,
}
}
const start = segments[idx - 1].next
return { return {
start: startPos, start,
controlPoint: segment.controlPoint ?? null, controlPoint: segment.controlPoint ?? null,
end: segment.next, end: segment.next,
} }
} })
const start = segments[idx - 1].next },
return { [segments, startPos],
start, )
controlPoint: segment.controlPoint ?? null,
end: segment.next,
}
})
}, [segments, startPos])
// Cache the segments so that when the user is changing the segments (it moves an ArrowPoint), // Cache the segments so that when the user is changing the segments (it moves an ArrowPoint),
// it does not unwind to this arrow's component parent until validated. // it does not unwind to this arrow's component parent until validated.
@ -151,8 +154,6 @@ export default function BendableArrow({
const headRef = useRef<HTMLDivElement>(null) const headRef = useRef<HTMLDivElement>(null)
const tailRef = useRef<HTMLDivElement>(null) const tailRef = useRef<HTMLDivElement>(null)
/** /**
* Computes and return the segments edition points * Computes and return the segments edition points
* @param parentBase * @param parentBase

@ -8,6 +8,7 @@ import {
useState, useState,
} from "react" } from "react"
import CourtPlayer from "./CourtPlayer" import CourtPlayer from "./CourtPlayer"
import { Player } from "../../tactic/Player" import { Player } from "../../tactic/Player"
import { Action, ActionKind } from "../../tactic/Action" import { Action, ActionKind } from "../../tactic/Action"
import ArrowAction from "../actions/ArrowAction" import ArrowAction from "../actions/ArrowAction"

@ -9,3 +9,6 @@
height: 20px; height: 20px;
cursor: pointer; cursor: pointer;
} }
.ball-div:focus-within {
yanis.dahmane-bounoua marked this conversation as resolved
Review

empty css rule

empty css rule

not my production

not my production
}

@ -1,13 +0,0 @@
:root {
--main-color: #ffffff;
--second-color: #ccde54;
--background-color: #d2cdd3;
--selected-team-primarycolor: #ffffff;
--selected-team-secondarycolor: #000000;
--selection-color: #3f7fc4;
--arrows-color: #676767;
}

@ -0,0 +1,43 @@
@import url(../theme/dark.css);
@import url(personnal_space.css);
@import url(side_menu.css);
@import url(../template/header.css);
body {
/* background-color: #303030; */
}
#main {
/* margin-left : 10%;
margin-right: 10%; */
/* border : solid 1px #303030; */
display: flex;
flex-direction: column;
font-family: var(--font-content);
height: 100%;
}
#body {
display: flex;
flex-direction: row;
margin: 0px;
height: 100%;
background-color: var(--second-color);
}
.data {
border: 1.5px solid var(--main-contrast-color);
background-color: var(--main-color);
border-radius: 0.75cap;
color: var(--main-contrast-color);
}
.data:hover {
border-color: var(--accent-color);
cursor: pointer;
}
.set-button {
width: 80%;
margin-left: 5%;
margin-top: 5%;
}

@ -0,0 +1,40 @@
#personal-space {
display: flex;
flex-direction: column;
}
#title-personal-space h2 {
text-align: center;
color: var(--main-contrast-color);
/* font-family: Helvetica;
font-weight: bold; */
}
#body-personal-space {
width: 95%;
/* background-color: #ccc2b7; */
border: 3px var(--main-color) solid;
border-radius: 0.5cap;
align-self: center;
}
#body-personal-space table {
width: 100%;
border-collapse: separate;
border-spacing: 1em;
table-layout: fixed;
overflow: hidden;
}
#body-personal-space td {
width: 80px !important;
padding-bottom: 1%;
padding-top: 1%;
height: fit-content;
text-align: center;
overflow: hidden;
}
tbody p {
text-align: center;
}

@ -0,0 +1,53 @@
@import url(../theme/dark.css);
#side-menu {
background-color: var(--third-color);
display: flex;
flex-direction: column;
align-items: center;
overflow: hidden;
}
#side-menu h2 {
display: inline-block;
margin-right: 5%;
}
#side-menu-content {
width: 90%;
}
.titre-side-menu {
border-bottom: var(--main-color) solid 3px;
width: 100%;
margin-bottom: 3%;
}
#side-menu .title {
font-size: 12px;
font-weight: bold;
color: var(--main-contrast-color);
letter-spacing: 1px;
text-transform: uppercase;
background-color: var(--main-color);
padding: 3%;
margin-bottom: 0px;
margin-right: 3%;
}
.new {
border-radius: 100%;
}
.button-side-menu {
/* border : black solid 1px; */
border-radius: 0.5cap;
width: fit-content;
padding: 2%;
margin-top: 3%;
overflow: hidden;
}
.button-side-menu:hover {
/* background-color: #c9d1e0; */
cursor: pointer;
}

@ -0,0 +1,65 @@
#header {
text-align: center;
background-color: var(--main-color);
margin: 0px;
/* border : var(--accent-color) 1px solid; */
display: flex;
flex-direction: row;
font-family: var(--font-title);
/* border-radius: 0.75cap; */
}
#img-account {
width: 100%;
cursor: pointer;
}
#header-right,
#header-left {
width: 10%;
/* border: yellow 2px solid; */
}
#header-right {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#username {
color: var(--main-contrast-color);
margin: 0;
}
#clickable-header-right:hover #username {
color: var(--accent-color);
}
#header-center {
width: 80%;
}
#clickable-header-right {
width: 40%;
border-radius: 1cap;
padding: 2%;
}
#clickable-header-right:hover {
border: orange 1px solid;
}
.clickable {
cursor: pointer;
}
#img-account {
width: 100%;
}
#iqball {
color: var(--accent-color);
font-weight: bold;
font-size: 45px;
}

@ -0,0 +1,9 @@
:root {
--main-color: #191a21;
--second-color: #282a36;
--third-color: #303341;
--accent-color: #ffa238;
--main-contrast-color: #e6edf3;
--font-title: Helvetica;
--font-content: Helvetica;
}

@ -0,0 +1,267 @@
import "../style/home/home.css"
// import AccountSvg from "../assets/account.svg?react"
import { CSSProperties, useRef } from "react"
import { Header } from "./template/Header"
interface Tactic {
id: number
name: string
creation_date: string
}
interface Team {
id: number
name: string
picture: string
main_color: string
second_color: string
}
export default function Home({
yanis.dahmane-bounoua marked this conversation as resolved
Review

Only this function should be exported, all the other functions may not be exported as they are not intended to be used by external files.

Only this function should be exported, all the other functions may not be exported as they are not intended to be used by external files.
lastTactics,
allTactics,
teams,
username,
}: {
lastTactics: Tactic[]
allTactics: Tactic[]
teams: Team[]
username: string
}) {
return (
<div id="main">
<Header username={username} />
<Body
lastTactics={lastTactics}
allTactics={allTactics}
teams={teams}
/>
</div>
)
}
function Body({
lastTactics,
allTactics,
teams,
}: {
lastTactics: Tactic[]
allTactics: Tactic[]
teams: Team[]
}) {
const widthPersonalSpace = 78
const widthSideMenu = 100 - widthPersonalSpace
return (
<div id="body">
<PersonalSpace width={widthPersonalSpace} allTactics={allTactics} />
<SideMenu
width={widthSideMenu}
lastTactics={lastTactics}
teams={teams}
/>
</div>
)
}
function SideMenu({
width,
lastTactics,
teams,
}: {
width: number
lastTactics: Tactic[]
teams: Team[]
}) {
return (
<div
id="side-menu"
style={{
width: width + "%",
}}>
<div id="side-menu-content">
<Team teams={teams} />
<Tactic lastTactics={lastTactics} />
</div>
</div>
)
}
function PersonalSpace({
width,
allTactics,
}: {
width: number
allTactics: Tactic[]
}) {
return (
<div
id="personal-space"
style={{
width: width + "%",
}}>
<TitlePersonalSpace />
<BodyPersonalSpace allTactics={allTactics} />
</div>
)
}
function TitlePersonalSpace() {
return (
<div id="title-personal-space">
<h2>Espace Personnel</h2>
</div>
)
}
function TableData({ allTactics }: { allTactics: Tactic[] }) {
const nbRow = Math.floor(allTactics.length / 3) + 1
let listTactic = Array(nbRow)
for (let i = 0; i < nbRow; i++) {
listTactic[i] = Array(0)
}
let i = 0
let j = 0
allTactics.forEach((tactic) => {
listTactic[i].push(tactic)
j++
if (j === 3) {
i++
j = 0
}
})
i = 0
while (i < nbRow) {
listTactic[i] = listTactic[i].map((tactic: Tactic) => (
<td
key={tactic.id}
className="data"
onClick={() => {
location.pathname = "/tactic/" + tactic.id + "/edit"
}}>
{truncateString(tactic.name, 25)}
</td>
))
i++
}
if (nbRow == 1) {
if (listTactic[0].length < 3) {
for (let i = 0; i <= 3 - listTactic[0].length; i++) {
listTactic[0].push(<td key={"tdNone" + i}></td>)
}
}
}
const data = listTactic.map((tactic, rowIndex) => (
<tr key={rowIndex + "row"}>{tactic}</tr>
))
return data
}
function BodyPersonalSpace({ allTactics }: { allTactics: Tactic[] }) {
let data
if (allTactics.length == 0) {
data = <p>Aucune tactique créé !</p>
} else {
data = <TableData allTactics={allTactics} />
}
return (
<div id="body-personal-space">
<table>
<tbody key="tbody">{data}</tbody>
</table>
</div>
)
}
function Team({ teams }: { teams: Team[] }) {
const listTeam = teams.map((team, rowIndex) => (
<li key={"team" + rowIndex}>
{team.name}
<button onClick={() => (location.pathname = "/team/" + team.id)}>
open
</button>
</li>
))
return (
<div id="teams">
<div className="titre-side-menu">
<h2 className="title">Mes équipes</h2>
<button
className="new"
onClick={() => (location.pathname = "/team/new")}>
+
</button>
</div>
<SetButtonTeam teams={teams} />
</div>
)
}
function Tactic({ lastTactics }: { lastTactics: Tactic[] }) {
return (
<div id="tactic">
<div className="titre-side-menu">
<h2 className="title">Mes dernières stratégies</h2>
<button
className="new"
id="create-tactic"
onClick={() => (location.pathname = "/tactic/new")}>
+
</button>
</div>
<SetButtonTactic tactics={lastTactics} />
</div>
)
}
function SetButtonTactic({ tactics }: { tactics: Tactic[] }) {
const lastTactics = tactics.map((tactic) => (
<ButtonLastTactic tactic={tactic} />
))
return <div className="set-button">{lastTactics}</div>
}
function SetButtonTeam({ teams }: { teams: Team[] }) {
const listTeam = teams.map((teams) => <ButtonTeam team={teams} />)
return <div className="set-button">{listTeam}</div>
}
function ButtonTeam({ team }: { team: Team }) {
const name = truncateString(team.name, 20)
return (
<div>
<div
id={"button-team" + team.id}
className="button-side-menu data"
onClick={() => {
location.pathname = "/team/" + team.id
yanis.dahmane-bounoua marked this conversation as resolved
Review

Not used

Not used

used at line 121

used at line 121
}}>
{name}
</div>
</div>
)
}
function ButtonLastTactic({ tactic }: { tactic: Tactic }) {
const name = truncateString(tactic.name, 20)
return (
<div
id={"button" + tactic.id}
className="button-side-menu data"
onClick={() => {
location.pathname = "/tactic/" + tactic.id + "/edit"
}}>
{name}
</div>
)
}
function truncateString(name: string, limit: number): string {
if (name.length > limit) {
name = name.substring(0, limit) + "..."
}
return name
}

@ -0,0 +1,36 @@
/**
*
* @param param0 username
* @returns Header
*/
export function Header({ username }: { username: string }) {
return (
<div id="header">
<div id="header-left"></div>
<div id="header-center">
<h1
id="iqball"
className="clickable"
onClick={() => {
location.pathname = "/"
}}>
<span id="IQ">IQ</span>
<span id="Ball">Ball</span>
</h1>
</div>
<div id="header-right">
<div className="clickable" id="clickable-header-right">
{/* <AccountSvg id="img-account" /> */}
<img
id="img-account"
src="account.svg"
onClick={() => {
location.pathname = "/settings"
}}
/>
<p id="username">{username}</p>
</div>
</div>
</div>
)
}

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm246-164q-59 0-99.5-40.5T340-580q0-59 40.5-99.5T480-720q59 0 99.5 40.5T620-580q0 59-40.5 99.5T480-440Zm0 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q53 0 100-15.5t86-44.5q-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160Zm0-360q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm0-60Zm0 360Z" fill="#e6edf3"/></svg>

After

Width:  |  Height:  |  Size: 747 B

@ -1,6 +1,5 @@
<?php <?php
require "../vendor/autoload.php"; require "../vendor/autoload.php";
require "../config.php"; require "../config.php";
require "../sql/database.php"; require "../sql/database.php";
@ -39,7 +38,7 @@ function getConnection(): Connection {
} }
function getUserController(): UserController { function getUserController(): UserController {
return new UserController(new TacticModel(new TacticInfoGateway(getConnection()))); return new UserController(new TacticModel(new TacticInfoGateway(getConnection())), new TeamModel(new TeamGateway(getConnection()), new MemberGateway(getConnection()), new AccountGateway(getConnection())));
} }
function getVisualizerController(): VisualizerController { function getVisualizerController(): VisualizerController {
@ -122,7 +121,6 @@ function runMatch($match, MutableSessionHandle $session): HttpResponse {
return App::runAction($basePath . '/login', $match['target'], $match['params'], $session); return App::runAction($basePath . '/login', $match['target'], $match['params'], $session);
} }
//this is a global variable //this is a global variable
$basePath = get_public_path(__DIR__); $basePath = get_public_path(__DIR__);

@ -7,15 +7,19 @@ use IQBall\App\Session\SessionHandle;
use IQBall\App\ViewHttpResponse; use IQBall\App\ViewHttpResponse;
use IQBall\Core\Http\HttpResponse; use IQBall\Core\Http\HttpResponse;
use IQBall\Core\Model\TacticModel; use IQBall\Core\Model\TacticModel;
use IQBall\Core\Model\TeamModel;
class UserController { class UserController {
private TacticModel $tactics; private TacticModel $tactics;
private ?TeamModel $teams;
/** /**
* @param TacticModel $tactics * @param TacticModel $tactics
*/ */
public function __construct(TacticModel $tactics) { public function __construct(TacticModel $tactics, ?TeamModel $teams = null) {
$this->tactics = $tactics; $this->tactics = $tactics;
$this->teams = $teams;
} }
/** /**
@ -23,16 +27,34 @@ class UserController {
* @return ViewHttpResponse the home page view * @return ViewHttpResponse the home page view
*/ */
public function home(SessionHandle $session): ViewHttpResponse { public function home(SessionHandle $session): ViewHttpResponse {
//TODO use session's account to get the last 5 tactics of the logged-in account $limitNbTactics = 5;
$listTactic = $this->tactics->getLast(5); $lastTactics = $this->tactics->getLast($limitNbTactics, $session->getAccount()->getId());
return ViewHttpResponse::twig("home.twig", ["recentTactic" => $listTactic]); $allTactics = $this->tactics->getAll($session->getAccount()->getId());
$name = $session->getAccount()->getName();
if ($this->teams != null) {
$teams = $this->teams->getAll($session->getAccount()->getId());
} else {
$teams = [];
}
return ViewHttpResponse::react("views/Home.tsx", [
"lastTactics" => $lastTactics,
"allTactics" => $allTactics,
"teams" => $teams,
"username" => $name,
]);
}
public function homeTwig(SessionHandle $session): ViewHttpResponse {
return ViewHttpResponse::twig("home.twig", []);
} }
/** /**
* @return ViewHttpResponse account settings page * @return ViewHttpResponse account settings page
*/ */
public function settings(SessionHandle $session): ViewHttpResponse { public function settings(SessionHandle $session): ViewHttpResponse {
return ViewHttpResponse::twig("account_settings.twig", []); return ViewHttpResponse::react("views/Settings.tsx", []);
} }
public function disconnect(MutableSessionHandle $session): HttpResponse { public function disconnect(MutableSessionHandle $session): HttpResponse {

@ -45,13 +45,40 @@ class TacticInfoGateway {
* @param integer $nb * @param integer $nb
* @return array<array<string,mixed>> * @return array<array<string,mixed>>
yanis.dahmane-bounoua marked this conversation as resolved
Review

I think it should rather return TacticInfo[]

I think it should rather return `TacticInfo[]`
*/ */
public function getLast(int $nb): ?array { public function getLast(int $nb, int $ownerId): ?array {
$res = $this->con->fetch( $res = $this->con->fetch(
"SELECT * FROM Tactic ORDER BY creation_date DESC LIMIT :nb ", "SELECT *
[":nb" => [$nb, PDO::PARAM_INT]] FROM Tactic
WHERE owner = :ownerId
ORDER BY creation_date DESC
LIMIT :nb",
[
":ownerId" => [$ownerId, PDO::PARAM_INT],":nb" => [$nb, PDO::PARAM_INT],
]
); );
if (count($res) == 0) { if (count($res) == 0) {
return null; return [];
}
return $res;
}
/**
* Get all the tactics of the owner
*
* @return array<array<string,mixed>>
yanis.dahmane-bounoua marked this conversation as resolved
Review

I think it should rather returns TacticInfo[]

I think it should rather returns `TacticInfo[]`
*/
public function getAll(int $ownerId): ?array {
$res = $this->con->fetch(
"SELECT *
FROM Tactic
WHERE owner = :ownerId
ORDER BY name DESC",
[
":ownerId" => [$ownerId, PDO::PARAM_INT],
]
);
if (count($res) == 0) {
return [];
} }
return $res; return $res;
} }

@ -81,5 +81,14 @@ class TeamGateway {
)[0]['id'] ?? null; )[0]['id'] ?? null;
} }
/**
* Get all the user's teams
*
* @param integer $user
* @return array<array<string, mixed>>
*/
public function getAll(int $user): array {
return $this->con->fetch("SELECT * FROM Team", []);
}
} }

@ -3,6 +3,7 @@
namespace IQBall\Core\Model; namespace IQBall\Core\Model;
use IQBall\Core\Data\CourtType; use IQBall\Core\Data\CourtType;
use IQBall\App\Session\SessionHandle;
use IQBall\Core\Data\TacticInfo; use IQBall\Core\Data\TacticInfo;
use IQBall\Core\Gateway\TacticInfoGateway; use IQBall\Core\Gateway\TacticInfoGateway;
use IQBall\Core\Validation\ValidationFail; use IQBall\Core\Validation\ValidationFail;
@ -57,10 +58,27 @@ class TacticModel {
* @param integer $nb * @param integer $nb
* @return array<array<string,mixed>> * @return array<array<string,mixed>>
*/ */
public function getLast(int $nb): ?array {
return $this->tactics->getLast($nb); /**
* Return the nb last tactics
*
* @param integer $nb
* @param integer $ownerId
* @return array<array<string,mixed>>
*/
public function getLast(int $nb, int $ownerId): array {
return $this->tactics->getLast($nb, $ownerId);
} }
/**
* Get all the tactics of the owner
*
* @param integer $ownerId
* @return array<array<string,mixed>>
*/
public function getAll(int $ownerId): ?array {
return $this->tactics->getAll($ownerId);
}
/** /**
* Update the name of a tactic * Update the name of a tactic
* @param int $id the tactic identifier * @param int $id the tactic identifier

@ -79,4 +79,14 @@ class TeamModel {
return $teamId; return $teamId;
} }
/**
* Get all user's teams
*
* @param integer $user
* @return array<array<string, mixed>>
*/
public function getAll(int $user): array {
return $this->teams->getAll($user);
}
} }

Loading…
Cancel
Save