diff --git a/.gitignore b/.gitignore
index a02dfdf..3934c5c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.vs
+.vscode
.idea
.code
.vite
diff --git a/config.php b/config.php
index 6e510c8..fdf02a4 100644
--- a/config.php
+++ b/config.php
@@ -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.
* @param string $assetURI relative uri path from `/front` folder
* @return string valid url that points to the given uri
+
*/
function asset(string $assetURI): string {
return _asset($assetURI);
diff --git a/front/assets/account.svg b/front/assets/account.svg
new file mode 100644
index 0000000..70d7391
--- /dev/null
+++ b/front/assets/account.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/front/assets/court/court.svg b/front/assets/court/court.svg
new file mode 100644
index 0000000..e01fd58
--- /dev/null
+++ b/front/assets/court/court.svg
@@ -0,0 +1,63 @@
+
\ No newline at end of file
diff --git a/front/components/editor/BasketCourt.tsx b/front/components/editor/BasketCourt.tsx
index 525e232..1e3d916 100644
--- a/front/components/editor/BasketCourt.tsx
+++ b/front/components/editor/BasketCourt.tsx
@@ -9,6 +9,7 @@ import {
} from "react"
import CourtPlayer from "./CourtPlayer"
+
import { Player } from "../../model/tactic/Player"
import { Action, ActionKind } from "../../model/tactic/Action"
import ArrowAction from "../actions/ArrowAction"
diff --git a/front/model/team/Team.ts b/front/model/Team.ts
similarity index 71%
rename from front/model/team/Team.ts
rename to front/model/Team.ts
index 01a9d10..99d530b 100644
--- a/front/model/team/Team.ts
+++ b/front/model/Team.ts
@@ -1,3 +1,5 @@
+import {User} from "./User";
+
export interface TeamInfo {
id: number
name: string
@@ -15,10 +17,3 @@ export interface Member {
user: User
role: string
}
-
-export interface User {
- id: number
- name: string
- email: string
- profilePicture: string
-}
diff --git a/front/model/User.ts b/front/model/User.ts
new file mode 100644
index 0000000..36bbb67
--- /dev/null
+++ b/front/model/User.ts
@@ -0,0 +1,6 @@
+export interface User {
+ id: number
+ name: string
+ email: string
+ profilePicture: string
+}
diff --git a/front/style/ball.css b/front/style/ball.css
index c14c196..5169ec7 100644
--- a/front/style/ball.css
+++ b/front/style/ball.css
@@ -9,3 +9,6 @@
height: 20px;
cursor: pointer;
}
+
+.ball-div:focus-within {
+}
diff --git a/front/style/colors.css b/front/style/colors.css
deleted file mode 100644
index db7edfe..0000000
--- a/front/style/colors.css
+++ /dev/null
@@ -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;
-}
diff --git a/front/style/home/home.css b/front/style/home/home.css
new file mode 100644
index 0000000..455e3af
--- /dev/null
+++ b/front/style/home/home.css
@@ -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%;
+}
diff --git a/front/style/home/personnal_space.css b/front/style/home/personnal_space.css
new file mode 100644
index 0000000..173098e
--- /dev/null
+++ b/front/style/home/personnal_space.css
@@ -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;
+}
diff --git a/front/style/home/side_menu.css b/front/style/home/side_menu.css
new file mode 100644
index 0000000..3a23947
--- /dev/null
+++ b/front/style/home/side_menu.css
@@ -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;
+}
diff --git a/front/style/template/header.css b/front/style/template/header.css
new file mode 100644
index 0000000..2ea8d2f
--- /dev/null
+++ b/front/style/template/header.css
@@ -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;
+}
diff --git a/front/style/theme/dark.css b/front/style/theme/dark.css
new file mode 100644
index 0000000..bdd4824
--- /dev/null
+++ b/front/style/theme/dark.css
@@ -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;
+}
diff --git a/front/views/Home.tsx b/front/views/Home.tsx
new file mode 100644
index 0000000..44803a3
--- /dev/null
+++ b/front/views/Home.tsx
@@ -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({
+ lastTactics,
+ allTactics,
+ teams,
+ username,
+}: {
+ lastTactics: Tactic[]
+ allTactics: Tactic[]
+ teams: Team[]
+ username: string
+}) {
+ return (
+
+
+
+
+ )
+}
+
+function Body({
+ lastTactics,
+ allTactics,
+ teams,
+}: {
+ lastTactics: Tactic[]
+ allTactics: Tactic[]
+ teams: Team[]
+}) {
+ const widthPersonalSpace = 78
+ const widthSideMenu = 100 - widthPersonalSpace
+ return (
+
+ )
+}
+
+function SideMenu({
+ width,
+ lastTactics,
+ teams,
+}: {
+ width: number
+ lastTactics: Tactic[]
+ teams: Team[]
+}) {
+ return (
+
+ )
+}
+
+function PersonalSpace({
+ width,
+ allTactics,
+}: {
+ width: number
+ allTactics: Tactic[]
+}) {
+ return (
+
+
+
+
+ )
+}
+
+function TitlePersonalSpace() {
+ return (
+
+
Espace Personnel
+
+ )
+}
+
+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) => (
+ {
+ location.pathname = "/tactic/" + tactic.id + "/edit"
+ }}>
+ {truncateString(tactic.name, 25)}
+ |
+ ))
+ i++
+ }
+ if (nbRow == 1) {
+ if (listTactic[0].length < 3) {
+ for (let i = 0; i <= 3 - listTactic[0].length; i++) {
+ listTactic[0].push( | )
+ }
+ }
+ }
+
+ const data = listTactic.map((tactic, rowIndex) => (
+ {tactic}
+ ))
+ return data
+}
+
+function BodyPersonalSpace({ allTactics }: { allTactics: Tactic[] }) {
+ let data
+ if (allTactics.length == 0) {
+ data = Aucune tactique créé !
+ } else {
+ data =
+ }
+
+ return (
+
+ )
+}
+
+function Team({ teams }: { teams: Team[] }) {
+ const listTeam = teams.map((team, rowIndex) => (
+
+ {team.name}
+
+
+ ))
+ return (
+
+
+
Mes équipes
+
+
+
+
+ )
+}
+
+function Tactic({ lastTactics }: { lastTactics: Tactic[] }) {
+ return (
+
+
+
Mes dernières stratégies
+
+
+
+
+ )
+}
+
+function SetButtonTactic({ tactics }: { tactics: Tactic[] }) {
+ const lastTactics = tactics.map((tactic) => (
+
+ ))
+ return {lastTactics}
+}
+
+function SetButtonTeam({ teams }: { teams: Team[] }) {
+ const listTeam = teams.map((teams) => )
+ return {listTeam}
+}
+
+function ButtonTeam({ team }: { team: Team }) {
+ const name = truncateString(team.name, 20)
+ return (
+
+
{
+ location.pathname = "/team/" + team.id
+ }}>
+ {name}
+
+
+ )
+}
+
+function ButtonLastTactic({ tactic }: { tactic: Tactic }) {
+ const name = truncateString(tactic.name, 20)
+ return (
+ {
+ location.pathname = "/tactic/" + tactic.id + "/edit"
+ }}>
+ {name}
+
+ )
+}
+
+function truncateString(name: string, limit: number): string {
+ if (name.length > limit) {
+ name = name.substring(0, limit) + "..."
+ }
+ return name
+}
diff --git a/front/views/TeamPanel.tsx b/front/views/TeamPanel.tsx
index 6d873c8..709d7f2 100644
--- a/front/views/TeamPanel.tsx
+++ b/front/views/TeamPanel.tsx
@@ -1,6 +1,7 @@
import "../style/team_panel.css"
import { BASE } from "../Constants"
-import { Team, TeamInfo, User, Member } from "../model/team/Team"
+import { Team, TeamInfo, Member } from "../model/Team"
+import { User } from "../model/User"
export default function TeamPanel({
isCoach,
diff --git a/front/views/template/Header.tsx b/front/views/template/Header.tsx
new file mode 100644
index 0000000..7129153
--- /dev/null
+++ b/front/views/template/Header.tsx
@@ -0,0 +1,36 @@
+/**
+ *
+ * @param param0 username
+ * @returns Header
+ */
+export function Header({ username }: { username: string }) {
+ return (
+
+ )
+}
diff --git a/public/account.svg b/public/account.svg
new file mode 100644
index 0000000..70d7391
--- /dev/null
+++ b/public/account.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/App/Controller/UserController.php b/src/App/Controller/UserController.php
index 5ce1318..e33ee61 100644
--- a/src/App/Controller/UserController.php
+++ b/src/App/Controller/UserController.php
@@ -7,15 +7,19 @@ use IQBall\App\Session\SessionHandle;
use IQBall\App\ViewHttpResponse;
use IQBall\Core\Http\HttpResponse;
use IQBall\Core\Model\TacticModel;
+use IQBall\Core\Model\TeamModel;
class UserController {
private TacticModel $tactics;
+ private ?TeamModel $teams;
+
/**
* @param TacticModel $tactics
*/
- public function __construct(TacticModel $tactics) {
+ public function __construct(TacticModel $tactics, ?TeamModel $teams = null) {
$this->tactics = $tactics;
+ $this->teams = $teams;
}
/**
@@ -23,16 +27,34 @@ class UserController {
* @return ViewHttpResponse the home page view
*/
public function home(SessionHandle $session): ViewHttpResponse {
- //TODO use session's account to get the last 5 tactics of the logged-in account
- $listTactic = $this->tactics->getLast(5);
- return ViewHttpResponse::twig("home.twig", ["recentTactic" => $listTactic]);
+ $limitNbTactics = 5;
+ $lastTactics = $this->tactics->getLast($limitNbTactics, $session->getAccount()->getId());
+ $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
*/
public function settings(SessionHandle $session): ViewHttpResponse {
- return ViewHttpResponse::twig("account_settings.twig", []);
+ return ViewHttpResponse::react("views/Settings.tsx", []);
}
public function disconnect(MutableSessionHandle $session): HttpResponse {
diff --git a/src/Core/Gateway/TacticInfoGateway.php b/src/Core/Gateway/TacticInfoGateway.php
index 67cffc4..08302c9 100644
--- a/src/Core/Gateway/TacticInfoGateway.php
+++ b/src/Core/Gateway/TacticInfoGateway.php
@@ -45,13 +45,40 @@ class TacticInfoGateway {
* @param integer $nb
* @return array>
*/
- public function getLast(int $nb): ?array {
+ public function getLast(int $nb, int $ownerId): ?array {
$res = $this->con->fetch(
- "SELECT * FROM Tactic ORDER BY creation_date DESC LIMIT :nb ",
- [":nb" => [$nb, PDO::PARAM_INT]]
+ "SELECT *
+ 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) {
- return null;
+ return [];
+ }
+ return $res;
+ }
+
+ /**
+ * Get all the tactics of the owner
+ *
+ * @return array>
+ */
+ 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;
}
diff --git a/src/Core/Gateway/TeamGateway.php b/src/Core/Gateway/TeamGateway.php
index 71df931..fe0b2bb 100644
--- a/src/Core/Gateway/TeamGateway.php
+++ b/src/Core/Gateway/TeamGateway.php
@@ -105,7 +105,8 @@ class TeamGateway {
* @param string $newSecondColor
* @return void
*/
- public function editTeam(int $idTeam, string $newName, string $newPicture, string $newMainColor, string $newSecondColor) {
+ public function editTeam(int $idTeam, string $newName, string $newPicture, string $newMainColor, string $newSecondColor)
+ {
$this->con->exec(
"UPDATE team
SET name = :newName,
@@ -121,6 +122,15 @@ class TeamGateway {
"newSecondColor" => [$newSecondColor, PDO::PARAM_STR],
]
);
+
+ }
+ /**
+ * Get all the user's teams
+ * @param integer $user
+ * @return array>
+ */
+ public function getAll(int $user): array {
+ return $this->con->fetch("SELECT * FROM Team", []);
}
}
diff --git a/src/Core/Model/TacticModel.php b/src/Core/Model/TacticModel.php
index 51e5eb8..7057e7f 100644
--- a/src/Core/Model/TacticModel.php
+++ b/src/Core/Model/TacticModel.php
@@ -3,6 +3,7 @@
namespace IQBall\Core\Model;
use IQBall\Core\Data\CourtType;
+use IQBall\App\Session\SessionHandle;
use IQBall\Core\Data\TacticInfo;
use IQBall\Core\Gateway\TacticInfoGateway;
use IQBall\Core\Validation\ValidationFail;
@@ -57,10 +58,27 @@ class TacticModel {
* @param integer $nb
* @return array>
*/
- public function getLast(int $nb): ?array {
- return $this->tactics->getLast($nb);
+
+ /**
+ * Return the nb last tactics
+ *
+ * @param integer $nb
+ * @param integer $ownerId
+ * @return array>
+ */
+ 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>
+ */
+ public function getAll(int $ownerId): ?array {
+ return $this->tactics->getAll($ownerId);
+ }
/**
* Update the name of a tactic
* @param int $id the tactic identifier
diff --git a/src/Core/Model/TeamModel.php b/src/Core/Model/TeamModel.php
index 9f03953..d6c97ce 100644
--- a/src/Core/Model/TeamModel.php
+++ b/src/Core/Model/TeamModel.php
@@ -126,8 +126,18 @@ class TeamModel {
* @param string $newSecondColor
* @return void
*/
- public function editTeam(int $idTeam, string $newName, string $newPicture, string $newMainColor, string $newSecondColor) {
+ public function editTeam(int $idTeam, string $newName, string $newPicture, string $newMainColor, string $newSecondColor)
+ {
$this->teams->editTeam($idTeam, $newName, $newPicture, $newMainColor, $newSecondColor);
}
+ /**
+ * Get all user's teams
+ *
+ * @param integer $user
+ * @return array>
+ */
+ public function getAll(int $user): array {
+ return $this->teams->getAll($user);
+ }
}