+ {showExportPopup && (
+
+ )}
@@ -834,10 +853,15 @@ function EditorPage({
VISUALISER
+
diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx
index e99a32e..413e88b 100644
--- a/src/pages/HomePage.tsx
+++ b/src/pages/HomePage.tsx
@@ -1,9 +1,18 @@
import "../style/home/home.css"
import { useNavigate } from "react-router-dom"
-import { createContext, Dispatch, useContext, useEffect, useReducer } from "react"
+import {
+ createContext,
+ Dispatch,
+ useContext,
+ useEffect, useMemo,
+ useReducer,
+} from "react"
import { useAppFetcher } from "../App.tsx"
import { Visualizer } from "../components/Visualizer.tsx"
import BinSvg from "../assets/icon/bin.svg?react"
+import ExportSvg from "../assets/icon/export.svg?react"
+import ExportTacticPopup from "./popup/ExportTacticPopup.tsx"
+import { APITacticService } from "../service/APITacticService.ts"
interface Tactic {
id: number
@@ -22,26 +31,40 @@ interface Team {
enum HomePageStateActionKind {
UPDATE_TACTICS = "UPDATE_TACTICS",
UPDATE_TEAMS = "UPDATE_TEAMS",
+ SET_EXPORTING_TACTIC = "SET_EXPORTING_TACTIC",
INIT = "INIT"
}
-type HomePageStateAction = {
- type: HomePageStateActionKind.UPDATE_TACTICS,
+type HomePageStateAction =
+ | {
+ type: HomePageStateActionKind.UPDATE_TACTICS
tactics: Tactic[]
-} | {
- type: HomePageStateActionKind.UPDATE_TEAMS,
+}
+ | {
+ type: HomePageStateActionKind.UPDATE_TEAMS
teams: Team[]
-} | {
- type: HomePageStateActionKind.INIT,
+}
+ | {
+ type: HomePageStateActionKind.INIT
state: HomePageState
+} | {
+ type: HomePageStateActionKind.SET_EXPORTING_TACTIC,
+ tacticId: number | undefined
}
interface HomePageState {
tactics: Tactic[]
teams: Team[]
+ /**
+ * The home page displays a popup to export a certains tactic
+ */
+ exportingTacticId?: number
}
-function homePageStateReducer(state: HomePageState, action: HomePageStateAction): HomePageState {
+function homePageStateReducer(
+ state: HomePageState,
+ action: HomePageStateAction,
+): HomePageState {
switch (action.type) {
case HomePageStateActionKind.UPDATE_TACTICS:
return { ...state!, tactics: action.tactics }
@@ -49,13 +72,16 @@ function homePageStateReducer(state: HomePageState, action: HomePageStateAction)
case HomePageStateActionKind.UPDATE_TEAMS:
return { ...state!, teams: action.teams }
+ case HomePageStateActionKind.SET_EXPORTING_TACTIC:
+ return { ...state!, exportingTacticId: action.tacticId }
+
case HomePageStateActionKind.INIT:
return action.state
}
}
interface HomeStateContextMutable {
- state: HomePageState,
+ state: HomePageState
dispatch: Dispatch
}
@@ -66,8 +92,10 @@ function useHomeState() {
}
export default function HomePage() {
- const [state, dispatch] = useReducer(homePageStateReducer, { tactics: [], teams: [] })
-
+ const [state, dispatch] = useReducer(homePageStateReducer, {
+ tactics: [],
+ teams: [],
+ })
const navigate = useNavigate()
const fetcher = useAppFetcher()
@@ -80,18 +108,32 @@ export default function HomePage() {
navigate("/login")
return // if unauthorized
}
- type UserDataResponse = { teams: Team[], tactics: Tactic[] }
+ type UserDataResponse = { teams: Team[]; tactics: Tactic[] }
const { teams, tactics }: UserDataResponse = await response.json()
tactics.sort((a, b) => b.creationDate - a.creationDate)
- dispatch({ type: HomePageStateActionKind.INIT, state: { teams, tactics } })
+ dispatch({
+ type: HomePageStateActionKind.INIT,
+ state: { teams, tactics },
+ })
}
initUserData()
}, [fetcher, navigate])
+ const tacticExportService = useMemo(() =>
+ state.exportingTacticId ? new APITacticService(fetcher, state.exportingTacticId!) : null
+ , [fetcher, state.exportingTacticId],
+ )
return (
+ {tacticExportService && }
)
@@ -111,9 +153,7 @@ function Body() {
return (
)
}
@@ -133,9 +173,7 @@ function SideMenu({ width }: { width: number }) {
)
}
-function PersonalSpace({
- width,
- }: { width: number }) {
+function PersonalSpace({ width }: { width: number }) {
return (
+
navigate(`/tactic/${tactic.id}/edit`)}
+ >
navigate(`/tactic/${tactic.id}/edit`)}>
+ className={"tactic-card-preview"}>
{tactic.name}
-
{
- const response = await fetcher.fetchAPI(`tactics/${tactic.id}`, {}, "DELETE")
- if (!response.ok) {
- throw Error(`Cannot delete tactic ${tactic.id}!`)
- }
- dispatch({
- type: HomePageStateActionKind.UPDATE_TACTICS,
- tactics: tactics.filter(t => t.id !== tactic.id),
- })
- }}
- />
+
+ {
+ e.stopPropagation()
+ dispatch({
+ type: HomePageStateActionKind.SET_EXPORTING_TACTIC,
+ tacticId: tactic.id,
+ })
+ }}
+ />
+ {
+ e.stopPropagation()
+ const response = await fetcher.fetchAPI(
+ `tactics/${tactic.id}`,
+ {},
+ "DELETE",
+ )
+ if (!response.ok) {
+ throw Error(`Cannot delete tactic ${tactic.id}!`)
+ }
+ dispatch({
+ type: HomePageStateActionKind.UPDATE_TACTICS,
+ tactics: tactics.filter((t) => t.id !== tactic.id),
+ })
+ }}
+ />
+
+
+
)
@@ -258,9 +320,7 @@ function SetButtonTactic() {
function SetButtonTeam() {
const teams = useHomeState()!.state.teams
- const listTeam = teams.map((team) => (
-
- ))
+ const listTeam = teams.map((team) =>
)
return
{listTeam}
}
diff --git a/src/pages/NewTacticPage.tsx b/src/pages/NewTacticPage.tsx
index 68e4be1..8d83f43 100644
--- a/src/pages/NewTacticPage.tsx
+++ b/src/pages/NewTacticPage.tsx
@@ -3,7 +3,7 @@ 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 { CourtType } from "../model/tactic/TacticInfo.ts"
import { useCallback } from "react"
import { useAppFetcher, useUser } from "../App.tsx"
import { useNavigate } from "react-router-dom"
diff --git a/src/pages/VisualizerPage.tsx b/src/pages/VisualizerPage.tsx
index 9a66766..f27e7ad 100644
--- a/src/pages/VisualizerPage.tsx
+++ b/src/pages/VisualizerPage.tsx
@@ -1,15 +1,15 @@
import { ServiceError, TacticService } from "../service/MutableTacticService.ts"
import { useNavigate, useParams } from "react-router-dom"
-import { useCallback, useEffect, useMemo, useState } from "react"
import {
useVisualizer,
VisualizerState,
VisualizerStateActionKind,
} from "../visualizer/VisualizerState.ts"
+import { useCallback, useEffect, useMemo, useState } from "react"
import { getParent } from "../domains/StepsDomain.ts"
import { mapToParentContent } from "../domains/TacticContentDomains.ts"
import StepsTree from "../components/editor/StepsTree.tsx"
-import { StepInfoNode } from "../model/tactic/Tactic.ts"
+import { StepInfoNode } from "../model/tactic/TacticInfo.ts"
import SplitLayout from "../components/SplitLayout.tsx"
import { LocalStorageTacticService } from "../service/LocalStorageTacticService.ts"
import { APITacticService } from "../service/APITacticService.ts"
@@ -17,12 +17,13 @@ import { APITacticService } from "../service/APITacticService.ts"
import "../style/visualizer.css"
import { VisualizerFrame } from "../components/Visualizer.tsx"
import { useAppFetcher } from "../App.tsx"
+import ExportTacticPopup from "./popup/ExportTacticPopup.tsx"
export interface VisualizerPageProps {
guestMode: boolean
}
-export function VisualizerPage({ guestMode }: VisualizerPageProps) {
+export default function VisualizerPage({ guestMode }: VisualizerPageProps) {
const { tacticId: idStr } = useParams()
const navigate = useNavigate()
@@ -48,6 +49,8 @@ interface VisualizerService {
selectStep(step: number): Promise
openEditor(): Promise
+
+ getTacticService(): TacticService
}
interface ServedVisualizerPageProps {
@@ -101,7 +104,7 @@ function ServedVisualizerPage({
}
if (state === null) init()
- }, [service, state])
+ }, [dispatch, service, state])
const visualizerService: VisualizerService = useMemo(
() => ({
@@ -125,8 +128,12 @@ function ServedVisualizerPage({
async openEditor() {
openEditor()
},
+
+ getTacticService(): TacticService {
+ return service
+ },
}),
- [openEditor, service, state],
+ [dispatch, openEditor, service, state],
)
if (panicMessage) {
@@ -162,6 +169,8 @@ function VisualizerPageContent({
const [editorContentCurtainWidth, setEditorContentCurtainWidth] =
useState(80)
+ const [showExportPopup, setShowExportPopup] = useState(false)
+
const stepsTreeNode = (
+ {showExportPopup && (
+
+ )}