Add two-level tab structure (Schedule/Baseline/Workday Exceptions), calendar view, enhanced list view with progress rings and initials avatars, split-pane gantt view, workday exception management with business day integration, and baseline snapshot comparison.
83 lines
1.8 KiB
TypeScript
Executable File
83 lines
1.8 KiB
TypeScript
Executable File
import { addDays, isWeekend, parseISO, format, isWithinInterval } from "date-fns"
|
|
import type { WorkdayExceptionData } from "./types"
|
|
|
|
function isExceptionDay(
|
|
date: Date,
|
|
exceptions: WorkdayExceptionData[]
|
|
): boolean {
|
|
return exceptions.some((ex) => {
|
|
const start = parseISO(ex.startDate)
|
|
const end = parseISO(ex.endDate)
|
|
return isWithinInterval(date, { start, end })
|
|
})
|
|
}
|
|
|
|
function isNonWorkday(
|
|
date: Date,
|
|
exceptions: WorkdayExceptionData[] = []
|
|
): boolean {
|
|
return isWeekend(date) || isExceptionDay(date, exceptions)
|
|
}
|
|
|
|
export function calculateEndDate(
|
|
startDate: string,
|
|
workdays: number,
|
|
exceptions: WorkdayExceptionData[] = []
|
|
): string {
|
|
if (workdays <= 0) return startDate
|
|
|
|
let current = parseISO(startDate)
|
|
let remaining = workdays
|
|
|
|
if (!isNonWorkday(current, exceptions)) {
|
|
remaining--
|
|
}
|
|
|
|
while (remaining > 0) {
|
|
current = addDays(current, 1)
|
|
if (!isNonWorkday(current, exceptions)) {
|
|
remaining--
|
|
}
|
|
}
|
|
|
|
return format(current, "yyyy-MM-dd")
|
|
}
|
|
|
|
export function countBusinessDays(
|
|
startDate: string,
|
|
endDate: string,
|
|
exceptions: WorkdayExceptionData[] = []
|
|
): number {
|
|
let current = parseISO(startDate)
|
|
const end = parseISO(endDate)
|
|
let count = 0
|
|
|
|
while (current <= end) {
|
|
if (!isNonWorkday(current, exceptions)) {
|
|
count++
|
|
}
|
|
current = addDays(current, 1)
|
|
}
|
|
|
|
return count
|
|
}
|
|
|
|
export function addBusinessDays(
|
|
date: string,
|
|
days: number,
|
|
exceptions: WorkdayExceptionData[] = []
|
|
): string {
|
|
let current = parseISO(date)
|
|
let remaining = Math.abs(days)
|
|
const direction = days >= 0 ? 1 : -1
|
|
|
|
while (remaining > 0) {
|
|
current = addDays(current, direction)
|
|
if (!isNonWorkday(current, exceptions)) {
|
|
remaining--
|
|
}
|
|
}
|
|
|
|
return format(current, "yyyy-MM-dd")
|
|
}
|