Summary table: split Rooms and D/S/A into separate columns per day

Match the original WP plugin layout — left cell has occupied count, vac,
and pickup controls; right cell has departs/stays/arrivals stacked
vertically, right-aligned, with delta indicators above them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-02 14:34:21 +00:00
parent 135f1f6cf0
commit 31fd73ce1e

View file

@ -439,10 +439,10 @@ function SummaryTable({ bookings, pickup, onPickupChange }: SummaryProps) {
</tr> </tr>
<tr> <tr>
{dates.map(d => ( {dates.map(d => (
<th key={d} colSpan={2} style={{ fontSize: '0.72rem', fontWeight: 400, background: '#1e2d42' }}> <>
<span style={{ padding: '0 0.5rem' }}>Occ</span> <th key={d + '-r'} style={{ fontSize: '0.72rem', fontWeight: 400, background: '#1e2d42', minWidth: '72px' }}>Rooms</th>
<span style={{ borderLeft: '1px solid rgba(255,255,255,0.15)', padding: '0 0.5rem' }}>D / S / A</span> <th key={d + '-d'} style={{ fontSize: '0.72rem', fontWeight: 400, background: '#1e2d42', minWidth: '56px', borderLeft: '1px solid rgba(255,255,255,0.1)' }}>D / S / A</th>
</th> </>
))} ))}
</tr> </tr>
</thead> </thead>
@ -471,13 +471,10 @@ function CatRows({ cat, dates, pickup, onPickupChange, isLast }: {
onPickupChange: (date: string, delta: number) => void onPickupChange: (date: string, delta: number) => void
isLast: boolean isLast: boolean
}) { }) {
const bbStyle = isLast ? '2px solid var(--card-border)' : undefined
return ( return (
<> <tr>
{/* Row 1: Occ + Departs */} <td className="col-label" style={{ borderBottom: bbStyle }}>{cat.name}</td>
<tr className="row-depart">
<td className="col-label" rowSpan={3} style={{ borderBottom: isLast ? '2px solid var(--card-border)' : undefined }}>
{cat.name}
</td>
{dates.map((date, di) => { {dates.map((date, di) => {
const d = cat.days[date] const d = cat.days[date]
const occupied = d.stays + d.arrivals const occupied = d.stays + d.arrivals
@ -490,46 +487,45 @@ function CatRows({ cat, dates, pickup, onPickupChange, isLast }: {
const dCanc = d.delta_cancelled || 0 const dCanc = d.delta_cancelled || 0
return ( return (
<td key={date} colSpan={2} rowSpan={3} <>
style={{ verticalAlign: 'top', paddingTop: '0.5rem', {/* Left cell: Rooms / vac / pickup controls */}
borderBottom: isLast ? '2px solid var(--card-border)' : undefined }}> <td key={date + '-r'} style={{ textAlign: 'center', verticalAlign: 'middle', borderBottom: bbStyle, padding: '0.4rem 0.3rem' }}>
{(dNew > 0 || dCanc > 0) && ( <div style={{ fontWeight: 700, fontSize: '1.1rem' }}>
<div style={{ display: 'flex', justifyContent: 'center', gap: '0.25rem', marginBottom: '2px' }}> {occupied}{pu > 0 && <span className="pickup-tag"> +{pu}</span>}
{dNew > 0 && <span className="delta-new">{dNew}</span>}
{dCanc > 0 && <span className="delta-canc">{dCanc}</span>}
</div> </div>
)} <div style={{ fontSize: '0.72rem', color: 'var(--text-mid)', marginBottom: '4px' }}>
<div style={{ textAlign: 'center', fontWeight: 700, fontSize: '1rem' }}>
{occupied}
{pu > 0 && <span className="pickup-tag"> +{pu}</span>}
</div>
<div style={{ textAlign: 'center', fontSize: '0.78rem', color: 'var(--text-mid)' }}>
{vacant} vac{pu > 0 && <span className="pickup-tag"> ({vacant - pu})</span>} {vacant} vac{pu > 0 && <span className="pickup-tag"> ({vacant - pu})</span>}
</div> </div>
<div className="pickup-ctrl"> <div className="pickup-ctrl">
<button className="pickup-btn" disabled={pu <= 0} <button className="pickup-btn" disabled={pu <= 0} onClick={() => onPickupChange(date, -1)}></button>
onClick={() => onPickupChange(date, -1)}></button>
<span className="pickup-num">{pu}</span> <span className="pickup-num">{pu}</span>
<button className="pickup-btn" disabled={pu >= vacant} <button className="pickup-btn" disabled={pu >= vacant}
title={d.pickup_hint > 0 ? `${d.pickup_hint} late pickup${d.pickup_hint > 1 ? 's' : ''} last ${getDayName(date)}` : 'No late pickups last week'} title={d.pickup_hint > 0 ? `${d.pickup_hint} late pickup${d.pickup_hint > 1 ? 's' : ''} last ${getDayName(date)}` : 'No late pickups last week'}
onClick={() => onPickupChange(date, 1)}>+</button> onClick={() => onPickupChange(date, 1)}>+</button>
</div> </div>
{/* D/S/A breakdown: sits to the right via colSpan trick — shown as sub-rows via CSS */} </td>
<div style={{ fontSize: '0.72rem', color: 'var(--text-mid)', textAlign: 'center', marginTop: '4px', borderTop: '1px dashed var(--card-border)', paddingTop: '3px' }}> {/* Right cell: D / S / A */}
<span style={{ color: '#c2502e' }}>{d.departs}d{prevPu > 0 && <span className="pickup-tag"> +{prevPu}</span>}</span> <td key={date + '-dsa'} style={{ verticalAlign: 'middle', borderLeft: '1px solid var(--card-border)', borderBottom: bbStyle, padding: '0.4rem 0.5rem 0.4rem 0.4rem', textAlign: 'right' }}>
{' / '} {(dNew > 0 || dCanc > 0) && (
<span style={{ color: '#1d6fb8' }}>{d.stays}s</span> <div style={{ marginBottom: '3px' }}>
{' / '} {dNew > 0 && <span className="delta-new">{dNew}</span>}
<span style={{ color: '#1a7a4a' }}>{d.arrivals}a{pu > 0 && <span className="pickup-tag"> +{pu}</span>}</span> {dCanc > 0 && <span className="delta-canc"> {dCanc}</span>}
</div>
)}
<div style={{ fontSize: '0.8rem', color: '#c2502e', fontWeight: 600 }}>
{d.departs}d{prevPu > 0 && <span className="pickup-tag"> +{prevPu}</span>}
</div>
<div style={{ fontSize: '0.8rem', color: '#1d6fb8', fontWeight: 600 }}>
{d.stays}s
</div>
<div style={{ fontSize: '0.8rem', color: '#1a7a4a', fontWeight: 600 }}>
{d.arrivals}a{pu > 0 && <span className="pickup-tag"> +{pu}</span>}
</div> </div>
</td> </td>
</>
) )
})} })}
</tr> </tr>
{/* Rows 2 & 3 are consumed by rowSpan — needed for tbody structure */}
<tr className="row-stay" />
<tr className={`row-arrive${isLast ? ' row-group-last' : ''}`} />
</>
) )
} }
@ -558,27 +554,31 @@ function TotalRows({ dates, cats, pickup }: {
dCanc += d.delta_cancelled || 0 dCanc += d.delta_cancelled || 0
} }
return ( return (
<td key={date} colSpan={2}> <>
<td key={date + '-r'} style={{ textAlign: 'center', verticalAlign: 'middle', padding: '0.4rem 0.3rem' }}>
<div style={{ fontWeight: 700, fontSize: '1.1rem' }}>
{occupied}{pu > 0 && <span className="pickup-tag"> +{pu}</span>}
</div>
<div style={{ fontSize: '0.72rem', color: 'var(--text-mid)' }}>
{vacant} vac{pu > 0 && <span className="pickup-tag"> ({vacant - pu})</span>}
</div>
</td>
<td key={date + '-dsa'} style={{ verticalAlign: 'middle', borderLeft: '1px solid var(--card-border)', padding: '0.4rem 0.5rem 0.4rem 0.4rem', textAlign: 'right' }}>
{(dNew > 0 || dCanc > 0) && ( {(dNew > 0 || dCanc > 0) && (
<div style={{ display: 'flex', justifyContent: 'center', gap: '0.25rem', marginBottom: '2px' }}> <div style={{ marginBottom: '3px' }}>
{dNew > 0 && <span className="delta-new">{dNew}</span>} {dNew > 0 && <span className="delta-new">{dNew}</span>}
{dCanc > 0 && <span className="delta-canc"> {dCanc}</span>} {dCanc > 0 && <span className="delta-canc"> {dCanc}</span>}
</div> </div>
)} )}
<div style={{ fontWeight: 700 }}> <div style={{ fontSize: '0.8rem', color: '#c2502e', fontWeight: 600 }}>
{occupied}{pu > 0 && <span className="pickup-tag"> +{pu}</span>} {departs}d{prevPu > 0 && <span className="pickup-tag"> +{prevPu}</span>}
</div> </div>
<div style={{ fontSize: '0.78rem', color: 'var(--text-mid)' }}> <div style={{ fontSize: '0.8rem', color: '#1d6fb8', fontWeight: 600 }}>{stays}s</div>
{vacant} vac{pu > 0 && <span className="pickup-tag"> ({vacant - pu})</span>} <div style={{ fontSize: '0.8rem', color: '#1a7a4a', fontWeight: 600 }}>
</div> {arrivals}a{pu > 0 && <span className="pickup-tag"> +{pu}</span>}
<div style={{ fontSize: '0.72rem', color: 'var(--text-mid)', borderTop: '1px dashed var(--card-border)', paddingTop: '3px', marginTop: '3px' }}>
<span style={{ color: '#c2502e' }}>{departs}d{prevPu > 0 && <span className="pickup-tag"> +{prevPu}</span>}</span>
{' / '}
<span style={{ color: '#1d6fb8' }}>{stays}s</span>
{' / '}
<span style={{ color: '#1a7a4a' }}>{arrivals}a{pu > 0 && <span className="pickup-tag"> +{pu}</span>}</span>
</div> </div>
</td> </td>
</>
) )
})} })}
</tr> </tr>