import {
Analytics,
BarChart,
CallReceived,
CloudOff,
EventBusy,
Schedule,
Speed,
Timeline,
TrendingUp,
Update,
} from '@mui/icons-material'
import {
Avatar,
Box,
Button,
Card,
Chip,
Container,
Grid,
List,
ListDivider,
ListItem,
ListItemContent,
Typography,
} from '@mui/joy'
import { useTheme } from '@mui/joy/styles'
import moment from 'moment'
import { useParams } from 'react-router-dom'
import { useLocalization } from '../../contexts/LocalizationContext'
import {
Line,
LineChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts'
import EmptyState from '../../components/common/EmptyState'
import { useThingHistory } from '../../queries/ThingQueries'
import LoadingComponent from '../components/Loading'
const ThingsHistory = () => {
const { id } = useParams()
const theme = useTheme()
const { fmt } = useLocalization()
const {
data,
error,
isLoading,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
refetch,
} = useThingHistory(id)
// Flatten all pages of history data
const thingsHistory = data?.pages.flatMap(page => page.res) || []
// Calculate analytics data
const calculateAnalytics = () => {
if (!thingsHistory.length) return []
// Calculate average update frequency
let avgUpdateFrequency = '--'
if (thingsHistory.length > 1) {
const oldestUpdate = moment(
thingsHistory[thingsHistory.length - 1].createdAt,
)
const newestUpdate = moment(thingsHistory[0].createdAt)
const totalDuration = newestUpdate.diff(oldestUpdate, 'hours')
const frequency = totalDuration / (thingsHistory.length - 1)
avgUpdateFrequency =
frequency < 1
? `${Math.round(frequency * 60)} minutes`
: frequency < 24
? `${Math.round(frequency)} hours`
: `${Math.round(frequency / 24)} days`
}
const lastUpdated = thingsHistory[0]
? moment(thingsHistory[0].updatedAt).fromNow()
: '--'
// Calculate update trend value
let updateTrend = '--'
if (thingsHistory.length >= 3) {
const diffs = thingsHistory
.map((h, i, arr) =>
i < arr.length - 1
? moment(h.createdAt).diff(arr[i + 1].createdAt, 'minutes')
: null,
)
.filter(d => d !== null)
const last = diffs[0]
const prev = diffs[1]
if (last > prev) updateTrend = 'Interval increasing'
else if (last < prev) updateTrend = 'Interval decreasing'
else updateTrend = 'Interval stable'
}
return [
{
icon: ,
text: 'Update Frequency',
subtext: `Every ${avgUpdateFrequency}`,
},
{
icon: ,
text: 'Last Updated',
subtext: lastUpdated,
},
{
icon: ,
text: 'Last Value',
subtext: thingsHistory[0]?.state ?? '--',
},
{
icon: ,
text: 'Update Trend',
subtext: updateTrend,
},
]
}
const analyticsData = calculateAnalytics()
const handleLoadMore = () => {
fetchNextPage()
}
const formatTimeDifference = (startDate, endDate) => {
const diffInMinutes = moment(startDate).diff(endDate, 'minutes')
let timeValue = diffInMinutes
let unit = 'minute'
if (diffInMinutes >= 60) {
const diffInHours = moment(startDate).diff(endDate, 'hours')
timeValue = diffInHours
unit = 'hour'
if (diffInHours >= 24) {
const diffInDays = moment(startDate).diff(endDate, 'days')
timeValue = diffInDays
unit = 'day'
}
}
return `${timeValue} ${unit}${timeValue !== 1 ? 's' : ''}`
}
// if loading show loading spinner:
if (isLoading) {
return
}
if (error || !thingsHistory || thingsHistory.length === 0) {
return (
: }
title={error ? "Couldn't load this history" : 'No history yet'}
description={
error
? 'We could not reach the server. Check your connection and try again.'
: "Each time this thing's value changes, the change is recorded here."
}
primaryAction={
error
? { label: 'Try again', onClick: () => refetch() }
: { label: 'Back to things', to: '/things' }
}
/>
)
}
return (
{/* Enhanced Analytics Header Section */}
Things Overview
{/* Statistics Cards Grid - Compact Design */}
{analyticsData.map((info, index) => (
{info.icon}
{info.text}
{info.subtext || '--'}
))}
{/* Chart Section Header */}
{thingsHistory.every(history => !isNaN(history.state)) &&
thingsHistory.length > 1 && (
Data Visualization
)}
{/* check if all the states are number the show it: */}
{thingsHistory.every(history => !isNaN(history.state)) &&
thingsHistory.length > 1 && (
{/* */}
fmt.dateTime(tick)}
/>
fmt.dateTime(label)}
/>
)}
{/* History Section Header */}
Change History
{thingsHistory.map((history, index) => (
{/* First Row: Status and Time Info */}
Updated
}
>
{fmt.dateTime(history.updatedAt)}
{/* Second Row: State Value */}
{history.state}
{/* Divider with time difference */}
{index < thingsHistory.length - 1 && (
{formatTimeDifference(
history.createdAt,
thingsHistory[index + 1].createdAt,
)}{' '}
before
)}
))}
{/* Load more Button */}
)
}
export default ThingsHistory