133 lines
4.6 KiB
TypeScript
133 lines
4.6 KiB
TypeScript
import React from 'react';
|
|
import { Zap, Activity, BatteryCharging, Power } from 'lucide-react';
|
|
import { UpsData } from '../app/page';
|
|
import styles from './StatCards.module.css';
|
|
|
|
interface StatCardsProps {
|
|
data: UpsData | null;
|
|
}
|
|
|
|
export default function StatCards({ data }: StatCardsProps) {
|
|
// If no data received yet (device offline), show dashes
|
|
if (!data) {
|
|
return (
|
|
<div className={styles.cardsGrid}>
|
|
{['Output Status', 'Charging Status', 'Battery Level', 'Power Source'].map(title => (
|
|
<div key={title} className={styles.card}>
|
|
<div className={styles.cardHeader}>
|
|
<span>{title}</span>
|
|
</div>
|
|
<div className={styles.cardContent}>
|
|
<div className={styles.valueArea}>
|
|
<span className={styles.powerSourceValue} style={{ color: 'var(--text-muted)' }}>—</span>
|
|
</div>
|
|
<div className={styles.status}>
|
|
<div className={styles.dot}></div>
|
|
<span style={{ color: 'var(--text-muted)' }}>No signal</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const outputOn = data.on === 1;
|
|
const isCharging = data.charging === 1;
|
|
const chgError = data.chgError === 1;
|
|
const isFull = data.charging === 0 && (data.battP ?? 0) >= 95 && (data.line ?? 0) > 0;
|
|
|
|
let chargingText = "Discharging";
|
|
if (chgError) chargingText = "Error";
|
|
else if (isFull) chargingText = "Fully Charged";
|
|
else if (isCharging) chargingText = "Charging";
|
|
else if ((data.line ?? 0) > 0) chargingText = "Standby";
|
|
|
|
const battPercent = data.battP ?? 0;
|
|
const battVoltage = data.v ?? "0.00";
|
|
|
|
const isBypass = (data.line ?? 0) > 0;
|
|
const powerSource = isBypass ? "Adaptor" : "Battery";
|
|
|
|
return (
|
|
<div className={styles.cardsGrid}>
|
|
{/* Card 1: Output Status */}
|
|
<div className={styles.card}>
|
|
<div className={styles.cardHeader}>
|
|
<span>Output Status</span>
|
|
<div className={styles.iconWrapper}>
|
|
<Activity size={18} />
|
|
</div>
|
|
</div>
|
|
<div className={styles.cardContent}>
|
|
<div className={styles.valueArea}>
|
|
<span className={styles.powerSourceValue}>{outputOn ? 'ON' : 'OFF'}</span>
|
|
</div>
|
|
<div className={styles.status}>
|
|
<div className={`${styles.dot} ${outputOn ? styles.active : ''}`}></div>
|
|
<span>{outputOn ? 'Powering Load' : 'Disabled'}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 2: Charging Status */}
|
|
<div className={styles.card}>
|
|
<div className={styles.cardHeader}>
|
|
<span>Charging Status</span>
|
|
<div className={styles.iconWrapper}>
|
|
<Zap size={18} />
|
|
</div>
|
|
</div>
|
|
<div className={styles.cardContent}>
|
|
<div className={styles.valueArea}>
|
|
<span className={styles.powerSourceValue}>{chargingText}</span>
|
|
</div>
|
|
<div className={styles.status}>
|
|
<div className={`${styles.dot} ${isCharging || isFull ? styles.active : ''} ${chgError ? styles.error : ''}`}></div>
|
|
<span>{chgError ? 'Check Battery' : isCharging ? 'Active' : 'Idle'}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 3: Battery Level */}
|
|
<div className={styles.card}>
|
|
<div className={styles.cardHeader}>
|
|
<span>Battery Level</span>
|
|
<div className={`${styles.iconWrapper} ${styles.batteryIcon}`}>
|
|
<BatteryCharging size={18} />
|
|
</div>
|
|
</div>
|
|
<div className={styles.cardContent}>
|
|
<div className={styles.valueArea}>
|
|
<span className={styles.value}>{battPercent}</span>
|
|
<span className={styles.unit}>%</span>
|
|
<span className={styles.subtext}>({battVoltage}V)</span>
|
|
</div>
|
|
<div className={styles.progressBarContainer}>
|
|
<div className={styles.progressBar} style={{ width: `${battPercent}%` }}></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 4: Power Source */}
|
|
<div className={styles.card}>
|
|
<div className={styles.cardHeader}>
|
|
<span>Power Source</span>
|
|
<div className={`${styles.iconWrapper} ${styles.powerSourceIcon}`}>
|
|
<Power size={18} />
|
|
</div>
|
|
</div>
|
|
<div className={styles.cardContent}>
|
|
<div className={styles.valueArea}>
|
|
<span className={styles.powerSourceValue}>{powerSource}</span>
|
|
</div>
|
|
<div className={styles.status}>
|
|
<span>Relay: {isBypass ? 'Bypass Mode' : 'Inverter Mode'}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|