Bookability: show last-updated timestamp per date column
Backend adds valid_from to DateRateInfo and computes date_last_updated dict (max valid_from across categories per date). Frontend renders it as a small timestamp below the date in each column header — time only if today, date+time if older. Full ISO string in title tooltip. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9e6801482f
commit
7223ae9c30
2 changed files with 40 additions and 2 deletions
|
|
@ -52,12 +52,14 @@ class DateRateInfo(BaseModel):
|
|||
tariffs: List[TariffInfo]
|
||||
tariff_count: int
|
||||
occupancy: Optional[OccupancyInfo] = None
|
||||
valid_from: Optional[str] = None
|
||||
|
||||
|
||||
class RateMatrixResponse(BaseModel):
|
||||
categories: List[CategoryInfo]
|
||||
dates: List[str]
|
||||
matrix: Dict[str, Dict[str, DateRateInfo]]
|
||||
date_last_updated: Dict[str, Optional[str]] = {}
|
||||
|
||||
|
||||
# ============================================
|
||||
|
|
@ -229,19 +231,32 @@ async def get_rate_matrix(
|
|||
|
||||
# Preserve existing occupancy data
|
||||
existing_occ = matrix[cat_id][rate_date].occupancy
|
||||
vf = row.valid_from.isoformat() if row.valid_from else None
|
||||
|
||||
matrix[cat_id][rate_date] = DateRateInfo(
|
||||
rate_gross=float(row.rate_gross) if row.rate_gross else None,
|
||||
rate_net=float(row.rate_net) if row.rate_net else None,
|
||||
tariffs=tariffs_list,
|
||||
tariff_count=tariffs_data.get('tariff_count', len(tariffs_list)),
|
||||
occupancy=existing_occ
|
||||
occupancy=existing_occ,
|
||||
valid_from=vf
|
||||
)
|
||||
|
||||
# Per-date latest update time (max valid_from across all categories for each date)
|
||||
date_last_updated: Dict[str, Optional[str]] = {}
|
||||
for date_str in dates:
|
||||
latest = None
|
||||
for cat in categories:
|
||||
vf = matrix.get(cat.category_id, {}).get(date_str, DateRateInfo(tariffs=[], tariff_count=0)).valid_from
|
||||
if vf and (latest is None or vf > latest):
|
||||
latest = vf
|
||||
date_last_updated[date_str] = latest
|
||||
|
||||
return RateMatrixResponse(
|
||||
categories=categories,
|
||||
dates=dates,
|
||||
matrix=matrix
|
||||
matrix=matrix,
|
||||
date_last_updated=date_last_updated
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -37,12 +37,14 @@ interface DateRateInfo {
|
|||
tariffs: TariffInfo[]
|
||||
tariff_count: number
|
||||
occupancy?: OccupancyInfo
|
||||
valid_from?: string | null
|
||||
}
|
||||
|
||||
interface RateMatrixData {
|
||||
categories: CategoryInfo[]
|
||||
dates: string[]
|
||||
matrix: Record<string, Record<string, DateRateInfo>>
|
||||
date_last_updated?: Record<string, string | null>
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
|
@ -56,6 +58,16 @@ const formatDayOfWeek = (dateStr: string): string => {
|
|||
return date.toLocaleDateString('en-GB', { weekday: 'short' })
|
||||
}
|
||||
|
||||
const formatLastUpdated = (isoStr: string | null | undefined): string => {
|
||||
if (!isoStr) return ''
|
||||
const d = new Date(isoStr)
|
||||
const now = new Date()
|
||||
const isToday = d.toDateString() === now.toDateString()
|
||||
return isToday
|
||||
? d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })
|
||||
: d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short' }) + ' ' + d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })
|
||||
}
|
||||
|
||||
const isWeekend = (dateStr: string): boolean => {
|
||||
const date = new Date(dateStr + 'T00:00:00')
|
||||
const day = date.getDay()
|
||||
|
|
@ -422,6 +434,11 @@ const Bookability: React.FC = () => {
|
|||
>
|
||||
{refreshingDate === dateStr ? '...' : '↻'}
|
||||
</button>
|
||||
{data.date_last_updated?.[dateStr] && (
|
||||
<span style={styles.lastUpdated} title={`Rates last fetched: ${data.date_last_updated[dateStr]}`}>
|
||||
{formatLastUpdated(data.date_last_updated[dateStr])}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</th>
|
||||
))}
|
||||
|
|
@ -853,6 +870,12 @@ const styles: Record<string, React.CSSProperties> = {
|
|||
fontSize: '13px',
|
||||
fontWeight: 600,
|
||||
},
|
||||
lastUpdated: {
|
||||
fontSize: '9px',
|
||||
color: 'var(--text-mid)',
|
||||
opacity: 0.7,
|
||||
lineHeight: 1,
|
||||
},
|
||||
weekendHeader: {
|
||||
background: 'var(--body-bg)',
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue