Fix sprint timezone bug and add auto-rollover
- Sprint end dates now treated as end-of-day (23:59:59) to handle timezone issues where sprints appeared empty before local midnight - Added auto-rollover: when a sprint ends, incomplete tasks automatically move to the next sprint, ended sprint marked as completed - Applied fix to both main page and BacklogView
This commit is contained in:
parent
bea107b4e9
commit
02d19a1afb
@ -359,6 +359,7 @@ export default function Home() {
|
||||
setCurrentUser,
|
||||
syncFromServer,
|
||||
isLoading,
|
||||
updateSprint,
|
||||
} = useTaskStore()
|
||||
|
||||
const [newTaskOpen, setNewTaskOpen] = useState(false)
|
||||
@ -583,12 +584,14 @@ export default function Home() {
|
||||
}, [selectedTask])
|
||||
|
||||
// Get current active sprint (across all projects)
|
||||
// Treat end date as end-of-day (23:59:59) to handle timezone issues
|
||||
const now = new Date()
|
||||
const currentSprint = sprints.find((s) =>
|
||||
s.status === 'active' &&
|
||||
new Date(s.startDate) <= now &&
|
||||
new Date(s.endDate) >= now
|
||||
)
|
||||
const currentSprint = sprints.find((s) => {
|
||||
if (s.status !== 'active') return false
|
||||
const sprintEnd = new Date(s.endDate)
|
||||
sprintEnd.setHours(23, 59, 59, 999)
|
||||
return new Date(s.startDate) <= now && sprintEnd >= now
|
||||
})
|
||||
|
||||
// Filter tasks to only show current sprint tasks in Kanban (from ALL projects)
|
||||
const sprintTasks = currentSprint
|
||||
@ -604,6 +607,51 @@ export default function Home() {
|
||||
return true
|
||||
})
|
||||
: []
|
||||
|
||||
// Auto-rollover: Move incomplete tasks from ended sprints to next sprint
|
||||
useEffect(() => {
|
||||
if (!authReady || sprints.length === 0) return
|
||||
|
||||
const now = new Date()
|
||||
const endedSprints = sprints.filter((s) => {
|
||||
if (s.status !== 'active') return false
|
||||
const sprintEnd = new Date(s.endDate)
|
||||
sprintEnd.setHours(23, 59, 59, 999)
|
||||
return sprintEnd < now
|
||||
})
|
||||
|
||||
if (endedSprints.length === 0) return
|
||||
|
||||
// Find next sprint (earliest start date that's in the future or active)
|
||||
const nextSprint = sprints
|
||||
.filter((s) => s.status === 'planning' || (s.status === 'active' && !endedSprints.find((e) => e.id === s.id)))
|
||||
.sort((a, b) => new Date(a.startDate).getTime() - new Date(b.startDate).getTime())[0]
|
||||
|
||||
if (!nextSprint) return
|
||||
|
||||
// Process each ended sprint
|
||||
endedSprints.forEach((endedSprint) => {
|
||||
const incompleteTasks = tasks.filter(
|
||||
(t) => t.sprintId === endedSprint.id && t.status !== 'done' && t.status !== 'canceled' && t.status !== 'archived'
|
||||
)
|
||||
|
||||
if (incompleteTasks.length > 0) {
|
||||
console.log(`Auto-rolling over ${incompleteTasks.length} tasks from "${endedSprint.name}" to "${nextSprint.name}"`)
|
||||
|
||||
// Move incomplete tasks to next sprint
|
||||
incompleteTasks.forEach((task) => {
|
||||
updateTask(task.id, { sprintId: nextSprint.id })
|
||||
})
|
||||
|
||||
// Mark ended sprint as completed
|
||||
updateSprint(endedSprint.id, { status: 'completed' })
|
||||
} else {
|
||||
// No incomplete tasks, just mark as completed
|
||||
updateSprint(endedSprint.id, { status: 'completed' })
|
||||
}
|
||||
})
|
||||
}, [authReady, sprints, tasks, updateTask, updateSprint])
|
||||
|
||||
const activeKanbanTask = activeKanbanTaskId
|
||||
? sprintTasks.find((task) => task.id === activeKanbanTaskId)
|
||||
: null
|
||||
|
||||
@ -306,13 +306,14 @@ export function BacklogView({ searchQuery = "" }: BacklogViewProps) {
|
||||
)
|
||||
|
||||
// Get current active sprint
|
||||
// Treat end date as end-of-day (23:59:59) to handle timezone issues
|
||||
const now = new Date()
|
||||
const currentSprint = sprints.find(
|
||||
(s) =>
|
||||
s.status === "active" &&
|
||||
new Date(s.startDate) <= now &&
|
||||
new Date(s.endDate) >= now
|
||||
)
|
||||
const currentSprint = sprints.find((s) => {
|
||||
if (s.status !== "active") return false
|
||||
const sprintEnd = new Date(s.endDate)
|
||||
sprintEnd.setHours(23, 59, 59, 999)
|
||||
return new Date(s.startDate) <= now && sprintEnd >= now
|
||||
})
|
||||
|
||||
// Get other sprints (not current)
|
||||
const otherSprints = sprints.filter((s) => s.id !== currentSprint?.id)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user