Compare commits

..

2 Commits

Author SHA1 Message Date
Maxime BATISTA b941d6530c Update '.env'
continuous-integration/drone/push Build is passing Details
1 year ago
maxime.batista 1faa8168f9 fix cards
continuous-integration/drone/push Build is passing Details
1 year ago

2123
composer.lock generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

@ -23,7 +23,6 @@ import {
import { BASE } from "./Constants.ts"
import { Authentication, Fetcher } from "./app/Fetcher.ts"
import { User } from "./model/User.ts"
import AddMemberPage from "./pages/AddMemberPage.tsx";
const HomePage = lazy(() => import("./pages/HomePage.tsx"))
const LoginPage = lazy(() => import("./pages/LoginPage.tsx"))
@ -132,10 +131,6 @@ export default function App() {
</LoggedInPage>,
)}
/>
<Route
path={"/team/:teamId/addMember"}
element={suspense(<AddMemberPage/>)}
/>
<Route
path={"/tactic/new"}
element={suspense(<NewTacticPage />)}

@ -15,10 +15,5 @@ export interface Team {
export interface Member {
user: User
role: MemberRole
}
export const enum MemberRole{
PLAYER,
COACH
role: string
}

@ -1,96 +0,0 @@
import {FormEvent, useState} from "react"
import "../style/form.css"
// @ts-ignore
import {useNavigate, useParams} from "react-router-dom"
import {useAppFetcher} from "../App.tsx";
import {Failure} from "../app/Failure.ts";
export default function AddMemberPage() {
const [errors, setErrors] = useState<Failure[]>([])
const fetcher = useAppFetcher()
const navigate = useNavigate()
const { teamId } = useParams()
async function handleSubmit(e : FormEvent){
e.preventDefault()
const { email,role} = Object.fromEntries(
new FormData(e.target as HTMLFormElement),
)
console.log(email,role)
const response = await fetcher.fetchAPI(
"teams/"+teamId+"/members",
{email,role},
"POST"
)
if(response.ok){
const teamId = await response.json()
navigate("/team/"+teamId)
return
}
try {
const failures = await response.json()
setErrors(
Object.entries<string[]>(failures).map(([type, messages]) => ({
type,
messages,
})),
)
} catch (e) {
setErrors([
{
type: "internal error",
messages: ["an internal error occurred."],
},
])
}
}
return (
<div className="container">
<h2>Ajouter un membre à votre équipe</h2>
{errors.map(({ type, messages }) =>
messages.map((message) => (
<p key={type} style={{ color: "red" }}>
{type} : {message}
</p>
)),
)}
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="email">Email du membre :</label>
<input type="text" id="email" name="email" required/>
<fieldset className="role">
<legend>Rôle du membre dans l'équipe :</legend>
<div className="radio">
<label htmlFor="P">Joueur</label>
<input type="radio" id="P" name="role" value="PLAYER" checked />
</div>
<div className="radio">
<label htmlFor="C">Coach</label>
<input type="radio" id="C" name="role" value="COACH" />
</div>
</fieldset>
<div id="buttons">
<input
className="button"
type="submit"
value="Confirmer"
/>
</div>
</div>
</form>
</div>
)
}

@ -1,112 +1,3 @@
import {FormEvent, useState} from "react"
import "../style/form.css"
// @ts-ignore
import { useNavigate } from "react-router-dom"
import {useAppFetcher} from "../App.tsx";
import {Failure} from "../app/Failure.ts";
export default function CreateTeamPage() {
const [errors, setErrors] = useState<Failure[]>([])
const fetcher = useAppFetcher()
const navigate = useNavigate()
async function handleSubmit(e : FormEvent){
e.preventDefault()
const { name, firstColor,secondColor,picture } = Object.fromEntries(
new FormData(e.target as HTMLFormElement),
)
const response = await fetcher.fetchAPI(
"teams",
{name,firstColor: firstColor.toString().toUpperCase(),secondColor: secondColor.toString().toUpperCase(),picture},
"POST"
)
if(response.ok){
const {id} = await response.json()
navigate("/team/"+id)
return
}
try {
const failures = await response.json()
setErrors(
Object.entries<string[]>(failures).map(([type, messages]) => ({
type,
messages,
})),
)
} catch (e) {
setErrors([
{
type: "internal error",
messages: ["an internal error occurred."],
},
])
}
}
return (
<div className="container">
<h2>Créer une équipe</h2>
{errors.map(({ type, messages }) =>
messages.map((message) => (
<p key={type} style={{ color: "red" }}>
{type} : {message}
</p>
)),
)}
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="name">Nom de l'équipe :</label>
<input
className="text-input"
type="text"
id="name"
name="name"
required
/>
<label htmlFor="picture">Logo :</label>
<input
className="text-input"
type="text"
id="picture"
name="picture"
required
/>
<label htmlFor="firstColor">Couleur principale :</label>
<input
className="color-input"
type="color"
id="firstColor"
name="firstColor"
defaultValue="#ffffff"
required
/>
<label htmlFor="secondColor">Couleur secondaire :</label>
<input
className="color-input"
type="color"
id="secondColor"
name="secondColor"
required
/>
<div id="buttons">
<input
className="button"
type="submit"
value="Confirmer"
/>
</div>
</div>
</form>
</div>
)
return <h1>Create Team Page</h1>
}

@ -1,38 +1,23 @@
import "../style/team_panel.css"
import {Member, MemberRole, Team, TeamInfo} from "../model/Team"
import {useNavigate, useParams} from "react-router-dom"
import {useAppFetcher, useUser} from "../App.tsx";
import {useEffect, useState} from "react";
import { BASE } from "../Constants"
import { Member, Team, TeamInfo } from "../model/Team"
import { useParams } from "react-router-dom"
export default function TeamPanelPage() {
const fetcher = useAppFetcher()
const { teamId } = useParams()
const [team,setTeam ] = useState<Team>()
const [user] = useUser()
useEffect(() => {
async function init(){
const infoResponse = await fetcher.fetchAPIGet("teams/"+teamId)
const teamInfo : TeamInfo = await infoResponse.json()
const membersResponse = await fetcher.fetchAPIGet("teams/"+teamId+"/members")
const members : Member[] = await membersResponse.json()
setTeam({info:teamInfo, members:members})
const teamInfo = {
id: parseInt(teamId!),
name: teamId!,
mainColor: "#FFFFFF",
secondColor: "#000000",
picture:
"https://a.espncdn.com/combiner/i?img=/i/teamlogos/nba/500/lal.png",
}
if(team === undefined){
init()
}
}, [fetcher,team]);
if(team === undefined){
return <p>Chargement ...</p>
}
const isCoach = team.members.some(m=>m.user.id === user!.id && m.role === MemberRole.COACH)
return (
<TeamPanel
team={{ info: team.info, members: team.members }}
currentUserId={user!.id}
isCoach={isCoach}
team={{ info: teamInfo, members: [] }}
currentUserId={0}
isCoach={false}
/>
)
}
@ -48,9 +33,14 @@ function TeamPanel({
}) {
return (
<div id="main-div">
<header>
<h1>
<a href={BASE + "/"}>IQBall</a>
</h1>
</header>
<TeamDisplay team={team.info} />
{isCoach && <CoachOptions id={team.info.id} userId={currentUserId} />}
{isCoach && <CoachOptions id={team.info.id} />}
<MembersDisplay
members={team.members}
@ -87,27 +77,25 @@ function ColorDisplay({ color }: { color: string }) {
return <div className="square" style={{ backgroundColor: color }} />
}
function CoachOptions({ id,userId }: { id: number,userId:number }) {
const navigate = useNavigate()
const fetcher = useAppFetcher()
function CoachOptions({ id }: { id: number }) {
return (
<div>
<button
id="delete"
onClick={async () => {
const res = confirm("Êtes-vous sûr de supprimer cette équipe?")
if (res) {
await fetcher.fetchAPI(
"team/" + id + "/members/" + userId,
{},
"DELETE"
)
navigate("/")
}
}
onClick={() =>
confirm("Êtes-vous sûr de supprimer cette équipe?")
? (window.location.href = `${BASE}/team/${id}/delete`)
: {}
}>
Supprimer
</button>
<button
id="edit"
onClick={() =>
(window.location.href = `${BASE}/team/${id}/edit`)
}>
Modifier
</button>
</div>
)
}
@ -131,7 +119,6 @@ function MembersDisplay({
currentUserId={currentUserId}
/>
))
const navigate = useNavigate()
return (
<div id="members">
<div id="head-members">
@ -140,7 +127,7 @@ function MembersDisplay({
<button
id="add-member"
onClick={() =>
navigate("/team/"+idTeam+"/addMember")
(window.location.href = `${BASE}/team/${idTeam}/addMember`)
}>
+
</button>
@ -162,9 +149,6 @@ function MemberDisplay({
idTeam: number
currentUserId: number
}) {
const fetcher = useAppFetcher()
const navigate = useNavigate()
return (
<div className="member">
<img
@ -173,19 +157,16 @@ function MemberDisplay({
alt="Photo de profile"
/>
<p>{member.user.name}</p>
<p>{member.role === MemberRole.COACH ? "Coach" : "Joueur"}</p>
<p>{member.role}</p>
<p>{member.user.email}</p>
{isCoach && currentUserId !== member.user.id && (
<button
id="delete"
onClick={() =>
confirm("Êtes-vous sûr de quitter cette équipe?")
? (fetcher.fetchAPI(
"team/"+idTeam+"/members/"+member.user.id,
{},
"DELETE"
)
confirm(
"Êtes-vous sûr de retirer ce membre de l'équipe?",
)
? (window.location.href = `${BASE}/team/${idTeam}/remove/${member.user.id}`)
: {}
}>
Retirer
@ -194,20 +175,10 @@ function MemberDisplay({
{isCoach && currentUserId == member.user.id && (
<button
id="delete"
onClick={async () => {
const res = confirm(
"Êtes-vous sûr de retirer ce membre de l'équipe?"
)
if (res) {
await fetcher.fetchAPI(
"team/" + idTeam + "/members/" + member.user.id,
{},
"DELETE"
)
navigate("/")
}
}
onClick={() =>
confirm("Êtes-vous sûr de quitter cette équipe?")
? (window.location.href = `${BASE}/team/${idTeam}/remove/${member.user.id}`)
: {}
}>
Quitter
</button>

@ -75,9 +75,11 @@
.tactic-card-actions * {
width: 30px;
pointer-events: all;
}
.tactic-card-actions {
pointer-events: none;
display: flex;
width: 100%;
height: 30px;
@ -86,10 +88,6 @@
align-content: center;
align-items: center;
justify-content: center;
* {
pointer-events: all;
}
}
.tactic-card-export-btn {

Loading…
Cancel
Save