Parlellsession- Plan #35
|
|
@ -25,7 +25,7 @@ import {
|
||||||
swapAdjacentPhaseRuns,
|
swapAdjacentPhaseRuns,
|
||||||
reorderBlocksImmutableWithPlanLoc,
|
reorderBlocksImmutableWithPlanLoc,
|
||||||
reorderSectionBeforeParallelRunAsWholeGroup,
|
reorderSectionBeforeParallelRunAsWholeGroup,
|
||||||
reorderSectionAsFirstInParallelPhase,
|
reorderSectionAsFirstInParallelStream,
|
||||||
reorderBlockIntoParallelStreamEnd,
|
reorderBlockIntoParallelStreamEnd,
|
||||||
globalInsertBeforeIndexForParallelStreamEnd,
|
globalInsertBeforeIndexForParallelStreamEnd,
|
||||||
movePhaseRunUpByPhaseOrder,
|
movePhaseRunUpByPhaseOrder,
|
||||||
|
|
@ -744,7 +744,7 @@ export default function TrainingUnitSectionsEditor({
|
||||||
setDropSectionBand({ slot: sectionToSlot, phaseAboveSplitPo: Number(po) || 0 })
|
setDropSectionBand({ slot: sectionToSlot, phaseAboveSplitPo: Number(po) || 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPhaseBelowSplitDragOver = (e, po) => {
|
const onPhaseBelowSplitDragOver = (e, po, so) => {
|
||||||
if (!enableSectionDragReorder || !enableParallelPhaseControls) return
|
if (!enableSectionDragReorder || !enableParallelPhaseControls) return
|
||||||
if (!dtHasType(e, DND_TU_SECTION)) return
|
if (!dtHasType(e, DND_TU_SECTION)) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
@ -754,7 +754,10 @@ export default function TrainingUnitSectionsEditor({
|
||||||
} catch {
|
} catch {
|
||||||
/* ignore */
|
/* ignore */
|
||||||
}
|
}
|
||||||
setDropSectionBand({ slot: sectionToSlot, phaseBelowSplitPo: Number(po) || 0 })
|
setDropSectionBand({
|
||||||
|
slot: sectionToSlot,
|
||||||
|
phaseBelowSplit: { po: Number(po) || 0, so: Number(so) || 0 },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const applyParsedSectionDrop = (data) => {
|
const applyParsedSectionDrop = (data) => {
|
||||||
|
|
@ -824,7 +827,7 @@ export default function TrainingUnitSectionsEditor({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPhaseBelowSplitDrop = (e, po) => {
|
const onPhaseBelowSplitDrop = (e, po, so) => {
|
||||||
if (!enableSectionDragReorder || !enableParallelPhaseControls) return
|
if (!enableSectionDragReorder || !enableParallelPhaseControls) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
@ -843,6 +846,7 @@ export default function TrainingUnitSectionsEditor({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const targetPo = Number(po) || 0
|
const targetPo = Number(po) || 0
|
||||||
|
const targetSo = Number(so) || 0
|
||||||
const parsed = applyParsedSectionDrop(data)
|
const parsed = applyParsedSectionDrop(data)
|
||||||
if (!parsed) return
|
if (!parsed) return
|
||||||
|
|
||||||
|
|
@ -864,7 +868,7 @@ export default function TrainingUnitSectionsEditor({
|
||||||
|
|
||||||
const { fromSi } = parsed
|
const { fromSi } = parsed
|
||||||
patch((prev) => {
|
patch((prev) => {
|
||||||
let next = reorderSectionAsFirstInParallelPhase(prev, fromSi, targetPo)
|
let next = reorderSectionAsFirstInParallelStream(prev, fromSi, targetPo, targetSo)
|
||||||
if (enableParallelPhaseControls) next = afterSectionReorderParallelGuard(prev, next)
|
if (enableParallelPhaseControls) next = afterSectionReorderParallelGuard(prev, next)
|
||||||
return next
|
return next
|
||||||
})
|
})
|
||||||
|
|
@ -1383,7 +1387,7 @@ export default function TrainingUnitSectionsEditor({
|
||||||
dropSectionBand.beforeIdx === bx &&
|
dropSectionBand.beforeIdx === bx &&
|
||||||
!dropSectionBand.streamDrop &&
|
!dropSectionBand.streamDrop &&
|
||||||
dropSectionBand.phaseAboveSplitPo == null &&
|
dropSectionBand.phaseAboveSplitPo == null &&
|
||||||
dropSectionBand.phaseBelowSplitPo == null
|
!dropSectionBand.phaseBelowSplit
|
||||||
|
|
||||||
const streamChipDropActive = (po, so) =>
|
const streamChipDropActive = (po, so) =>
|
||||||
useStreamTagDropUx &&
|
useStreamTagDropUx &&
|
||||||
|
|
@ -1398,7 +1402,8 @@ export default function TrainingUnitSectionsEditor({
|
||||||
const phaseBelowSplitDnd =
|
const phaseBelowSplitDnd =
|
||||||
parallelPhaseOrder != null &&
|
parallelPhaseOrder != null &&
|
||||||
dropSectionBand?.slot === sectionToSlot &&
|
dropSectionBand?.slot === sectionToSlot &&
|
||||||
dropSectionBand?.phaseBelowSplitPo === parallelPhaseOrder
|
dropSectionBand?.phaseBelowSplit?.po === parallelPhaseOrder &&
|
||||||
|
dropSectionBand?.phaseBelowSplit?.so === activeParallelStream
|
||||||
|
|
||||||
const streamVisual =
|
const streamVisual =
|
||||||
enableParallelPhaseControls && pl?.phaseKind === 'parallel'
|
enableParallelPhaseControls && pl?.phaseKind === 'parallel'
|
||||||
|
|
@ -1622,22 +1627,6 @@ export default function TrainingUnitSectionsEditor({
|
||||||
+ Abschnitt in diesem Stream
|
+ Abschnitt in diesem Stream
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{enableSectionDragReorder ? (
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
'tu-section-dropband tu-phase-drop--below-split tu-section-dropband--phase-parallel-slot' +
|
|
||||||
(phaseBelowSplitDnd ? ' tu-section-dropband--active' : '')
|
|
||||||
}
|
|
||||||
title="Erster Abschnitt dieser Split-Phase (vorne einfügen)"
|
|
||||||
aria-label="Dropzone erster Abschnitt unter dem Split-Kopf"
|
|
||||||
onDragOver={(e) => onPhaseBelowSplitDragOver(e, parallelPhaseOrder)}
|
|
||||||
onDragLeave={(e) => {
|
|
||||||
if (e.currentTarget.contains(e.relatedTarget)) return
|
|
||||||
clearSectionDnD()
|
|
||||||
}}
|
|
||||||
onDrop={(e) => onPhaseBelowSplitDrop(e, parallelPhaseOrder)}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
<div
|
<div
|
||||||
role="tablist"
|
role="tablist"
|
||||||
aria-label={`Streams · Phase ${parallelPhaseOrder}`}
|
aria-label={`Streams · Phase ${parallelPhaseOrder}`}
|
||||||
|
|
@ -1797,6 +1786,39 @@ export default function TrainingUnitSectionsEditor({
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{enableSectionDragReorder ? (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'tu-section-dropband tu-phase-drop--below-split tu-section-dropband--phase-parallel-slot' +
|
||||||
|
sectionDropBandRegionClass(
|
||||||
|
list,
|
||||||
|
firstVisibleIdxActiveStream ?? firstGlobalIdxThisPhase ?? sIdx,
|
||||||
|
enableParallelPhaseControls
|
||||||
|
) +
|
||||||
|
(phaseBelowSplitDnd ? ' tu-section-dropband--active' : '')
|
||||||
|
}
|
||||||
|
title="Erster Abschnitt in dieser Gruppe (hier vorne einfügen)"
|
||||||
|
aria-label="Dropzone: erster Slot der gewählten Splitgruppe unter dem Split-Kopf"
|
||||||
|
onDragOver={(e) =>
|
||||||
|
onPhaseBelowSplitDragOver(
|
||||||
|
e,
|
||||||
|
parallelPhaseOrder,
|
||||||
|
activeParallelStream ?? 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onDragLeave={(e) => {
|
||||||
|
if (e.currentTarget.contains(e.relatedTarget)) return
|
||||||
|
clearSectionDnD()
|
||||||
|
}}
|
||||||
|
onDrop={(e) =>
|
||||||
|
onPhaseBelowSplitDrop(
|
||||||
|
e,
|
||||||
|
parallelPhaseOrder,
|
||||||
|
activeParallelStream ?? 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) : null}
|
) : null}
|
||||||
{!hideParallelSection ? (
|
{!hideParallelSection ? (
|
||||||
|
|
|
||||||
|
|
@ -905,6 +905,58 @@ export function reorderSectionAsFirstInParallelPhase(prev, fromI, phaseOrderInde
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Abschnitt als ersten Eintrag eines parallelen Streams setzen (planLoc wie erster Abschnitt dieses Streams, bzw. leerer Stream wie reorderBlockIntoParallelStreamEnd). */
|
||||||
|
export function reorderSectionAsFirstInParallelStream(prev, fromI, phaseOrderIndex, streamOrderIndex) {
|
||||||
|
const po = Number(phaseOrderIndex) || 0
|
||||||
|
const so = Number(streamOrderIndex) || 0
|
||||||
|
const len = prev?.length ?? 0
|
||||||
|
if (fromI < 0 || fromI >= len) return prev
|
||||||
|
|
||||||
|
const arr = [...prev]
|
||||||
|
const [moved] = arr.splice(fromI, 1)
|
||||||
|
|
||||||
|
const streamIdx = sectionIndicesForParallelStream(arr, po, so)
|
||||||
|
let insertAt
|
||||||
|
let headTpl
|
||||||
|
let skipFromIAdjust = false
|
||||||
|
|
||||||
|
if (streamIdx.length) {
|
||||||
|
const first = Math.min(...streamIdx)
|
||||||
|
headTpl = { ...arr[first].planLoc }
|
||||||
|
insertAt = first
|
||||||
|
} else {
|
||||||
|
const phaseIdx = indicesOfParallelPhase(arr, po)
|
||||||
|
if (!phaseIdx.length) {
|
||||||
|
const ml = moved?.planLoc
|
||||||
|
if (ml?.phaseKind !== 'parallel' || (ml.phaseOrderIndex ?? 0) !== po) return prev
|
||||||
|
headTpl = {
|
||||||
|
...ml,
|
||||||
|
parallelStreamOrderIndex: so,
|
||||||
|
streamTitle: null,
|
||||||
|
streamNotes: null,
|
||||||
|
streamAssignedTrainerProfileIds: null,
|
||||||
|
}
|
||||||
|
insertAt = Math.min(fromI, arr.length)
|
||||||
|
skipFromIAdjust = true
|
||||||
|
} else {
|
||||||
|
const ref = arr[phaseIdx[phaseIdx.length - 1]]
|
||||||
|
headTpl = {
|
||||||
|
...ref.planLoc,
|
||||||
|
parallelStreamOrderIndex: so,
|
||||||
|
streamTitle: null,
|
||||||
|
streamNotes: null,
|
||||||
|
streamAssignedTrainerProfileIds: null,
|
||||||
|
}
|
||||||
|
insertAt = phaseIdx[phaseIdx.length - 1] + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skipFromIAdjust && fromI < insertAt) insertAt -= 1
|
||||||
|
insertAt = Math.max(0, Math.min(insertAt, arr.length))
|
||||||
|
arr.splice(insertAt, 0, { ...moved, planLoc: { ...headTpl } })
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abschnitt ans Ende eines parallelen Streams setzen (planLoc wie dieser Stream).
|
* Abschnitt ans Ende eines parallelen Streams setzen (planLoc wie dieser Stream).
|
||||||
* Leerer Stream: Einfügen hinter den letzten Abschnitt der zugehörigen parallelen Phase, planLoc vom Referenz-Abschnitt mit angepasstem streamIndex.
|
* Leerer Stream: Einfügen hinter den letzten Abschnitt der zugehörigen parallelen Phase, planLoc vom Referenz-Abschnitt mit angepasstem streamIndex.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user