diff --git a/frontend-modern/src/components/Dashboard/GuestRow.tsx b/frontend-modern/src/components/Dashboard/GuestRow.tsx index b098f69..f2de400 100644 --- a/frontend-modern/src/components/Dashboard/GuestRow.tsx +++ b/frontend-modern/src/components/Dashboard/GuestRow.tsx @@ -205,6 +205,100 @@ function NetworkInfoCell(props: { ipAddresses: string[]; networkInterfaces: Netw ); } +// Backup status cell with Portal tooltip +function BackupStatusCell(props: { lastBackup: string | number | null | undefined }) { + const [showTooltip, setShowTooltip] = createSignal(false); + const [tooltipPos, setTooltipPos] = createSignal({ x: 0, y: 0 }); + + const info = createMemo(() => getBackupInfo(props.lastBackup)); + const config = createMemo(() => BACKUP_STATUS_CONFIG[info().status]); + + const handleMouseEnter = (e: MouseEvent) => { + const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); + setTooltipPos({ x: rect.left + rect.width / 2, y: rect.top }); + setShowTooltip(true); + }; + + const handleMouseLeave = () => { + setShowTooltip(false); + }; + + return ( + <> + + {/* Status icon */} + + + + + + + + + + + + + + + + {/* Status text */} + {info().status === 'fresh' && 'OK'} + {info().status === 'stale' && info().ageFormatted} + {info().status === 'critical' && info().ageFormatted} + {info().status === 'never' && 'Never'} + + + + +
+
+
+ Backup Status +
+ +
+
Last backup
+
+ {new Date(props.lastBackup!).toLocaleDateString(undefined, { + weekday: 'short', + year: 'numeric', + month: 'short', + day: 'numeric', + })} +
+
+ {new Date(props.lastBackup!).toLocaleTimeString()} +
+
+
+ {info().ageFormatted} ago +
+
+ +
+ No backup has ever been recorded for this guest. +
+
+
+
+
+
+ + ); +} + // Column configuration using the priority system export interface GuestColumnDef { id: string; @@ -870,26 +964,12 @@ export function GuestRow(props: GuestRowProps) { - {/* Backup Status - NEW */} + {/* Backup Status */}
- {(() => { - const info = getBackupInfo(props.guest.lastBackup); - const config = BACKUP_STATUS_CONFIG[info.status]; - return ( - - {info.status === 'fresh' && 'OK'} - {info.status === 'stale' && info.ageFormatted} - {info.status === 'critical' && info.ageFormatted} - {info.status === 'never' && 'Never'} - - ); - })()} + -