Some checks failed
Deploy MyApp on Same Server / build-and-deploy (push) Failing after 1s
107 lines
3.9 KiB
TypeScript
107 lines
3.9 KiB
TypeScript
import { useState, useMemo, memo, useCallback } from 'react'
|
|
import { BarChart3 } from 'lucide-react'
|
|
import { LineChart, Panel } from '@/components/Charts'
|
|
import { TimeRangeSelector } from './TimeRangeSelector'
|
|
import { DataGap, detectDataGaps, normalizeTelemetryData } from '@/features/daily-report/utils'
|
|
import { TelemetryDto } from '@/lib/api'
|
|
import { EmptyState } from '@/components/common'
|
|
import { useTelemetryCharts } from '@/features/daily-report/hooks/useTelemetryCharts'
|
|
|
|
type ChartsTabProps = {
|
|
sortedTelemetry: TelemetryDto[]
|
|
dataGaps?: DataGap[]
|
|
}
|
|
|
|
export const ChartsTab = memo(function ChartsTab({
|
|
sortedTelemetry,
|
|
dataGaps = [],
|
|
}: ChartsTabProps) {
|
|
const [chartStartMinute, setChartStartMinute] = useState(0)
|
|
const [chartEndMinute, setChartEndMinute] = useState(1439)
|
|
|
|
const handleStartMinuteChange = useCallback((minute: number) => {
|
|
setChartStartMinute(minute)
|
|
}, [])
|
|
|
|
const handleEndMinuteChange = useCallback((minute: number) => {
|
|
setChartEndMinute(minute)
|
|
}, [])
|
|
|
|
// Normalize telemetry data
|
|
const normalizedTelemetry = useMemo(
|
|
() => normalizeTelemetryData(sortedTelemetry),
|
|
[sortedTelemetry]
|
|
)
|
|
|
|
// Filter by time range
|
|
const filteredTelemetry = useMemo(() => {
|
|
return normalizedTelemetry.filter(
|
|
t => t.minute >= chartStartMinute && t.minute <= chartEndMinute
|
|
)
|
|
}, [normalizedTelemetry, chartStartMinute, chartEndMinute])
|
|
|
|
// Detect data gaps in filtered data
|
|
const timestamps = useMemo(
|
|
() => filteredTelemetry.map(t => t.timestamp),
|
|
[filteredTelemetry]
|
|
)
|
|
|
|
const filteredDataGaps = useMemo(
|
|
() => detectDataGaps(timestamps, 30),
|
|
[timestamps]
|
|
)
|
|
|
|
// Build charts using custom hook
|
|
const { charts, chartLabels } = useTelemetryCharts({
|
|
filteredTelemetry,
|
|
filteredDataGaps,
|
|
})
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<TimeRangeSelector
|
|
startMinute={chartStartMinute}
|
|
endMinute={chartEndMinute}
|
|
onStartMinuteChange={handleStartMinuteChange}
|
|
onEndMinuteChange={handleEndMinuteChange}
|
|
totalRecords={filteredTelemetry.length}
|
|
dataGaps={dataGaps}
|
|
/>
|
|
|
|
{filteredTelemetry.length === 0 ? (
|
|
<EmptyState
|
|
icon={BarChart3}
|
|
title="دادهای موجود نیست"
|
|
message="دادهای برای این بازه زمانی موجود نیست"
|
|
/>
|
|
) : (
|
|
<div className="grid gap-6 md:grid-cols-2">
|
|
{charts.map(chart => (
|
|
<Panel key={chart.key} title={chart.title} id={`chart-${chart.key}`}>
|
|
<LineChart
|
|
labels={chartLabels}
|
|
series={[
|
|
{
|
|
label: chart.seriesLabel,
|
|
data: chart.data,
|
|
borderColor: chart.color,
|
|
backgroundColor: chart.bgColor,
|
|
fill: true,
|
|
},
|
|
]}
|
|
yAxisMin={chart.yAxisMin}
|
|
yAxisMax={chart.yAxisMax}
|
|
/>
|
|
</Panel>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}, (prevProps, nextProps) => {
|
|
// Custom comparison for better performance
|
|
return prevProps.sortedTelemetry.length === nextProps.sortedTelemetry.length &&
|
|
(prevProps.dataGaps?.length ?? 0) === (nextProps.dataGaps?.length ?? 0) &&
|
|
prevProps.sortedTelemetry[0]?.id === nextProps.sortedTelemetry[0]?.id
|
|
})
|