Add DOW-aligned LY toggle to directors forecast worksheet and report
Checkbox in the header switches between 364-day same-weekday comparison and same calendar-date last year. Default remains DOW-aligned. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2e8a908f05
commit
9530125509
4 changed files with 33 additions and 20 deletions
|
|
@ -38,8 +38,8 @@ export function getWeeklyActual(weekEnding: string): Promise<WeeklyActualData> {
|
|||
|
||||
// ── Directors Forecast API ──────────────────────────────────────────────────
|
||||
|
||||
export function dfGetWorksheet(year: number, month: number): Promise<WorksheetData> {
|
||||
return request<WorksheetData>(`/directors-forecast/worksheet/${year}/${month}`)
|
||||
export function dfGetWorksheet(year: number, month: number, dowAlign = true): Promise<WorksheetData> {
|
||||
return request<WorksheetData>(`/directors-forecast/worksheet/${year}/${month}?dow_align=${dowAlign}`)
|
||||
}
|
||||
|
||||
export function dfSaveWorksheet(year: number, month: number, data: { pickup_avg_rate: number; overrides: object[] }): Promise<{ ok: boolean }> {
|
||||
|
|
@ -48,8 +48,8 @@ export function dfSaveWorksheet(year: number, month: number, data: { pickup_avg_
|
|||
})
|
||||
}
|
||||
|
||||
export function dfGetReport(year: number, month: number): Promise<ForecastReportData> {
|
||||
return request<ForecastReportData>(`/directors-forecast/report/${year}/${month}`)
|
||||
export function dfGetReport(year: number, month: number, dowAlign = true): Promise<ForecastReportData> {
|
||||
return request<ForecastReportData>(`/directors-forecast/report/${year}/${month}?dow_align=${dowAlign}`)
|
||||
}
|
||||
|
||||
export function dfSaveSnapshot(year: number, month: number, data: object) {
|
||||
|
|
|
|||
|
|
@ -449,6 +449,11 @@ html, body, #root {
|
|||
}
|
||||
.df-nav-btn:hover { background: var(--body-bg); }
|
||||
.df-month-label { font-weight: 600; font-size: 14px; min-width: 140px; text-align: center; }
|
||||
.df-dow-toggle {
|
||||
display: flex; align-items: center; gap: 6px; margin-left: auto;
|
||||
font-size: 12px; color: var(--text-muted); cursor: pointer; user-select: none;
|
||||
}
|
||||
.df-dow-toggle input[type="checkbox"] { cursor: pointer; accent-color: var(--gold); }
|
||||
.df-tabs { display: flex; gap: 4px; }
|
||||
.df-tab {
|
||||
padding: 5px 14px; border-radius: 4px; border: 1px solid var(--border);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ type DayOverride = {
|
|||
|
||||
// ── Worksheet tab ─────────────────────────────────────────────────────────────
|
||||
|
||||
function WorksheetTab({ year, month }: { year: number; month: number }) {
|
||||
function WorksheetTab({ year, month, dowAlign }: { year: number; month: number; dowAlign: boolean }) {
|
||||
const { user } = useAuth()
|
||||
const canEdit = can(user, 'edit')
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ function WorksheetTab({ year, month }: { year: number; month: number }) {
|
|||
const load = useCallback(async () => {
|
||||
setLoading(true); setError(null)
|
||||
try {
|
||||
const d: WorksheetData = await dfGetWorksheet(year, month)
|
||||
const d: WorksheetData = await dfGetWorksheet(year, month, dowAlign)
|
||||
setData(d)
|
||||
setRate(String(d.session.pickup_avg_rate ?? 135))
|
||||
const ovrs: Record<string, DayOverride> = {}
|
||||
|
|
@ -73,7 +73,7 @@ function WorksheetTab({ year, month }: { year: number; month: number }) {
|
|||
setDirty(false)
|
||||
} catch { setError('Failed to load worksheet data.') }
|
||||
finally { setLoading(false) }
|
||||
}, [year, month])
|
||||
}, [year, month, dowAlign])
|
||||
|
||||
useEffect(() => { load() }, [load])
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ function VarCell({ a, b }: { a: number; b: number }) {
|
|||
return <td className={v >= 0 ? 'df-pos' : 'df-neg'}>{v >= 0 ? '+' : ''}{fmtCcy(v)}</td>
|
||||
}
|
||||
|
||||
function ReportTab({ year, month }: { year: number; month: number }) {
|
||||
function ReportTab({ year, month, dowAlign }: { year: number; month: number; dowAlign: boolean }) {
|
||||
const { user } = useAuth()
|
||||
const canEdit = can(user, 'edit')
|
||||
|
||||
|
|
@ -299,10 +299,10 @@ function ReportTab({ year, month }: { year: number; month: number }) {
|
|||
|
||||
const load = useCallback(async () => {
|
||||
setLoading(true); setError(null)
|
||||
try { setData(await dfGetReport(year, month)) }
|
||||
try { setData(await dfGetReport(year, month, dowAlign)) }
|
||||
catch { setError('Failed to load report data.') }
|
||||
finally { setLoading(false) }
|
||||
}, [year, month])
|
||||
}, [year, month, dowAlign])
|
||||
|
||||
useEffect(() => { load() }, [load])
|
||||
|
||||
|
|
@ -494,14 +494,19 @@ type Tab = 'worksheet' | 'report'
|
|||
export default function DirectorsForecast() {
|
||||
useFrameViewport('desktop')
|
||||
const now = new Date()
|
||||
const [year, setYear] = useState(now.getFullYear())
|
||||
const [month, setMonth] = useState(now.getMonth() + 1)
|
||||
const [tab, setTab] = useState<Tab>('worksheet')
|
||||
const [year, setYear] = useState(now.getFullYear())
|
||||
const [month, setMonth] = useState(now.getMonth() + 1)
|
||||
const [tab, setTab] = useState<Tab>('worksheet')
|
||||
const [dowAlign, setDowAlign] = useState(true)
|
||||
|
||||
return (
|
||||
<div className="df-root">
|
||||
<div className="df-header">
|
||||
<MonthNav year={year} month={month} onChange={(y, m) => { setYear(y); setMonth(m) }} />
|
||||
<label className="df-dow-toggle">
|
||||
<input type="checkbox" checked={dowAlign} onChange={e => setDowAlign(e.target.checked)} />
|
||||
DOW-aligned LY
|
||||
</label>
|
||||
<div className="df-tabs">
|
||||
<button className={`df-tab${tab === 'worksheet' ? ' active' : ''}`} onClick={() => setTab('worksheet')}>
|
||||
Worksheet
|
||||
|
|
@ -513,8 +518,8 @@ export default function DirectorsForecast() {
|
|||
</div>
|
||||
|
||||
{tab === 'worksheet'
|
||||
? <WorksheetTab key={`ws-${year}-${month}`} year={year} month={month} />
|
||||
: <ReportTab key={`rp-${year}-${month}`} year={year} month={month} />}
|
||||
? <WorksheetTab key={`ws-${year}-${month}-${dowAlign}`} year={year} month={month} dowAlign={dowAlign} />
|
||||
: <ReportTab key={`rp-${year}-${month}-${dowAlign}`} year={year} month={month} dowAlign={dowAlign} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue