9 changed files with 137 additions and 77 deletions
@ -0,0 +1,86 @@ |
|||
import React from 'react'; |
|||
import { |
|||
PlugZapIcon, |
|||
BatteryFullIcon, |
|||
BatteryMediumIcon, |
|||
BatteryLowIcon, |
|||
} from 'lucide-react'; |
|||
import { Subtle } from "@components/UI/Typography/Subtle.tsx"; |
|||
|
|||
interface DeviceMetrics { |
|||
batteryLevel?: number | null; |
|||
voltage?: number | null; |
|||
} |
|||
|
|||
interface BatteryStatusProps { |
|||
deviceMetrics?: DeviceMetrics | null; |
|||
} |
|||
|
|||
interface BatteryStateConfig { |
|||
condition: (level: number) => boolean; |
|||
Icon: React.ElementType; |
|||
className: string; |
|||
text: (level: number) => string; |
|||
} |
|||
|
|||
const batteryStates: BatteryStateConfig[] = [ |
|||
{ |
|||
condition: level => level > 100, |
|||
Icon: PlugZapIcon, |
|||
className: 'text-gray-600', |
|||
text: () => 'Plugged in', |
|||
}, |
|||
{ |
|||
condition: level => level > 80, |
|||
Icon: BatteryFullIcon, |
|||
className: 'text-green-500', |
|||
text: level => `${level}% charging`, |
|||
}, |
|||
{ |
|||
condition: level => level > 20, |
|||
Icon: BatteryMediumIcon, |
|||
className: 'text-yellow-400', |
|||
text: level => `${level}% charging`, |
|||
}, |
|||
{ |
|||
condition: () => true, |
|||
Icon: BatteryLowIcon, |
|||
className: 'text-red-500', |
|||
text: level => `${level}% charging`, |
|||
}, |
|||
]; |
|||
|
|||
const getBatteryState = (level: number) => { |
|||
return batteryStates.find(state => state.condition(level)); |
|||
}; |
|||
|
|||
|
|||
const BatteryStatus: React.FC<BatteryStatusProps> = ({ deviceMetrics }) => { |
|||
if (deviceMetrics?.batteryLevel === undefined || deviceMetrics?.batteryLevel === null) { |
|||
return null; |
|||
} |
|||
|
|||
const { batteryLevel, voltage } = deviceMetrics; |
|||
const currentState = getBatteryState(batteryLevel) ?? batteryStates[batteryStates.length - 1]; |
|||
|
|||
|
|||
const BatteryIcon = currentState.Icon; |
|||
const iconClassName = currentState.className; |
|||
const statusText = currentState.text(batteryLevel); |
|||
|
|||
const voltageTitle = `${voltage?.toPrecision(3) ?? 'Unknown'} volts`; |
|||
|
|||
return ( |
|||
<div |
|||
className="flex items-center gap-1 mt-0.5 text-gray-500" |
|||
title={voltageTitle} |
|||
> |
|||
<BatteryIcon size={22} className={iconClassName} /> |
|||
<Subtle aria-label="Battery"> |
|||
{statusText} |
|||
</Subtle> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default BatteryStatus; |
|||
Loading…
Reference in new issue