pull/114/head
maxime 1 year ago
parent 32b79ed5c4
commit 64e8362e53

@ -13,13 +13,18 @@ export interface EditableCourtBallProps extends CourtBallProps {
onRemove: () => void onRemove: () => void
} }
export function CourtBall({
export function CourtBall({ onPosValidated, ball, onRemove }: EditableCourtBallProps) { onPosValidated,
ball,
onRemove,
}: EditableCourtBallProps) {
const pieceRef = useRef<HTMLDivElement>(null) const pieceRef = useRef<HTMLDivElement>(null)
function courtBallPiece({ x, y }: Pos, function courtBallPiece(
pieceRef?: RefObject<HTMLDivElement>, { x, y }: Pos,
onKeyUp?: KeyboardEventHandler) { pieceRef?: RefObject<HTMLDivElement>,
onKeyUp?: KeyboardEventHandler,
) {
return ( return (
<div <div
className={"ball-div"} className={"ball-div"}
@ -47,16 +52,9 @@ export function CourtBall({ onPosValidated, ball, onRemove }: EditableCourtBallP
} }
position={NULL_POS} position={NULL_POS}
nodeRef={pieceRef}> nodeRef={pieceRef}>
{courtBallPiece( {courtBallPiece(ball.pos, pieceRef, (e) => {
ball.pos, if (e.key == "Delete") onRemove()
pieceRef, })}
(e) => {
if (e.key == "Delete") onRemove()
},
)}
</Draggable> </Draggable>
) )
} }

@ -77,7 +77,7 @@ export function placeObjectAt(
id: BALL_ID, id: BALL_ID,
pos, pos,
actions: [], actions: [],
frozen: false frozen: false,
} }
break break
} }
@ -200,9 +200,9 @@ export function moveComponent(
phantomIdx == 0 phantomIdx == 0
? origin ? origin
: getComponent( : getComponent(
originPathItems[phantomIdx - 1], originPathItems[phantomIdx - 1],
content.components, content.components,
) )
// detach the action from the screen target and transform it to a regular move action to the phantom. // detach the action from the screen target and transform it to a regular move action to the phantom.
content = updateComponent( content = updateComponent(
{ {
@ -210,18 +210,18 @@ export function moveComponent(
actions: playerBeforePhantom.actions.map((a) => actions: playerBeforePhantom.actions.map((a) =>
a.target === referent a.target === referent
? { ? {
...a, ...a,
segments: a.segments.toSpliced( segments: a.segments.toSpliced(
a.segments.length - 2, a.segments.length - 2,
1, 1,
{ {
...a.segments[a.segments.length - 1], ...a.segments[a.segments.length - 1],
next: component.id, next: component.id,
}, },
), ),
target: component.id, target: component.id,
type: ActionKind.MOVE, type: ActionKind.MOVE,
} }
: a, : a,
), ),
}, },
@ -234,9 +234,9 @@ export function moveComponent(
...component, ...component,
pos: isPhantom pos: isPhantom
? { ? {
type: "fixed", type: "fixed",
...newPos, ...newPos,
} }
: newPos, : newPos,
}, },
content, content,
@ -315,15 +315,15 @@ export function computeTerminalState(
content.components.filter((c) => c.type !== "phantom") as ( content.components.filter((c) => c.type !== "phantom") as (
| Player | Player
| CourtObject | CourtObject
)[] )[]
const componentsTargetedState = nonPhantomComponents.map((comp) => const componentsTargetedState = nonPhantomComponents.map((comp) =>
comp.type === "player" comp.type === "player"
? getPlayerTerminalState(comp, content, computedPositions) ? getPlayerTerminalState(comp, content, computedPositions)
: { : {
...comp, ...comp,
frozen: true, frozen: true,
}, },
) )
return { return {
@ -403,7 +403,12 @@ export function drainTerminalStateOnChildContent(
//filter out all frozen components that are not present on the parent's terminal state anymore //filter out all frozen components that are not present on the parent's terminal state anymore
childContent = { childContent = {
components: childContent.components.filter(comp => comp.type === "phantom" || (comp.frozen && tryGetComponent(comp.id, parentTerminalState.components))) components: childContent.components.filter(
(comp) =>
comp.type === "phantom" ||
(comp.frozen &&
tryGetComponent(comp.id, parentTerminalState.components)),
),
} }
for (const parentComponent of parentTerminalState.components) { for (const parentComponent of parentTerminalState.components) {

@ -156,7 +156,9 @@ function GuestModeEditor() {
) )
} }
const tacticName = localStorage.getItem(GUEST_MODE_TITLE_STORAGE_KEY) ?? "Nouvelle Tactique" const tacticName =
localStorage.getItem(GUEST_MODE_TITLE_STORAGE_KEY) ??
"Nouvelle Tactique"
const courtRef = useRef<HTMLDivElement>(null) const courtRef = useRef<HTMLDivElement>(null)
const [stepId, setStepId] = useState(ROOT_STEP_ID) const [stepId, setStepId] = useState(ROOT_STEP_ID)
@ -165,40 +167,45 @@ function GuestModeEditor() {
SaveStates.Guest, SaveStates.Guest,
useMemo( useMemo(
() => () =>
debounceAsync( debounceAsync(async (content: StepContent) => {
async (content: StepContent) => { localStorage.setItem(
localStorage.setItem( GUEST_MODE_STEP_CONTENT_STORAGE_KEY + stepId,
GUEST_MODE_STEP_CONTENT_STORAGE_KEY + stepId, JSON.stringify(content),
JSON.stringify(content), )
)
const stepsTree: StepInfoNode = JSON.parse( const stepsTree: StepInfoNode = JSON.parse(
localStorage.getItem( localStorage.getItem(
GUEST_MODE_STEP_ROOT_NODE_INFO_STORAGE_KEY, GUEST_MODE_STEP_ROOT_NODE_INFO_STORAGE_KEY,
)!, )!,
) )
await updateStepContents( await updateStepContents(
stepId, stepId,
stepsTree, stepsTree,
async (stepId) => { async (stepId) => {
const content = JSON.parse(localStorage.getItem( const content = JSON.parse(
GUEST_MODE_STEP_CONTENT_STORAGE_KEY + stepId, localStorage.getItem(
)!) GUEST_MODE_STEP_CONTENT_STORAGE_KEY +
const courtBounds = courtRef.current!.getBoundingClientRect() stepId,
const relativePositions = computeRelativePositions(courtBounds, content) )!,
return { content, relativePositions } )
}, const courtBounds =
async (stepId, content) => localStorage.setItem( courtRef.current!.getBoundingClientRect()
const relativePositions = computeRelativePositions(
courtBounds,
content,
)
return { content, relativePositions }
},
async (stepId, content) =>
localStorage.setItem(
GUEST_MODE_STEP_CONTENT_STORAGE_KEY + stepId, GUEST_MODE_STEP_CONTENT_STORAGE_KEY + stepId,
JSON.stringify(content), JSON.stringify(content),
), ),
) )
return SaveStates.Guest return SaveStates.Guest
}, }, 250),
250,
),
[stepId], [stepId],
), ),
) )
@ -281,7 +288,6 @@ function UserModeEditor() {
const tacticId = parseInt(idStr!) const tacticId = parseInt(idStr!)
const navigation = useNavigate() const navigation = useNavigate()
const courtRef = useRef<HTMLDivElement>(null) const courtRef = useRef<HTMLDivElement>(null)
const [stepId, setStepId] = useState(1) const [stepId, setStepId] = useState(1)
@ -301,12 +307,17 @@ function UserModeEditor() {
`tactics/${tacticId}/steps/${id}`, `tactics/${tacticId}/steps/${id}`,
) )
if (!response.ok) if (!response.ok)
throw new Error("Error when retrieving children content") throw new Error(
"Error when retrieving children content",
)
const content = await response.json() const content = await response.json()
const courtBounds = courtRef.current!.getBoundingClientRect() const courtBounds =
const relativePositions = computeRelativePositions(courtBounds, content) courtRef.current!.getBoundingClientRect()
const relativePositions = computeRelativePositions(
courtBounds,
content,
)
return { return {
content, content,
relativePositions, relativePositions,
@ -386,10 +397,7 @@ function UserModeEditor() {
) )
if (!response.ok) return if (!response.ok) return
setStepId(step) setStepId(step)
setStepContent( setStepContent(await response.json(), false)
await response.json(),
false,
)
}, },
[tacticId, setStepContent], [tacticId, setStepContent],
) )
@ -468,18 +476,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)
@ -508,7 +516,9 @@ function EditorPage({
const relativePositions = useMemo(() => { const relativePositions = useMemo(() => {
const courtBounds = courtRef.current?.getBoundingClientRect() const courtBounds = courtRef.current?.getBoundingClientRect()
return courtBounds ? computeRelativePositions(courtBounds, content) : new Map() return courtBounds
? computeRelativePositions(courtBounds, content)
: new Map()
}, [content, courtRef]) }, [content, courtRef])
// const setContent = useCallback( // const setContent = useCallback(
@ -655,15 +665,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, doMoveBall, previewAction?.isInvalid, setContent], [content, doMoveBall, previewAction?.isInvalid, setContent],
@ -946,13 +956,13 @@ interface EditorStepsTreeProps {
} }
function EditorStepsTree({ function EditorStepsTree({
isVisible, isVisible,
selectedStepId, selectedStepId,
root, root,
onAddChildren, onAddChildren,
onRemoveNode, onRemoveNode,
onStepSelected, onStepSelected,
}: EditorStepsTreeProps) { }: EditorStepsTreeProps) {
return ( return (
<div <div
id="steps-div" id="steps-div"
@ -981,12 +991,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],
@ -1040,15 +1050,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],
@ -1236,29 +1246,38 @@ function computeRelativePositions(courtBounds: DOMRect, content: StepContent) {
return relativePositionsCache return relativePositionsCache
} }
async function updateStepContents(stepId: number, async function updateStepContents(
stepsTree: StepInfoNode, stepId: number,
getStepContent: (stepId: number) => Promise<ComputedStepContent>, stepsTree: StepInfoNode,
setStepContent: (stepId: number, content: StepContent) => Promise<void>, getStepContent: (stepId: number) => Promise<ComputedStepContent>,
setStepContent: (stepId: number, content: StepContent) => Promise<void>,
) { ) {
async function updateSteps(
step: StepInfoNode,
content: StepContent,
async function updateSteps(step: StepInfoNode, content: StepContent, relativePositions: ComputedRelativePositions) { relativePositions: ComputedRelativePositions,
) {
const terminalStateContent = computeTerminalState( const terminalStateContent = computeTerminalState(
content, content,
relativePositions, relativePositions,
) )
const tasks = step.children.map(async (child) => { const tasks = step.children.map(async (child) => {
const { content: childContent, relativePositions: childRelativePositions } = await getStepContent(child.id) const {
content: childContent,
relativePositions: childRelativePositions,
} = await getStepContent(child.id)
const childUpdatedContent = drainTerminalStateOnChildContent( const childUpdatedContent = drainTerminalStateOnChildContent(
terminalStateContent, terminalStateContent,
childContent, childContent,
) )
if (childUpdatedContent) { if (childUpdatedContent) {
await setStepContent(child.id, childUpdatedContent) await setStepContent(child.id, childUpdatedContent)
await updateSteps(child, childUpdatedContent, childRelativePositions) await updateSteps(
child,
childUpdatedContent,
childRelativePositions,
)
} }
}) })

Loading…
Cancel
Save