apply suggestions
continuous-integration/drone/push Build is passing Details

pull/107/head
maxime 1 year ago
parent 8fc8aa6917
commit 1d1ac1e088

@ -1,2 +1,2 @@
VITE_API_ENDPOINT=http://localhost:5254
VITE_BASE=
VITE_API_ENDPOINT=https://iqball.maxou.dev/api/dotnet-master
#VITE_API_ENDPOINT=http://localhost:5254

@ -5,6 +5,8 @@ module.exports = {
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",

1
.gitignore vendored

@ -14,7 +14,6 @@ dist-ssr
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo

@ -25,8 +25,9 @@ steps:
depends_on:
- "front CI"
commands:
- sed -Ei "s/VITE_BASE=/VITE_BASE=\\/${DRONE_BRANCH}/g" .env
- npm run build -- --base=/$DRONE_BRANCH
- # force to use the backend master branch if pushing on master
- echo "VITE_API_ENDPOINT=https://iqball.maxou.dev/api/dotnet-$([ "$DRONE_BRANCH" = master ] && echo master || cat .stage-backend-branch | tr / _)" > .env.STAGE
- npm run build -- --base=/$DRONE_BRANCH/ --mode STAGE
- mv dist/* /outputs

@ -6,4 +6,4 @@ export const API = import.meta.env.VITE_API_ENDPOINT
/**
* This constant defines the base app's endpoint.
*/
export const BASE = import.meta.env.VITE_BASE
export const BASE = import.meta.env.BASE_URL.slice(0, import.meta.env.BASE_URL.length - 1)

@ -1,9 +1,6 @@
import { API, BASE } from "./Constants"
import { API } from "./Constants"
import { getSession, saveSession, Session } from "./api/session.ts"
export function redirect(url: string) {
location.pathname = BASE + url
}
import { redirect } from "react-router-dom"
export async function fetchAPI(
url: string,
@ -62,11 +59,11 @@ async function handleResponse(
redirectIfNotAuth: boolean,
): Promise<Response> {
// if we provided a token but still unauthorized, the token has expired
console.log(response.status)
if (response.status == 401) {
if (!redirectIfNotAuth) return response
redirect("/login")
saveSession({ ...session, urlTarget: location.pathname })
return response
return redirect("/login")
}
const nextToken = response.headers.get("Next-Authorization")!

@ -99,20 +99,23 @@ interface EditorPageProps {
}
export default function EditorPage({ guestMode }: EditorPageProps) {
const [tactic, setTactic] = useState<TacticDto>()
const { tacticId: idStr } = useParams()
const id = guestMode ? -1 : parseInt(idStr!)
useEffect(() => {
const [tactic, setTactic] = useState<TacticDto | null>(() => {
if (guestMode) {
setTactic({
return {
id: -1,
courtType: "PLAIN",
content: '{"components": []}',
name: DEFAULT_TACTIC_NAME,
})
return
}
}
return null;
})
const { tacticId: idStr } = useParams()
const id = guestMode ? -1 : parseInt(idStr!)
useEffect(() => {
if (guestMode)
return
async function initialize() {
const infoResponse = fetchAPIGet(`tactics/${id}`)

@ -1,11 +1,11 @@
import "../style/home/home.css"
// import AccountSvg from "../assets/account.svg?react"
import { BASE } from "../Constants"
import { getSession } from "../api/session.ts"
import { fetchAPIGet, redirect } from "../Fetcher.ts"
import { useLayoutEffect, useState } from "react"
import { useNavigate } from "react-router-dom"
import { startTransition, useLayoutEffect, useState } from "react"
import { User } from "../model/User.ts"
import { fetchAPIGet } from "../Fetcher.ts"
interface Tactic {
id: number
@ -28,11 +28,15 @@ export default function HomePage() {
teams: [],
})
const navigate = useNavigate()
useLayoutEffect(() => {
const session = getSession()
if (!session.auth) {
redirect("/login")
startTransition(() => {
navigate("/login")
})
return
}
@ -42,7 +46,7 @@ export default function HomePage() {
}
getUser()
}, [])
}, [navigate])
tactics!.sort((a, b) => b.creationDate - a.creationDate)

@ -1,21 +1,22 @@
import { FormEvent, useRef, useState } from "react"
import { FormEvent, startTransition, useState } from "react"
import { BASE } from "../Constants.ts"
import { fetchAPI, redirect } from "../Fetcher.ts"
import { fetchAPI } from "../Fetcher.ts"
import { Failure } from "../api/failure.ts"
import { getSession, saveSession } from "../api/session.ts"
import "../style/form.css"
import { useNavigate } from "react-router-dom"
export default function LoginApp() {
const [errors, setErrors] = useState<Failure[]>([])
const emailRef = useRef<HTMLInputElement>(null)
const passwordRef = useRef<HTMLInputElement>(null)
const navigate = useNavigate()
async function handleSubmit(e: FormEvent) {
e.preventDefault()
const email = emailRef.current!.value
const password = passwordRef.current!.value
const { email, password } = Object.fromEntries(
new FormData(e.target as HTMLFormElement),
)
const response = await fetchAPI(
"auth/token",
@ -28,7 +29,9 @@ export default function LoginApp() {
const session = getSession()
const { token, expirationDate } = await response.json()
saveSession({ ...session, auth: { token, expirationDate }, urlTarget: undefined })
redirect(session.urlTarget ?? "/")
startTransition(() => {
navigate(session.urlTarget ?? "/")
})
return
}
@ -38,7 +41,7 @@ export default function LoginApp() {
{
type: "Non autorisé",
messages: [
"L'adresse email ou le mot de passe sont invalide.",
"L'adresse email ou le mot de passe sont invalides.",
],
},
])
@ -81,7 +84,6 @@ export default function LoginApp() {
<div className="form-group">
<label htmlFor="email">Email :</label>
<input
ref={emailRef}
type="text"
id="email"
name="email"
@ -90,7 +92,6 @@ export default function LoginApp() {
<label htmlFor="password">Mot de passe :</label>
<input
ref={passwordRef}
type="password"
id="password"
name="password"

@ -4,9 +4,10 @@ import "../style/new_tactic_panel.css"
import plainCourt from "../assets/court/full_court.svg"
import halfCourt from "../assets/court/half_court.svg"
import { CourtType } from "../model/tactic/Tactic.ts"
import { useCallback } from "react"
import { fetchAPI, redirect } from "../Fetcher.ts"
import { startTransition, useCallback } from "react"
import { fetchAPI } from "../Fetcher.ts"
import { getSession } from "../api/session.ts"
import { useNavigate } from "react-router-dom"
export const DEFAULT_TACTIC_NAME = "Nouvelle tactique"
@ -43,13 +44,18 @@ function CourtKindButton({
image: string
courtType: CourtType
}) {
const navigate = useNavigate()
return (
<div
className="court-kind-button"
onClick={useCallback(async () => {
// if user is not authenticated
if (!getSession().auth) {
redirect(`/tactic/edit-guest`)
startTransition(() => {
navigate(`/tactic/edit-guest`)
})
}
const response = await fetchAPI(
@ -62,8 +68,10 @@ function CourtKindButton({
)
const { id } = await response.json()
redirect(`/tactic/${id}/edit`)
}, [courtType])}>
startTransition(() => {
navigate(`/tactic/${id}/edit`)
})
}, [courtType, navigate])}>
<div className="court-kind-button-top">
<div className="court-kind-button-image-div">
<img

@ -1,10 +1,11 @@
import { FormEvent, useRef, useState } from "react"
import { FormEvent, startTransition, useRef, useState } from "react"
import { BASE } from "../Constants.ts"
import "../style/form.css"
import { Failure } from "../api/failure.ts"
import { fetchAPI, redirect } from "../Fetcher.ts"
import { fetchAPI } from "../Fetcher.ts"
import { getSession, saveSession } from "../api/session.ts"
import { useNavigate } from "react-router-dom"
export default function RegisterPage() {
const usernameField = useRef<HTMLInputElement>(null)
@ -14,6 +15,8 @@ export default function RegisterPage() {
const [errors, setErrors] = useState<Failure[]>([])
const navigate = useNavigate()
async function handleSubmit(e: FormEvent) {
e.preventDefault()
@ -44,7 +47,9 @@ export default function RegisterPage() {
const { token, expirationDate } = await response.json()
const session = getSession()
saveSession({ ...session, auth: { token, expirationDate }, urlTarget: undefined })
redirect(session.urlTarget ?? "/")
startTransition(() => {
navigate(session.urlTarget ?? "/")
})
return
}

@ -2,22 +2,22 @@
// import "../style/visualizer.css"
// import Court from "../assets/court/full_court.svg"
//
// // export default function Visualizer({ id, name }: { id: number; name: string }) {
// // const [style, setStyle] = useState<CSSProperties>({})
// //
// // return (
// // <div id="main">
// // <div id="topbar">
// // <h1>{name}</h1>
// // </div>
// // <div id="court-container">
// // <img
// // id="court"
// // src={Court}
// // style={style}
// // alt="Basketball Court"
// // />
// // </div>
// // </div>
// // )
// // }
// export default function Visualizer({ id, name }: { id: number; name: string }) {
// const [style, setStyle] = useState<CSSProperties>({})
//
// return (
// <div id="main">
// <div id="topbar">
// <h1>{name}</h1>
// </div>
// <div id="court-container">
// <img
// id="court"
// src={Court}
// style={style}
// alt="Basketball Court"
// />
// </div>
// </div>
// )
// }

@ -1,8 +1,9 @@
import AccountSvg from "../../assets/account.svg?react"
import "../../style/template/header.css"
import { useEffect, useState } from "react"
import { fetchAPIGet, redirect } from "../../Fetcher.ts"
import { startTransition, useEffect, useState } from "react"
import { fetchAPIGet } from "../../Fetcher.ts"
import { getSession, saveSession } from "../../api/session.ts"
import { useNavigate } from "react-router-dom"
export function Header() {
const session = getSession()
@ -10,6 +11,8 @@ export function Header() {
session.username ?? null,
)
const navigate = useNavigate()
useEffect(() => {
async function loadUsername() {
const response = await fetchAPIGet("user", false)
@ -36,7 +39,7 @@ export function Header() {
<p
id="iqball"
className="clickable"
onClick={() => redirect("/")}>
onClick={() => startTransition(() => navigate("/"))}>
IQBall
</p>
</div>
@ -46,14 +49,19 @@ export function Header() {
id="clickable-header-right"
onClick={() => {
if (username) {
redirect("/settings")
startTransition(() => {
navigate("/settings")
})
return
}
saveSession({
...session,
urlTarget: location.pathname,
})
redirect("/login")
startTransition(() => {
navigate("/login")
})
}}>
{/* <AccountSvg id="img-account" /> */}
<AccountSvg id="img-account" />

@ -13,8 +13,6 @@ export default defineConfig({
cssInjectedByJsPlugin({
relativeCSSInjection: true,
}),
svgr({
include: "**/*.svg?react",
}),
svgr(),
],
})

Loading…
Cancel
Save