MDM/mdm-front/src/pages/DevicePage/components/DeviceStatsCards/DeviceStatsCards.tsx

144 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { memo } from 'react'
import { Battery, RotateCcw, ShieldCheck, Smartphone } from 'lucide-react'
import type { Device } from '../../types'
type DeviceStatsCardsProps = {
device: Device
}
function formatWorkTimeHours(worktime?: number | null) {
if (typeof worktime !== 'number') return '-'
const hours = worktime / 1000 / 60 / 60
if (hours < 1) {
const minutes = Math.round(worktime / 1000 / 60)
return `${minutes} мин`
}
if (hours < 10) {
return `${hours.toFixed(1)} ч`
}
return `${Math.round(hours)} ч`
}
function areStatsCardsPropsEqual(
prev: DeviceStatsCardsProps,
next: DeviceStatsCardsProps,
) {
return (
prev.device.battery === next.device.battery &&
prev.device.batteryMaxCapacity === next.device.batteryMaxCapacity &&
prev.device.chargeCycles === next.device.chargeCycles &&
prev.device.totalWorkTime === next.device.totalWorkTime &&
prev.device.mediumImpacts === next.device.mediumImpacts
)
}
export const DeviceStatsCards = memo(function DeviceStatsCards({
device,
}: DeviceStatsCardsProps) {
const batteryValue =
typeof device.battery === 'number'
? Math.max(0, Math.min(100, device.battery))
: null
const batterySize = 110
const batteryStroke = 12
const batteryRadius = (batterySize - batteryStroke) / 2
const batteryLength = 2 * Math.PI * batteryRadius
const batteryProgress = batteryValue !== null ? batteryValue / 100 : 0
const batteryDashOffset = batteryLength * (1 - batteryProgress)
function getBatteryColor(value: number | null) {
if (value === null) return 'var(--device-battery-progress-empty)'
if (value <= 20) return 'var(--device-battery-progress-danger)'
if (value <= 50) return 'var(--device-battery-progress-warning)'
return 'var(--device-battery-progress-strong)'
}
return (
<div className="device-card-stats">
<div className="device-card device-battery">
<h3>Аккумулятор</h3>
<div className="device-battery__content">
<div className="device-battery__circle">
<svg
className="device-battery__circle-svg"
viewBox={`0 0 ${batterySize} ${batterySize}`}
aria-hidden="true"
>
<g transform={`rotate(45 ${batterySize / 2} ${batterySize / 2})`}>
<circle
className="device-battery__circle-track"
cx={batterySize / 2}
cy={batterySize / 2}
r={batteryRadius}
strokeWidth={batteryStroke}
/>
{batteryValue !== null && (
<circle
className="device-battery__circle-progress"
cx={batterySize / 2}
cy={batterySize / 2}
r={batteryRadius}
strokeWidth={batteryStroke}
stroke={getBatteryColor(batteryValue)}
strokeDasharray={batteryLength}
strokeDashoffset={batteryDashOffset}
/>
)}
</g>
</svg>
<span>{batteryValue !== null ? `${batteryValue}%` : '-'}</span>
</div>
<div className="device-stats">
<div className="device-stats-card">
<Battery size={18} />
<div className="device-stats-text">
<span>Остаточная емкость</span>
<b>{device.batteryMaxCapacity ?? '-'}%</b>
</div>
</div>
<div className="device-stats-card">
<RotateCcw size={18} />
<div className="device-stats-text">
<span>Циклов перезарядки</span>
<b>{device.chargeCycles ?? '-'}</b>
</div>
</div>
<div className="device-stats-card">
<Smartphone size={18} />
<div className="device-stats-text">
<span>Общее время работы</span>
<b>{formatWorkTimeHours(device.totalWorkTime)}</b>
</div>
</div>
</div>
</div>
</div>
<div className="device-card device-impacts">
<ShieldCheck size={18} />
<div className="device-stats-text">
<span>Средних ударов</span>
<b>{device.mediumImpacts ?? '-'}</b>
</div>
</div>
</div>
)
}, areStatsCardsPropsEqual)