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

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

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

@ -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 [stepId, setStepId] = useState(ROOT_STEP_ID)
@ -165,40 +167,45 @@ function GuestModeEditor() {
SaveStates.Guest,
useMemo(
() =>
debounceAsync(
async (content: StepContent) => {
localStorage.setItem(
GUEST_MODE_STEP_CONTENT_STORAGE_KEY + stepId,
JSON.stringify(content),
)
debounceAsync(async (content: StepContent) => {
localStorage.setItem(
GUEST_MODE_STEP_CONTENT_STORAGE_KEY + stepId,
JSON.stringify(content),
)
const stepsTree: StepInfoNode = JSON.parse(
localStorage.getItem(
GUEST_MODE_STEP_ROOT_NODE_INFO_STORAGE_KEY,
)!,
)
const stepsTree: StepInfoNode = JSON.parse(
localStorage.getItem(
GUEST_MODE_STEP_ROOT_NODE_INFO_STORAGE_KEY,
)!,
)
await updateStepContents(
stepId,
stepsTree,
async (stepId) => {
const content = JSON.parse(localStorage.getItem(
GUEST_MODE_STEP_CONTENT_STORAGE_KEY + stepId,
)!)
const courtBounds = courtRef.current!.getBoundingClientRect()
const relativePositions = computeRelativePositions(courtBounds, content)
return { content, relativePositions }
},
async (stepId, content) => localStorage.setItem(
await updateStepContents(
stepId,
stepsTree,
async (stepId) => {
const content = JSON.parse(
localStorage.getItem(
GUEST_MODE_STEP_CONTENT_STORAGE_KEY +
stepId,
)!,
)
const courtBounds =
courtRef.current!.getBoundingClientRect()
const relativePositions = computeRelativePositions(
courtBounds,
content,
)
return { content, relativePositions }
},
async (stepId, content) =>
localStorage.setItem(
GUEST_MODE_STEP_CONTENT_STORAGE_KEY + stepId,
JSON.stringify(content),
),
)
)
return SaveStates.Guest
},
250,
),
return SaveStates.Guest
}, 250),
[stepId],
),
)
@ -281,7 +288,6 @@ function UserModeEditor() {
const tacticId = parseInt(idStr!)
const navigation = useNavigate()
const courtRef = useRef<HTMLDivElement>(null)
const [stepId, setStepId] = useState(1)
@ -301,12 +307,17 @@ function UserModeEditor() {
`tactics/${tacticId}/steps/${id}`,
)
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 courtBounds = courtRef.current!.getBoundingClientRect()
const relativePositions = computeRelativePositions(courtBounds, content)
const courtBounds =
courtRef.current!.getBoundingClientRect()
const relativePositions = computeRelativePositions(
courtBounds,
content,
)
return {
content,
relativePositions,
@ -386,10 +397,7 @@ function UserModeEditor() {
)
if (!response.ok) return
setStepId(step)
setStepContent(
await response.json(),
false,
)
setStepContent(await response.json(), false)
},
[tacticId, setStepContent],
)
@ -468,18 +476,18 @@ export interface EditorViewProps {
}
function EditorPage({
tactic: { name, rootStepNode: initialStepsNode, courtType },
currentStepId,
setCurrentStepContent: setContent,
currentStepContent: content,
saveState,
onNameChange,
selectStep,
onRemoveStep,
onAddStep,
courtRef,
}: EditorViewProps) {
tactic: { name, rootStepNode: initialStepsNode, courtType },
currentStepId,
setCurrentStepContent: setContent,
currentStepContent: content,
saveState,
onNameChange,
selectStep,
onRemoveStep,
onAddStep,
courtRef,
}: EditorViewProps) {
const [titleStyle, setTitleStyle] = useState<CSSProperties>({})
const [rootStepsNode, setRootStepsNode] = useState(initialStepsNode)
@ -508,7 +516,9 @@ function EditorPage({
const relativePositions = useMemo(() => {
const courtBounds = courtRef.current?.getBoundingClientRect()
return courtBounds ? computeRelativePositions(courtBounds, content) : new Map()
return courtBounds
? computeRelativePositions(courtBounds, content)
: new Map()
}, [content, courtRef])
// const setContent = useCallback(
@ -655,15 +665,15 @@ function EditorPage({
/>
),
!isFrozen &&
(info.ballState === BallState.HOLDS_ORIGIN ||
info.ballState === BallState.PASSED_ORIGIN) && (
<BallAction
key={2}
onDrop={(ballBounds) => {
doMoveBall(ballBounds, player)
}}
/>
),
(info.ballState === BallState.HOLDS_ORIGIN ||
info.ballState === BallState.PASSED_ORIGIN) && (
<BallAction
key={2}
onDrop={(ballBounds) => {
doMoveBall(ballBounds, player)
}}
/>
),
]
},
[content, doMoveBall, previewAction?.isInvalid, setContent],
@ -946,13 +956,13 @@ interface EditorStepsTreeProps {
}
function EditorStepsTree({
isVisible,
selectedStepId,
root,
onAddChildren,
onRemoveNode,
onStepSelected,
}: EditorStepsTreeProps) {
isVisible,
selectedStepId,
root,
onAddChildren,
onRemoveNode,
onStepSelected,
}: EditorStepsTreeProps) {
return (
<div
id="steps-div"
@ -981,12 +991,12 @@ interface PlayerRackProps {
}
function PlayerRack({
id,
objects,
setObjects,
courtRef,
setComponents,
}: PlayerRackProps) {
id,
objects,
setObjects,
courtRef,
setComponents,
}: PlayerRackProps) {
const courtBounds = useCallback(
() => courtRef.current!.getBoundingClientRect(),
[courtRef],
@ -1040,15 +1050,15 @@ interface CourtPlayerArrowActionProps {
}
function CourtPlayerArrowAction({
playerInfo,
player,
isInvalid,
content,
setContent,
setPreviewAction,
courtRef,
}: CourtPlayerArrowActionProps) {
playerInfo,
player,
isInvalid,
content,
setContent,
setPreviewAction,
courtRef,
}: CourtPlayerArrowActionProps) {
const courtBounds = useCallback(
() => courtRef.current!.getBoundingClientRect(),
[courtRef],
@ -1236,29 +1246,38 @@ function computeRelativePositions(courtBounds: DOMRect, content: StepContent) {
return relativePositionsCache
}
async function updateStepContents(stepId: number,
stepsTree: StepInfoNode,
getStepContent: (stepId: number) => Promise<ComputedStepContent>,
setStepContent: (stepId: number, content: StepContent) => Promise<void>,
async function updateStepContents(
stepId: number,
stepsTree: StepInfoNode,
getStepContent: (stepId: number) => Promise<ComputedStepContent>,
setStepContent: (stepId: number, content: StepContent) => Promise<void>,
) {
async function updateSteps(step: StepInfoNode, content: StepContent, relativePositions: ComputedRelativePositions) {
async function updateSteps(
step: StepInfoNode,
content: StepContent,
relativePositions: ComputedRelativePositions,
) {
const terminalStateContent = computeTerminalState(
content,
relativePositions,
)
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(
terminalStateContent,
childContent,
)
if (childUpdatedContent) {
await setStepContent(child.id, childUpdatedContent)
await updateSteps(child, childUpdatedContent, childRelativePositions)
await updateSteps(
child,
childUpdatedContent,
childRelativePositions,
)
}
})
@ -1271,4 +1290,4 @@ async function updateStepContents(stepId: number,
const startNode = getStepNode(stepsTree!, stepId)!
await updateSteps(startNode, content, relativePositions)
}
}

Loading…
Cancel
Save