@ -92,6 +92,7 @@ import {
getStepNode ,
getStepNode ,
removeStepNode ,
removeStepNode ,
} from "../editor/StepsDomain"
} from "../editor/StepsDomain"
import CurtainLayout from "../components/CurtainLayout"
const ERROR_STYLE : CSSProperties = {
const ERROR_STYLE : CSSProperties = {
borderColor : "red" ,
borderColor : "red" ,
@ -186,7 +187,7 @@ function GuestModeEditor() {
const content = JSON . parse (
const content = JSON . parse (
localStorage . getItem (
localStorage . getItem (
GUEST_MODE_STEP_CONTENT_STORAGE_KEY +
GUEST_MODE_STEP_CONTENT_STORAGE_KEY +
stepId ,
stepId ,
) ! ,
) ! ,
)
)
const courtBounds =
const courtBounds =
@ -360,10 +361,7 @@ function UserModeEditor() {
const { name , courtType } = await infoResponse . json ( )
const { name , courtType } = await infoResponse . json ( )
const { root } = await treeResponse . json ( )
const { root } = await treeResponse . json ( )
if (
if ( infoResponse . status == 401 || treeResponse . status == 401 ) {
infoResponse . status == 401 ||
treeResponse . status == 401
) {
navigation ( "/login" )
navigation ( "/login" )
return
return
}
}
@ -372,7 +370,6 @@ function UserModeEditor() {
` tactics/ ${ tacticId } /steps/ ${ root . id } ` ,
` tactics/ ${ tacticId } /steps/ ${ root . id } ` ,
)
)
const contentResponse = await contentResponsePromise
const contentResponse = await contentResponsePromise
if ( contentResponse . status == 401 ) {
if ( contentResponse . status == 401 ) {
@ -485,18 +482,18 @@ export interface EditorViewProps {
}
}
function EditorPage ( {
function EditorPage ( {
tactic : { name , rootStepNode : initialStepsNode , courtType } ,
tactic : { name , rootStepNode : initialStepsNode , courtType } ,
currentStepId ,
currentStepId ,
setCurrentStepContent : setContent ,
setCurrentStepContent : setContent ,
currentStepContent : content ,
currentStepContent : content ,
saveState ,
saveState ,
onNameChange ,
onNameChange ,
selectStep ,
selectStep ,
onRemoveStep ,
onRemoveStep ,
onAddStep ,
onAddStep ,
courtRef ,
courtRef ,
} : EditorViewProps ) {
} : EditorViewProps ) {
const [ titleStyle , setTitleStyle ] = useState < CSSProperties > ( { } )
const [ titleStyle , setTitleStyle ] = useState < CSSProperties > ( { } )
const [ rootStepsNode , setRootStepsNode ] = useState ( initialStepsNode )
const [ rootStepsNode , setRootStepsNode ] = useState ( initialStepsNode )
@ -519,6 +516,8 @@ function EditorPage({
[ courtRef ] ,
[ courtRef ] ,
)
)
const [ editorContentCurtainWidth , setEditorContentCurtainWidth ] = useState ( 80 )
const relativePositions = useMemo ( ( ) = > {
const relativePositions = useMemo ( ( ) = > {
const courtBounds = courtRef . current ? . getBoundingClientRect ( )
const courtBounds = courtRef . current ? . getBoundingClientRect ( )
return courtBounds
return courtBounds
@ -635,15 +634,15 @@ function EditorPage({
/ >
/ >
) ,
) ,
! isFrozen &&
! isFrozen &&
( info . ballState === BallState . HOLDS_ORIGIN ||
( info . ballState === BallState . HOLDS_ORIGIN ||
info . ballState === BallState . PASSED_ORIGIN ) && (
info . ballState === BallState . PASSED_ORIGIN ) && (
< BallAction
< BallAction
key = { 2 }
key = { 2 }
onDrop = { ( ballBounds ) = > {
onDrop = { ( ballBounds ) = > {
doMoveBall ( ballBounds , player )
doMoveBall ( ballBounds , player )
} }
} }
/ >
/ >
) ,
) ,
]
]
} ,
} ,
[ content , courtRef , doMoveBall , previewAction ? . isInvalid , setContent ] ,
[ content , courtRef , doMoveBall , previewAction ? . isInvalid , setContent ] ,
@ -700,7 +699,15 @@ function EditorPage({
/ >
/ >
)
)
} ,
} ,
[ courtRef , content , relativePositions , courtBounds , renderAvailablePlayerActions , validatePlayerPosition , doRemovePlayer ] ,
[
courtRef ,
content ,
relativePositions ,
courtBounds ,
renderAvailablePlayerActions ,
validatePlayerPosition ,
doRemovePlayer ,
] ,
)
)
const doDeleteAction = useCallback (
const doDeleteAction = useCallback (
@ -771,10 +778,111 @@ function EditorPage({
onActionChanges = { ( action ) = >
onActionChanges = { ( action ) = >
doUpdateAction ( component , action , i )
doUpdateAction ( component , action , i )
}
}
renderDependency = { editorContentCurtainWidth }
/ >
/ >
)
)
} ) ,
} ) ,
[ courtRef , doDeleteAction , doUpdateAction ] ,
[ courtRef , doDeleteAction , doUpdateAction , editorContentCurtainWidth ] ,
)
const contentNode = (
< div id = "content-div" >
< div id = "racks" >
< PlayerRack
id = { "allies" }
objects = { allies }
setComponents = { setComponents }
courtRef = { courtRef }
/ >
< Rack
id = { "objects" }
objects = { objects }
onChange = { setObjects }
canDetach = { useCallback (
( div ) = >
overlaps (
courtBounds ( ) ,
div . getBoundingClientRect ( ) ,
) ,
[ courtBounds ] ,
) }
onElementDetached = { useCallback (
( r , e : RackedCourtObject ) = >
setContent ( ( content ) = >
placeObjectAt (
r . getBoundingClientRect ( ) ,
courtBounds ( ) ,
e ,
content ,
) ,
) ,
[ courtBounds , setContent ] ,
) }
render = { renderCourtObject }
/ >
< PlayerRack
id = { "opponents" }
objects = { opponents }
setComponents = { setComponents }
courtRef = { courtRef }
/ >
< / div >
< div id = "court-div" >
< div id = "court-div-bounds" >
< BasketCourt
components = { content . components }
courtImage = { < Court courtType = { courtType } / > }
courtRef = { courtRef }
previewAction = { previewAction }
renderComponent = { renderComponent }
renderActions = { renderActions }
/ >
< / div >
< / div >
< / div >
)
const stepsTreeNode = (
< EditorStepsTree
selectedStepId = { currentStepId }
root = { rootStepsNode }
onAddChildren = { useCallback (
async ( parent ) = > {
const addedNode = await onAddStep (
parent ,
computeTerminalState ( content , relativePositions ) ,
)
if ( addedNode == null ) {
console . error (
"could not add step : onAddStep returned null node" ,
)
return
}
selectStep ( addedNode . id )
setRootStepsNode ( ( root ) = >
addStepNode ( root , parent , addedNode ) ,
)
} ,
[ content , onAddStep , selectStep , relativePositions ] ,
) }
onRemoveNode = { useCallback (
async ( removed ) = > {
const isOk = await onRemoveStep ( removed )
selectStep ( getParent ( rootStepsNode , removed ) ! . id )
if ( isOk )
setRootStepsNode (
( root ) = > removeStepNode ( root , removed ) ! ,
)
} ,
[ rootStepsNode , onRemoveStep , selectStep ] ,
) }
onStepSelected = { useCallback (
( node ) = > selectStep ( node . id ) ,
[ selectStep ] ,
) }
/ >
)
)
return (
return (
@ -798,117 +906,31 @@ function EditorPage({
/ >
/ >
< / div >
< / div >
< div id = "topbar-right" >
< div id = "topbar-right" >
< button onClick = { ( ) = > setStepsTreeVisible ( ( b ) = > ! b ) } >
< button
id = { "show-steps-button" }
onClick = { ( ) = > setStepsTreeVisible ( ( b ) = > ! b ) } >
ETAPES
ETAPES
< / button >
< / button >
< / div >
< / div >
< / div >
< / div >
< div id = "editor-div" >
< div id = "editor-div" >
< div id = "content-div" >
{ isStepsTreeVisible ? (
< div id = "racks" >
< CurtainLayout
< PlayerRack
rightWidth = { editorContentCurtainWidth }
id = { "allies" }
onRightWidthChange = { setEditorContentCurtainWidth }
objects = { allies }
>
setComponents = { setComponents }
{ contentNode }
courtRef = { courtRef }
{ stepsTreeNode }
/ >
< / CurtainLayout >
) : (
< Rack
contentNode
id = { "objects" }
) }
objects = { objects }
onChange = { setObjects }
canDetach = { useCallback (
( div ) = >
overlaps (
courtBounds ( ) ,
div . getBoundingClientRect ( ) ,
) ,
[ courtBounds ] ,
) }
onElementDetached = { useCallback (
( r , e : RackedCourtObject ) = >
setContent ( ( content ) = >
placeObjectAt (
r . getBoundingClientRect ( ) ,
courtBounds ( ) ,
e ,
content ,
) ,
) ,
[ courtBounds , setContent ] ,
) }
render = { renderCourtObject }
/ >
< PlayerRack
id = { "opponents" }
objects = { opponents }
setComponents = { setComponents }
courtRef = { courtRef }
/ >
< / div >
< div id = "court-div" >
< div id = "court-div-bounds" >
< BasketCourt
components = { content . components }
courtImage = { < Court courtType = { courtType } / > }
courtRef = { courtRef }
previewAction = { previewAction }
renderComponent = { renderComponent }
renderActions = { renderActions }
/ >
< / div >
< / div >
< / div >
< EditorStepsTree
isVisible = { isStepsTreeVisible }
selectedStepId = { currentStepId }
root = { rootStepsNode }
onAddChildren = { useCallback (
async ( parent ) = > {
const addedNode = await onAddStep (
parent ,
computeTerminalState (
content ,
relativePositions ,
) ,
)
if ( addedNode == null ) {
console . error (
"could not add step : onAddStep returned null node" ,
)
return
}
selectStep ( addedNode . id )
setRootStepsNode ( ( root ) = >
addStepNode ( root , parent , addedNode ) ,
)
} ,
[ content , onAddStep , selectStep , relativePositions ] ,
) }
onRemoveNode = { useCallback (
async ( removed ) = > {
const isOk = await onRemoveStep ( removed )
selectStep ( getParent ( rootStepsNode , removed ) ! . id )
if ( isOk )
setRootStepsNode (
( root ) = > removeStepNode ( root , removed ) ! ,
)
} ,
[ rootStepsNode , onRemoveStep , selectStep ] ,
) }
onStepSelected = { useCallback (
( node ) = > selectStep ( node . id ) ,
[ selectStep ] ,
) }
/ >
< / div >
< / div >
< / div >
< / div >
)
)
}
}
interface EditorStepsTreeProps {
interface EditorStepsTreeProps {
isVisible : boolean
selectedStepId : number
selectedStepId : number
root : StepInfoNode
root : StepInfoNode
onAddChildren : ( parent : StepInfoNode ) = > void
onAddChildren : ( parent : StepInfoNode ) = > void
@ -917,19 +939,14 @@ interface EditorStepsTreeProps {
}
}
function EditorStepsTree ( {
function EditorStepsTree ( {
isVisible ,
selectedStepId ,
selectedStepId ,
root ,
root ,
onAddChildren ,
onAddChildren ,
onRemoveNode ,
onRemoveNode ,
onStepSelected ,
onStepSelected ,
} : EditorStepsTreeProps ) {
} : EditorStepsTreeProps ) {
return (
return (
< div
< div id = "steps-div" >
id = "steps-div"
style = { {
transform : isVisible ? "translateX(0)" : "translateX(100%)" ,
} } >
< StepsTree
< StepsTree
root = { root }
root = { root }
selectedStepId = { selectedStepId }
selectedStepId = { selectedStepId }
@ -952,12 +969,12 @@ interface PlayerRackProps {
}
}
function PlayerRack ( {
function PlayerRack ( {
id ,
id ,
objects ,
objects ,
setObjects ,
setObjects ,
courtRef ,
courtRef ,
setComponents ,
setComponents ,
} : PlayerRackProps ) {
} : PlayerRackProps ) {
const courtBounds = useCallback (
const courtBounds = useCallback (
( ) = > courtRef . current ! . getBoundingClientRect ( ) ,
( ) = > courtRef . current ! . getBoundingClientRect ( ) ,
[ courtRef ] ,
[ courtRef ] ,
@ -1011,15 +1028,15 @@ interface CourtPlayerArrowActionProps {
}
}
function CourtPlayerArrowAction ( {
function CourtPlayerArrowAction ( {
playerInfo ,
playerInfo ,
player ,
player ,
isInvalid ,
isInvalid ,
content ,
content ,
setContent ,
setContent ,
setPreviewAction ,
setPreviewAction ,
courtRef ,
courtRef ,
} : CourtPlayerArrowActionProps ) {
} : CourtPlayerArrowActionProps ) {
const courtBounds = useCallback (
const courtBounds = useCallback (
( ) = > courtRef . current ! . getBoundingClientRect ( ) ,
( ) = > courtRef . current ! . getBoundingClientRect ( ) ,
[ courtRef ] ,
[ courtRef ] ,