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