11'use client' ;
2- import { MAX_PREVIEW_HOURS } from '@/constants' ;
32import { DownInterval , Severity } from '@/types/DownInterval' ;
43
4+ const DAYS = 90 ;
5+ const MS_PER_DAY = 24 * 60 * 60 * 1000 ;
6+
57export default function BlocksAndDateTimeline ( {
68 downIntervals,
79} : {
810 downIntervals : DownInterval [ ] ;
911} ) {
10- const timeline : ( Severity | undefined ) [ ] =
11- Array ( MAX_PREVIEW_HOURS ) . fill ( undefined ) ;
12+ const timeline : ( Severity | undefined ) [ ] = Array ( DAYS ) . fill ( undefined ) ;
1213
1314 const mapMillisToIndex = ( m : number ) : number => {
14- const now = new Date ( ) . valueOf ( ) ;
15- return Math . floor ( Math . max ( now - m , 0 ) / ( 3.6 * Math . pow ( 10 , 6 ) ) ) ;
15+ const now = Date . now ( ) ;
16+ return Math . floor ( Math . max ( now - m , 0 ) / MS_PER_DAY ) ;
1617 } ;
1718
19+ let totalDowntimeMs = 0 ;
20+ const ninetyDaysAgoMs = Date . now ( ) - DAYS * MS_PER_DAY ;
21+
1822 for ( const { severity, startTime, endTime } of downIntervals ) {
1923 const startMillis = new Date ( startTime ) . valueOf ( ) ;
20- const endMillis = endTime
21- ? new Date ( endTime ) . valueOf ( )
22- : new Date ( ) . valueOf ( ) + 3.6 * Math . pow ( 10 , 6 ) ;
23- const first = Math . min ( mapMillisToIndex ( startMillis ) , MAX_PREVIEW_HOURS ) ;
24- const last = mapMillisToIndex ( endMillis ) ;
25-
26- for ( let index = last ; index <= first ; index ++ ) {
27- timeline [ index ] = severity ;
24+ const endMillis = endTime ? new Date ( endTime ) . valueOf ( ) : Date . now ( ) ;
25+
26+ const first = Math . min ( mapMillisToIndex ( startMillis ) , DAYS - 1 ) ;
27+ const last = Math . max ( mapMillisToIndex ( endMillis ) , 0 ) ;
28+
29+ if ( first >= 0 && last < DAYS ) {
30+ for ( let index = last ; index <= first ; index ++ ) {
31+ if ( timeline [ index ] !== Severity . High ) {
32+ timeline [ index ] = severity ;
33+ }
34+ }
35+ }
36+
37+ const clampedStart = Math . max ( startMillis , ninetyDaysAgoMs ) ;
38+ const clampedEnd = Math . min ( endMillis , Date . now ( ) ) ;
39+
40+ if ( clampedEnd > clampedStart ) {
41+ totalDowntimeMs += clampedEnd - clampedStart ;
2842 }
2943 }
44+
45+ const totalWindowMs = DAYS * MS_PER_DAY ;
46+ const uptimePercentage = Math . max (
47+ 0 ,
48+ ( ( totalWindowMs - totalDowntimeMs ) / totalWindowMs ) * 100
49+ ) ;
50+
51+ const formattedUptime =
52+ uptimePercentage >= 99.9
53+ ? uptimePercentage . toFixed ( 2 )
54+ : uptimePercentage . toFixed ( 1 ) ;
55+
3056 timeline . reverse ( ) ;
3157
32- const TimelineBlock = ( { severity } : { severity : Severity | undefined } ) => {
58+ // Updated TimelineBlock accepts daysAgo to calculate the exact date
59+ const TimelineBlock = ( {
60+ severity,
61+ daysAgo
62+ } : {
63+ severity : Severity | undefined ;
64+ daysAgo : number ;
65+ } ) => {
66+ // Format the date for the tooltip
67+ const blockDate = new Date ( Date . now ( ) - daysAgo * MS_PER_DAY ) ;
68+ const dateString = blockDate . toLocaleDateString ( 'en-US' , {
69+ month : 'short' ,
70+ day : 'numeric' ,
71+ year : 'numeric'
72+ } ) ;
73+
74+ // Swap tooltip-info for tooltip-error, tooltip-warning, and tooltip-success
3375 switch ( severity ) {
3476 case Severity . High : {
3577 return (
3678 < span
37- className = "tooltip tooltip-info rounded-xl h-4 hover:h-5 transition-all ease-in-out bg-failure"
38- data-tip = " Total outage"
79+ className = "tooltip tooltip-error rounded-xl h-4 hover:h-5 transition-all ease-in-out bg-failure"
80+ data-tip = { ` ${ dateString } : Total Outage` }
3981 />
4082 ) ;
4183 }
4284 case Severity . Medium : {
4385 return (
44- // <div className="tooltip" data-tip="hello">
4586 < span
46- className = "tooltip tooltip-info rounded-xl h-8 hover:h-9 transition-all ease-in-out bg-warning"
47- data-tip = " Partial Outage"
87+ className = "tooltip tooltip-warning rounded-xl h-8 hover:h-9 transition-all ease-in-out bg-warning"
88+ data-tip = { ` ${ dateString } : Partial Outage` }
4889 />
49- // </div>
5090 ) ;
5191 }
5292 default : {
5393 return (
54- // <div className="tooltip" data-tip="hello">
5594 < span
56- className = "tooltip tooltip-info rounded-xl h-12 hover:h-13 transition-all ease-in-out bg-success"
57- data-tip = " Operational"
95+ className = "tooltip tooltip-success rounded-xl h-12 hover:h-13 transition-all ease-in-out bg-success"
96+ data-tip = { ` ${ dateString } : Operational` }
5897 />
59- // </div>
6098 ) ;
6199 }
62100 }
63101 } ;
64102
65103 return (
66104 < >
67- { /* Blocks and Date Mobile */ }
68- < div className = "sm-tablet:hidden" >
69- < p className = "text-gray-06 p" > Timeline</ p >
70- < div className = "h-2" />
105+ < div className = "flex flex-row justify-between items-end mb-2" >
106+ < p className = "text-gray-06 p1" > Timeline</ p >
107+ < p className = "p1 text-gray-06 font-medium" > { formattedUptime } % uptime</ p >
108+ </ div >
109+
110+ { /* Mobile: 30 Days */ }
111+ < div className = "sm-tablet:hidden flex flex-col w-full" >
71112 < div className = "grid grid-flow-col gap-1 justify-stretch h-13 items-end" >
72- { timeline . slice ( timeline . length - 24 ) . map ( ( elt , i ) => (
73- < TimelineBlock severity = { elt } key = { i } />
113+ { timeline . slice ( timeline . length - 30 ) . map ( ( elt , i ) => (
114+ // Calculate daysAgo: (total days in slice - 1) - current index
115+ < TimelineBlock severity = { elt } daysAgo = { 29 - i } key = { i } />
74116 ) ) }
75117 </ div >
76- < div className = "h-2" />
77-
78- < div className = "flex flex-row justify-end" >
79- < p className = "p3 text-gray-04" > Last 24 hours</ p >
118+ < div className = "flex flex-row justify-between items-center text-sm mt-3" >
119+ < p className = "p3 text-gray-04" > 30 days ago</ p >
120+ < p className = "p3 text-gray-04" > Today</ p >
80121 </ div >
81122 </ div >
82- { /* Blocks and Date small tablet */ }
83- < div className = "hidden sm-tablet:block md-desktop:hidden" >
84- < p className = "text-gray-06 p1" > Timeline</ p >
85- < div className = "h-2" />
123+
124+ { /* Tablet: 60 Days */ }
125+ < div className = "hidden sm-tablet:flex md-desktop:hidden flex-col w-full" >
86126 < div className = "grid grid-flow-col gap-1 justify-stretch h-13 items-end" >
87- { timeline . slice ( timeline . length - 48 ) . map ( ( elt , i ) => (
88- < TimelineBlock severity = { elt } key = { i } />
127+ { timeline . slice ( timeline . length - 60 ) . map ( ( elt , i ) => (
128+ < TimelineBlock severity = { elt } daysAgo = { 59 - i } key = { i } />
89129 ) ) }
90130 </ div >
91- < div className = "h-2" />
92-
93- < div className = "flex flex-row justify-end" >
94- < p className = "p1 text-gray-04" > Last 48 hours</ p >
131+ < div className = "flex flex-row justify-between items-center text-sm mt-3" >
132+ < p className = "p1 text-gray-04" > 60 days ago</ p >
133+ < p className = "p1 text-gray-04" > Today</ p >
95134 </ div >
96135 </ div >
97- { /* Blocks and date large */ }
98- < div className = "hidden md-desktop:flex flex-col" >
99- < p className = "text-gray-06 p1" > Timeline</ p >
100- < div className = "h-2" />
136+
137+ { /* Desktop: 90 Days */ }
138+ < div className = "hidden md-desktop:flex flex-col w-full" >
101139 < div className = "grid grid-flow-col gap-1 justify-stretch h-13 items-end" >
102140 { timeline . map ( ( elt , i ) => (
103- < TimelineBlock severity = { elt } key = { i } />
141+ < TimelineBlock severity = { elt } daysAgo = { 89 - i } key = { i } />
104142 ) ) }
105143 </ div >
106- < div className = "h-2" / >
107- < div className = "flex flex-row justify-end" >
108- < p className = "p1 text-gray-04" > Last 72 hours </ p >
144+ < div className = "flex flex-row justify-between items-center text-sm mt-3" >
145+ < p className = "p1 text-gray-04" > 90 days ago </ p >
146+ < p className = "p1 text-gray-04" > Today </ p >
109147 </ div >
110148 </ div >
111149 </ >
112150 ) ;
113- }
151+ }
0 commit comments