1- import { Text , VStack , Badge , HStack , Card } from '@chakra-ui/react' ;
1+ import { Text , VStack , Badge , HStack , Card , Skeleton } from '@chakra-ui/react' ;
22import { CloudOff } from 'lucide-react' ;
33import { formatDistanceToNow } from 'date-fns' ;
44import type { Outage } from '@/api/types' ;
55
66interface OutagesListProps {
7- outages : Outage [ ] ;
7+ outages : Outage [ ] | undefined ;
8+ isLoading : boolean ;
89}
910
1011function formatDuration ( seconds ?: number | null ) : string {
@@ -18,8 +19,8 @@ function formatDuration(seconds?: number | null): string {
1819 return minutes > 0 ? `${ hours } h ${ minutes } m` : `${ hours } h` ;
1920}
2021
21- export function OutagesList ( { outages } : OutagesListProps ) {
22- if ( outages . length === 0 ) {
22+ export function OutagesList ( { outages, isLoading } : OutagesListProps ) {
23+ if ( outages ? .length === 0 ) {
2324 return (
2425 < VStack
2526 justify = 'center'
@@ -43,49 +44,54 @@ export function OutagesList({ outages }: OutagesListProps) {
4344 return text . charAt ( 0 ) . toUpperCase ( ) + text . slice ( 1 ) ;
4445 }
4546
47+ const sortedOutages = outages
48+ ? [ ...outages ] . sort ( ( a , b ) => {
49+ if ( ! a . endedTs && b . endedTs ) return - 1 ;
50+ if ( a . endedTs && ! b . endedTs ) return 1 ;
51+ return new Date ( b . startedTs ) . getTime ( ) - new Date ( a . startedTs ) . getTime ( ) ;
52+ } )
53+ : [ ] ;
54+
4655 return (
4756 < VStack gap = { 4 } align = 'stretch' >
48- { outages . slice ( 0 , 5 ) . map ( ( outage , index ) => (
49- < Card . Root key = { `${ outage . startedTs } -${ index } ` } size = { 'sm' } >
50- < Card . Body p = { 3 } >
51- < VStack gap = { 2 } align = 'stretch' >
52- < HStack justify = 'space-between' >
53- < Text fontSize = 'sm' fontWeight = 'medium' >
54- { capitalizeFirstLetter (
55- formatDistanceToNow ( new Date ( outage . startedTs ) , { addSuffix : true } )
56- ) }
57- </ Text >
58- < Badge colorPalette = { outage . endedTs ? 'green' : 'red' } size = 'sm' >
59- { outage . endedTs ? 'Resolved' : 'Ongoing' }
60- </ Badge >
61- </ HStack >
62- < HStack justify = 'space-between' >
63- < Text fontSize = 'sm' color = 'gray.600' >
64- Duration: { formatDuration ( outage . durationS ) }
65- </ Text >
66- < Text fontSize = 'sm' color = 'gray.600' >
67- Ended:{ ' ' }
68- { outage . endedTs
69- ? capitalizeFirstLetter (
70- formatDistanceToNow ( new Date ( outage . endedTs ) , { addSuffix : true } )
71- )
72- : 'Unknown' }
73- </ Text >
74- </ HStack >
75- { outage . lastError && (
76- < Text fontSize = 'sm' color = 'red.600' _dark = { { color : 'red.400' } } lineClamp = { 2 } >
77- { outage . lastError }
78- </ Text >
79- ) }
80- </ VStack >
81- </ Card . Body >
82- </ Card . Root >
57+ { sortedOutages . map ( ( outage , index ) => (
58+ < Skeleton loading = { isLoading } >
59+ < Card . Root key = { `${ outage . startedTs } -${ index } ` } size = { 'sm' } >
60+ < Card . Body p = { 3 } >
61+ < VStack gap = { 2 } align = 'stretch' >
62+ < HStack justify = 'space-between' >
63+ < Text fontSize = 'sm' fontWeight = 'medium' >
64+ { capitalizeFirstLetter (
65+ formatDistanceToNow ( new Date ( outage . startedTs ) , { addSuffix : true } )
66+ ) }
67+ </ Text >
68+ < Badge colorPalette = { outage . endedTs ? 'green' : 'red' } size = 'sm' >
69+ { outage . endedTs ? 'Resolved' : 'Ongoing' }
70+ </ Badge >
71+ </ HStack >
72+ < HStack justify = 'space-between' >
73+ < Text fontSize = 'sm' color = 'gray.600' >
74+ Duration: { formatDuration ( outage . durationS ) }
75+ </ Text >
76+ < Text fontSize = 'sm' color = 'gray.600' >
77+ Ended:{ ' ' }
78+ { outage . endedTs
79+ ? capitalizeFirstLetter (
80+ formatDistanceToNow ( new Date ( outage . endedTs ) , { addSuffix : true } )
81+ )
82+ : 'Unknown' }
83+ </ Text >
84+ </ HStack >
85+ { outage . lastError && (
86+ < Text fontSize = 'sm' color = 'red.600' _dark = { { color : 'red.400' } } lineClamp = { 2 } >
87+ { outage . lastError }
88+ </ Text >
89+ ) }
90+ </ VStack >
91+ </ Card . Body >
92+ </ Card . Root >
93+ </ Skeleton >
8394 ) ) }
84- { outages . length > 5 && (
85- < Text fontSize = 'sm' color = 'gray.500' textAlign = 'center' >
86- Showing 5 of { outages . length } recent outages
87- </ Text >
88- ) }
8995 </ VStack >
9096 ) ;
9197}
0 commit comments