Vision_Meta0 / ChargingHub.jsx
lattmamb's picture
Upload 32 files
b33d337 verified
import React, { useState, useEffect } from 'react';
import './ChargingHub.css';
// Mock data for demonstration purposes
const mockChargingPorts = [
{ id: 1, number: 1, status: 'available', type: 'DC Fast', power: '250kW', lastUsed: null },
{ id: 2, number: 2, status: 'charging', type: 'DC Fast', power: '250kW', vehicle: 'Tesla Model 3', startTime: '14:30', endTime: '15:15', progress: 68 },
{ id: 3, number: 3, status: 'reserved', type: 'DC Fast', power: '250kW', reservedFor: '17:00', duration: '45 min' },
{ id: 4, number: 4, status: 'maintenance', type: 'DC Fast', power: '250kW', maintenanceNote: 'Scheduled maintenance', estimatedCompletion: '18:00' },
{ id: 5, number: 5, status: 'available', type: 'DC Fast', power: '250kW', lastUsed: '13:45' },
{ id: 6, number: 6, status: 'charging', type: 'DC Fast', power: '250kW', vehicle: 'Tesla Model Y', startTime: '15:10', endTime: '15:55', progress: 42 },
{ id: 7, number: 7, status: 'available', type: 'DC Fast', power: '250kW', lastUsed: '12:30' },
{ id: 8, number: 8, status: 'charging', type: 'DC Fast', power: '250kW', vehicle: 'GMC Hummer EV', startTime: '15:25', endTime: '16:10', progress: 25 },
];
const mockEnergyData = {
currentDemand: 625,
peakDemand: 1200,
solarGeneration: 85,
batteryStorage: 72,
gridConsumption: 540,
dailyUsage: [
{ hour: '00:00', demand: 120 },
{ hour: '01:00', demand: 90 },
{ hour: '02:00', demand: 75 },
{ hour: '03:00', demand: 60 },
{ hour: '04:00', demand: 45 },
{ hour: '05:00', demand: 60 },
{ hour: '06:00', demand: 150 },
{ hour: '07:00', demand: 300 },
{ hour: '08:00', demand: 450 },
{ hour: '09:00', demand: 600 },
{ hour: '10:00', demand: 750 },
{ hour: '11:00', demand: 900 },
{ hour: '12:00', demand: 1050 },
{ hour: '13:00', demand: 1150 },
{ hour: '14:00', demand: 1200 },
{ hour: '15:00', demand: 1100 },
{ hour: '16:00', demand: 950 },
{ hour: '17:00', demand: 800 },
{ hour: '18:00', demand: 700 },
{ hour: '19:00', demand: 600 },
{ hour: '20:00', demand: 500 },
{ hour: '21:00', demand: 400 },
{ hour: '22:00', demand: 300 },
{ hour: '23:00', demand: 200 },
],
};
const mockVisitors = {
current: 24,
capacity: 50,
averageDuration: 38,
peakHours: '12:00 - 14:00',
amenityUsage: {
lounge: 65,
cafe: 48,
retail: 32,
workspace: 25,
},
};
const mockReservations = [
{ id: 101, name: 'John Smith', vehicle: 'Tesla Model 3', time: '17:00', duration: '45 min', port: 3, status: 'confirmed' },
{ id: 102, name: 'Sarah Johnson', vehicle: 'Tesla Model Y', time: '17:30', duration: '30 min', port: 1, status: 'confirmed' },
{ id: 103, name: 'Michael Brown', vehicle: 'Ford F-150 Lightning', time: '18:15', duration: '60 min', port: 5, status: 'pending' },
{ id: 104, name: 'Emily Davis', vehicle: 'Rivian R1T', time: '19:00', duration: '45 min', port: 7, status: 'confirmed' },
];
function ChargingHub() {
const [activeTab, setActiveTab] = useState('dashboard');
const [loading, setLoading] = useState(true);
const [currentTime, setCurrentTime] = useState('');
const [hubStatus, setHubStatus] = useState({
name: 'The Link - Downtown',
location: 'Springfield, IL',
status: 'operational',
occupancy: '48%',
availablePorts: 3,
totalPorts: 8,
energyEfficiency: '92%',
});
useEffect(() => {
// Simulate loading
const timer = setTimeout(() => {
setLoading(false);
}, 1500);
// Update current time
const updateTime = () => {
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
setCurrentTime(`${hours}:${minutes}`);
};
updateTime();
const timeInterval = setInterval(updateTime, 60000);
return () => {
clearTimeout(timer);
clearInterval(timeInterval);
};
}, []);
// Function to render status badge with appropriate color
const renderStatusBadge = (status) => {
let className = 'status-badge';
switch(status) {
case 'available':
className += ' available';
break;
case 'charging':
className += ' charging';
break;
case 'reserved':
className += ' reserved';
break;
case 'maintenance':
className += ' maintenance';
break;
default:
break;
}
return <span className={className}>{status}</span>;
};
// Function to render progress bar for charging ports
const renderProgressBar = (progress) => {
return (
<div className="progress-container">
<div className="progress-bar" style={{ width: `${progress}%` }}>
<div className="progress-glow"></div>
</div>
<span className="progress-text">{progress}%</span>
</div>
);
};
if (loading) {
return (
<div className="charging-hub loading">
<div className="loading-logo">
<img src="/images/the_link_logo.png" alt="The Link" />
<div className="loading-pulse"></div>
</div>
<p>Initializing Hub Dashboard...</p>
</div>
);
}
return (
<div className="charging-hub">
<header className="hub-header">
<div className="hub-title">
<h1>THE LINK</h1>
<span className="hub-subtitle">Charging Hub Dashboard</span>
</div>
<div className="hub-status">
<div className="status-item">
<span className="status-label">Hub Status:</span>
<span className={`status-value ${hubStatus.status}`}>{hubStatus.status}</span>
</div>
<div className="status-item">
<span className="status-label">Current Time:</span>
<span className="status-value">{currentTime}</span>
</div>
</div>
<div className="hub-actions">
<button className="action-button">
<span className="icon">⚙️</span>
<span>Settings</span>
</button>
<button className="action-button">
<span className="icon">🔔</span>
<span>Alerts</span>
</button>
<div className="user-profile">
<img src="/images/admin_avatar.png" alt="Admin" />
</div>
</div>
</header>
<div className="hub-navigation">
<button
className={`nav-button ${activeTab === 'dashboard' ? 'active' : ''}`}
onClick={() => setActiveTab('dashboard')}
>
Dashboard
</button>
<button
className={`nav-button ${activeTab === 'charging' ? 'active' : ''}`}
onClick={() => setActiveTab('charging')}
>
Charging Ports
</button>
<button
className={`nav-button ${activeTab === 'energy' ? 'active' : ''}`}
onClick={() => setActiveTab('energy')}
>
Energy Management
</button>
<button
className={`nav-button ${activeTab === 'visitors' ? 'active' : ''}`}
onClick={() => setActiveTab('visitors')}
>
Visitor Analytics
</button>
<button
className={`nav-button ${activeTab === 'reservations' ? 'active' : ''}`}
onClick={() => setActiveTab('reservations')}
>
Reservations
</button>
</div>
<main className="hub-content">
{activeTab === 'dashboard' && (
<div className="dashboard-view">
<div className="hub-overview">
<div className="overview-card location">
<h3>Hub Location</h3>
<div className="location-details">
<div className="location-name">{hubStatus.name}</div>
<div className="location-address">{hubStatus.location}</div>
</div>
<div className="location-map">
<img src="/images/hub_location_map.png" alt="Hub Location" />
</div>
</div>
<div className="overview-card occupancy">
<h3>Current Occupancy</h3>
<div className="occupancy-gauge">
<svg viewBox="0 0 120 120" className="gauge">
<circle cx="60" cy="60" r="50" className="gauge-background" />
<circle
cx="60"
cy="60"
r="50"
className="gauge-progress"
style={{
strokeDasharray: `${parseInt(hubStatus.occupancy) * 3.14}px, 314px`
}}
/>
<text x="60" y="65" textAnchor="middle" className="gauge-text">
{hubStatus.occupancy}
</text>
</svg>
</div>
<div className="occupancy-details">
<div className="detail-item">
<span className="detail-label">Available Ports:</span>
<span className="detail-value">{hubStatus.availablePorts}/{hubStatus.totalPorts}</span>
</div>
</div>
</div>
<div className="overview-card energy">
<h3>Energy Overview</h3>
<div className="energy-metrics">
<div className="metric">
<div className="metric-value">{mockEnergyData.currentDemand} kW</div>
<div className="metric-label">Current Demand</div>
</div>
<div className="metric">
<div className="metric-value">{mockEnergyData.solarGeneration}%</div>
<div className="metric-label">Solar Generation</div>
</div>
<div className="metric">
<div className="metric-value">{mockEnergyData.batteryStorage}%</div>
<div className="metric-label">Battery Storage</div>
</div>
</div>
<div className="energy-chart">
<div className="chart-container">
{/* Simplified chart representation */}
<div className="chart-bars">
{mockEnergyData.dailyUsage.slice(-8).map((hour, index) => (
<div
key={index}
className="chart-bar"
style={{ height: `${(hour.demand / mockEnergyData.peakDemand) * 100}%` }}
>
<div className="bar-glow"></div>
</div>
))}
</div>
</div>
</div>
</div>
<div className="overview-card visitors">
<h3>Visitor Analytics</h3>
<div className="visitor-count">
<div className="count-value">{mockVisitors.current}</div>
<div className="count-label">Current Visitors</div>
</div>
<div className="visitor-details">
<div className="detail-item">
<span className="detail-label">Capacity:</span>
<span className="detail-value">{mockVisitors.capacity}</span>
</div>
<div className="detail-item">
<span className="detail-label">Avg. Duration:</span>
<span className="detail-value">{mockVisitors.averageDuration} min</span>
</div>
<div className="detail-item">
<span className="detail-label">Peak Hours:</span>
<span className="detail-value">{mockVisitors.peakHours}</span>
</div>
</div>
</div>
</div>
<div className="quick-status">
<h3>Charging Port Status</h3>
<div className="port-status-grid">
{mockChargingPorts.map(port => (
<div key={port.id} className={`port-status-card ${port.status}`}>
<div className="port-number">{port.number}</div>
<div className="port-status">{renderStatusBadge(port.status)}</div>
{port.status === 'charging' && (
<div className="port-progress">{renderProgressBar(port.progress)}</div>
)}
</div>
))}
</div>
</div>
<div className="upcoming-reservations">
<h3>Upcoming Reservations</h3>
<div className="reservation-list">
{mockReservations.map(reservation => (
<div key={reservation.id} className="reservation-card">
<div className="reservation-time">{reservation.time}</div>
<div className="reservation-details">
<div className="reservation-name">{reservation.name}</div>
<div className="reservation-vehicle">{reservation.vehicle}</div>
</div>
<div className="reservation-port">Port {reservation.port}</div>
<div className="reservation-duration">{reservation.duration}</div>
<div className={`reservation-status ${reservation.status}`}>
{reservation.status}
</div>
</div>
))}
</div>
</div>
</div>
)}
{activeTab === 'charging' && (
<div className="charging-view">
<div className="section-header">
<h2>Charging Port Management</h2>
<div className="header-actions">
<button className="action-button">
<span className="icon">+</span>
<span>Add Port</span>
</button>
<div className="filter-dropdown">
<select>
<option value="all">All Statuses</option>
<option value="available">Available</option>
<option value="charging">Charging</option>
<option value="reserved">Reserved</option>
<option value="maintenance">Maintenance</option>
</select>
</div>
</div>
</div>
<div className="charging-ports-grid">
{mockChargingPorts.map(port => (
<div key={port.id} className={`port-card ${port.status}`}>
<div className="port-header">
<div className="port-number">Port {port.number}</div>
<div className="port-status">{renderStatusBadge(port.status)}</div>
</div>
<div className="port-details">
<div className="detail-item">
<span className="detail-label">Type:</span>
<span className="detail-value">{port.type}</span>
</div>
<div className="detail-item">
<span className="detail-label">Power:</span>
<span className="detail-value">{port.power}</span>
</div>
{port.status === 'available' && (
<div className="detail-item">
<span className="detail-label">Last Used:</span>
<span className="detail-value">{port.lastUsed || 'N/A'}</span>
</div>
)}
{port.status === 'charging' && (
<>
<div className="detail-item">
<span className="detail-label">Vehicle:</span>
<span className="detail-value">{port.vehicle}</span>
</div>
<div className="detail-item">
<span className="detail-label">Started:</span>
<span className="detail-value">{port.startTime}</span>
</div>
<div className="detail-item">
<span className="detail-label">Est. Completion:</span>
<span className="detail-value">{port.endTime}</span>
</div>
<div className="detail-item full-width">
<div className="progress-label">Charging Progress</div>
{renderProgressBar(port.progress)}
</div>
</>
)}
{port.status === 'reserved' && (
<>
<div className="detail-item">
<span className="detail-label">Reserved For:</span>
<span className="detail-value">{port.reservedFor}</span>
</div>
<div className="detail-item">
<span className="detail-label">Duration:</span>
<span className="detail-value">{port.duration}</span>
</div>
</>
)}
{port.status === 'maintenance' && (
<>
<div className="detail-item">
<span className="detail-label">Note:</span>
<span className="detail-value">{port.maintenanceNote}</span>
</div>
<div className="detail-item">
<span className="detail-label">Est. Completion:</span>
<span className="detail-value">{port.estimatedCompletion}</span>
</div>
</>
)}
</div>
<div className="port-actions">
{port.status === 'available' && (
<>
<button className="port-action reserve">Reserve</button>
<button className="port-action maintenance">Set Maintenance</button>
</>
)}
{port.status === 'charging' && (
<>
<button className="port-action stop">Stop Charging</button>
<button className="port-action details">View Details</button>
</>
)}
{port.status === 'reserved' && (
<>
<button className="port-action cancel">Cancel Reservation</button>
<button className="port-action edit">Edit Reservation</button>
</>
)}
{port.status === 'maintenance' && (
<>
<button className="port-action complete">Complete Maintenance</button>
<button className="port-action update">Update Status</button>
</>
)}
</div>
</div>
))}
</div>
</div>
)}
{activeTab === 'energy' && (
<div className="energy-view">
<div className="section-header">
<h2>Energy Management System</h2>
<div className="header-actions">
<button className="action-button">
<span className="icon">📊</span>
<span>Export Data</span>
</button>
<div className="time-range-selector">
<select>
<option value="day">Today</option>
<option value="week">This Week</option>
<option value="month">This Month</option>
<option value="custom">Custom Range</option>
</select>
</div>
</div>
</div>
<div className="energy-overview">
<div className="energy-card current-demand">
<h3>Current Demand</h3>
<div className="energy-value">{mockEnergyData.currentDemand} kW</div>
<div className="energy-chart">
<div className="chart-container">
{/* Simplified chart representation */}
<div className="chart-line">
<svg viewBox="0 0 100 30">
<path
d="M0,25 L10,20 L20,22 L30,15 L40,18 L50,10 L60,12 L70,8 L80,15 L90,5 L100,10"
className="chart-path"
/>
</svg>
</div>
</div>
</div>
<div className="energy-details">
<div className="detail-item">
<span className="detail-label">Peak Today:</span>
<span className="detail-value">{mockEnergyData.peakDemand} kW</span>
</div>
<div className="detail-item">
<span className="detail-label">Average:</span>
<span className="detail-value">780 kW</span>
</div>
</div>
</div>
<div className="energy-card energy-sources">
<h3>Energy Sources</h3>
<div className="sources-chart">
<div className="donut-chart">
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" className="donut-ring" />
<circle
cx="50"
cy="50"
r="40"
className="donut-segment grid"
style={{
strokeDasharray: `${mockEnergyData.gridConsumption / 10} 251.2`
}}
/>
<circle
cx="50"
cy="50"
r="40"
className="donut-segment solar"
style={{
strokeDasharray: `${mockEnergyData.solarGeneration / 10} 251.2`,
strokeDashoffset: `-${mockEnergyData.gridConsumption / 10}`
}}
/>
<circle
cx="50"
cy="50"
r="40"
className="donut-segment battery"
style={{
strokeDasharray: `${mockEnergyData.batteryStorage / 10} 251.2`,
strokeDashoffset: `-${(mockEnergyData.gridConsumption + mockEnergyData.solarGeneration) / 10}`
}}
/>
</svg>
</div>
</div>
<div className="sources-legend">
<div className="legend-item grid">
<span className="legend-color"></span>
<span className="legend-label">Grid</span>
<span className="legend-value">{mockEnergyData.gridConsumption} kW</span>
</div>
<div className="legend-item solar">
<span className="legend-color"></span>
<span className="legend-label">Solar</span>
<span className="legend-value">{mockEnergyData.solarGeneration}%</span>
</div>
<div className="legend-item battery">
<span className="legend-color"></span>
<span className="legend-label">Battery</span>
<span className="legend-value">{mockEnergyData.batteryStorage}%</span>
</div>
</div>
</div>
<div className="energy-card efficiency">
<h3>System Efficiency</h3>
<div className="efficiency-gauge">
<svg viewBox="0 0 120 120" className="gauge">
<circle cx="60" cy="60" r="50" className="gauge-background" />
<circle
cx="60"
cy="60"
r="50"
className="gauge-progress efficiency"
style={{
strokeDasharray: `${parseInt(hubStatus.energyEfficiency) * 3.14}px, 314px`
}}
/>
<text x="60" y="65" textAnchor="middle" className="gauge-text">
{hubStatus.energyEfficiency}
</text>
</svg>
</div>
<div className="efficiency-details">
<div className="detail-item">
<span className="detail-label">Power Factor:</span>
<span className="detail-value">0.98</span>
</div>
<div className="detail-item">
<span className="detail-label">Conversion Loss:</span>
<span className="detail-value">8%</span>
</div>
</div>
</div>
</div>
<div className="energy-daily-chart">
<h3>24-Hour Energy Demand</h3>
<div className="chart-container">
<div className="chart-y-axis">
<div className="axis-label">1200 kW</div>
<div className="axis-label">900 kW</div>
<div className="axis-label">600 kW</div>
<div className="axis-label">300 kW</div>
<div className="axis-label">0 kW</div>
</div>
<div className="chart-content">
<div className="chart-bars">
{mockEnergyData.dailyUsage.map((hour, index) => (
<div key={index} className="chart-bar-container">
<div
className="chart-bar"
style={{ height: `${(hour.demand / mockEnergyData.peakDemand) * 100}%` }}
>
<div className="bar-glow"></div>
</div>
<div className="bar-label">{hour.hour}</div>
</div>
))}
</div>
</div>
</div>
</div>
<div className="energy-controls">
<h3>Energy Management Controls</h3>
<div className="controls-grid">
<div className="control-card">
<h4>Load Balancing</h4>
<div className="control-status">
<span className="status-indicator active"></span>
<span className="status-text">Active</span>
</div>
<div className="control-actions">
<button className="control-action">Configure</button>
<button className="control-action">Disable</button>
</div>
</div>
<div className="control-card">
<h4>Peak Shaving</h4>
<div className="control-status">
<span className="status-indicator active"></span>
<span className="status-text">Active</span>
</div>
<div className="control-actions">
<button className="control-action">Configure</button>
<button className="control-action">Disable</button>
</div>
</div>
<div className="control-card">
<h4>Battery Storage</h4>
<div className="control-status">
<span className="status-indicator active"></span>
<span className="status-text">Discharging</span>
</div>
<div className="control-actions">
<button className="control-action">Switch to Charging</button>
<button className="control-action">Set to Auto</button>
</div>
</div>
<div className="control-card">
<h4>Grid Connection</h4>
<div className="control-status">
<span className="status-indicator active"></span>
<span className="status-text">Connected</span>
</div>
<div className="control-actions">
<button className="control-action">Emergency Disconnect</button>
<button className="control-action">Test Backup</button>
</div>
</div>
</div>
</div>
</div>
)}
{/* Additional tabs would be implemented here */}
</main>
</div>
);
}
export default ChargingHub;