feature/syasya/testlayout #7
@ -1,3 +1,6 @@
 | 
			
		||||
import axios from "axios";
 | 
			
		||||
import React, { useState, useEffect } from "react";
 | 
			
		||||
 | 
			
		||||
export type SiteName = 'Site A' | 'Site B' | 'Site C';
 | 
			
		||||
 | 
			
		||||
interface SiteStatusProps {
 | 
			
		||||
@ -15,6 +18,86 @@ const SiteStatus = ({
 | 
			
		||||
    emergencyContact,
 | 
			
		||||
    lastSyncTimestamp,
 | 
			
		||||
}: SiteStatusProps) => {
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
    const ws = new WebSocket("ws://localhost:8000/ws");
 | 
			
		||||
 | 
			
		||||
    ws.onmessage = (event) => {
 | 
			
		||||
        const data = event.data;
 | 
			
		||||
        alert(`MQTT: ${data}`);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ws.onopen = () => console.log("WebSocket connected");
 | 
			
		||||
    ws.onclose = () => console.log("WebSocket disconnected");
 | 
			
		||||
 | 
			
		||||
    return () => ws.close();
 | 
			
		||||
}, []);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    const [showModal, setShowModal] = useState(false);
 | 
			
		||||
    const [deviceId, setDeviceId] = useState("");
 | 
			
		||||
    const [functionType, setFunctionType] = useState("Grid");
 | 
			
		||||
 | 
			
		||||
    // Map site names to site IDs
 | 
			
		||||
    const siteIdMap: Record<SiteName, string> = {
 | 
			
		||||
        "Site A": "site_01",
 | 
			
		||||
        "Site B": "site_02",
 | 
			
		||||
        "Site C": "site_03",
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Track devices connected per site
 | 
			
		||||
    const [loggedDevices, setLoggedDevices] = useState<Record<string, string[]>>({
 | 
			
		||||
        site_01: [],
 | 
			
		||||
        site_02: [],
 | 
			
		||||
        site_03: [],
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const siteId = siteIdMap[selectedSite];
 | 
			
		||||
    const devicesAtSite = loggedDevices[siteId] || [];
 | 
			
		||||
 | 
			
		||||
    const handleStartLogging = () => {
 | 
			
		||||
        setShowModal(true);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const handleConfirm = async () => {
 | 
			
		||||
        const siteId = siteIdMap[selectedSite];
 | 
			
		||||
        const topic = `ADW300/${siteId}/${deviceId}/${functionType.toLowerCase()}`;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const response = await axios.post("http://localhost:8000/start-logging", {
 | 
			
		||||
                topics: [topic],
 | 
			
		||||
            });
 | 
			
		||||
            console.log("Started logging:", response.data);
 | 
			
		||||
 | 
			
		||||
            // Add device to list
 | 
			
		||||
            setLoggedDevices((prev) => ({
 | 
			
		||||
                ...prev,
 | 
			
		||||
                [siteId]: [...(prev[siteId] || []), deviceId],
 | 
			
		||||
            }));
 | 
			
		||||
            setShowModal(false);
 | 
			
		||||
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error("Failed to start logging:", error);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
     const handleStopLogging = async () => {
 | 
			
		||||
        try {
 | 
			
		||||
            await axios.post("http://localhost:8000/stop-logging");
 | 
			
		||||
 | 
			
		||||
            // Clear all devices for the site (or modify to remove only specific one)
 | 
			
		||||
            setLoggedDevices((prev) => ({
 | 
			
		||||
                ...prev,
 | 
			
		||||
                [siteId]: [],
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            console.log("Stopped logging for", siteId);
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error("Failed to stop logging:", error);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const statusMap: Record<SiteName, string> = {
 | 
			
		||||
        'Site A': 'Active',
 | 
			
		||||
        'Site B': 'Inactive',
 | 
			
		||||
@ -37,6 +120,12 @@ const SiteStatus = ({
 | 
			
		||||
                </p>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {/* Site ID */}
 | 
			
		||||
            <div className="flex justify-between items-center text-base">
 | 
			
		||||
                <p className="text-gray-600 dark:text-gray-400 font-medium">Site ID:</p>
 | 
			
		||||
                <p className="font-medium">{siteId}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {/* Location */}
 | 
			
		||||
            <div className="flex justify-between items-center text-base">
 | 
			
		||||
                <p className="text-gray-600 dark:text-gray-400 font-medium">Location:</p>
 | 
			
		||||
@ -60,6 +149,67 @@ const SiteStatus = ({
 | 
			
		||||
                <p className="text-gray-600 dark:text-gray-400 font-medium">Last Sync:</p>
 | 
			
		||||
                <p className="font-medium">{lastSyncTimestamp}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {/* Start Logging Button */}
 | 
			
		||||
            <div className="flex justify-between items-center text-base space-x-2">
 | 
			
		||||
                {devicesAtSite.length > 0 ? (
 | 
			
		||||
                    <button
 | 
			
		||||
                        onClick={handleStopLogging}
 | 
			
		||||
                        className="text-sm lg:text-md bg-red-500 hover:bg-red-600 text-white font-medium px-3 py-2 rounded"
 | 
			
		||||
                    >
 | 
			
		||||
                        Stop Logging
 | 
			
		||||
                    </button>
 | 
			
		||||
                ) : (
 | 
			
		||||
                    <button
 | 
			
		||||
                        onClick={handleStartLogging}
 | 
			
		||||
                        className="text-sm lg:text-md btn-primary px-3 py-2"
 | 
			
		||||
                    >
 | 
			
		||||
                        Start Logging
 | 
			
		||||
                    </button>
 | 
			
		||||
                )}
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            {/* Modal */}
 | 
			
		||||
            {showModal && (
 | 
			
		||||
                <div className="fixed inset-0 z-50 bg-black bg-opacity-50 flex items-center justify-center">
 | 
			
		||||
                    <div className="bg-white rounded-lg p-6 w-[90%] max-w-md shadow-lg">
 | 
			
		||||
                        <h2 className="text-lg font-semibold mb-4">Enter Device Info</h2>
 | 
			
		||||
 | 
			
		||||
                        <input
 | 
			
		||||
                            type="text"
 | 
			
		||||
                            placeholder="Device ID (e.g. device_01)"
 | 
			
		||||
                            className="w-full p-2 mb-4 border rounded"
 | 
			
		||||
                            value={deviceId}
 | 
			
		||||
                            onChange={(e) => setDeviceId(e.target.value)}
 | 
			
		||||
                        />
 | 
			
		||||
 | 
			
		||||
                        <select
 | 
			
		||||
                            className="w-full p-2 mb-4 border rounded"
 | 
			
		||||
                            value={functionType}
 | 
			
		||||
                            onChange={(e) => setFunctionType(e.target.value)}
 | 
			
		||||
                        >
 | 
			
		||||
                            <option value="Grid">Grid</option>
 | 
			
		||||
                            <option value="Solar">Solar</option>
 | 
			
		||||
                        </select>
 | 
			
		||||
 | 
			
		||||
                        <div className="flex justify-end space-x-2">
 | 
			
		||||
                            <button
 | 
			
		||||
                                onClick={() => setShowModal(false)}
 | 
			
		||||
                                className="btn-primary bg-white border-2 border-black hover:bg-rtgray-200 px-4 py-2"
 | 
			
		||||
                            >
 | 
			
		||||
                                Cancel
 | 
			
		||||
                            </button>
 | 
			
		||||
                            <button
 | 
			
		||||
                                onClick={handleConfirm}
 | 
			
		||||
                                className="btn-primary px-4 py-2"
 | 
			
		||||
                            >
 | 
			
		||||
                                Confirm
 | 
			
		||||
                            </button>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            )}
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ export interface SiteDetails {
 | 
			
		||||
    lastSyncTimestamp: string;
 | 
			
		||||
    consumptionData: number[]; // e.g., Daily consumption in kWh
 | 
			
		||||
    generationData: number[]; // e.g., Daily generation in kWh
 | 
			
		||||
 | 
			
		||||
    connectedDevices: string[];
 | 
			
		||||
    // Properties for SystemOverview
 | 
			
		||||
    systemStatus: string; // e.g., "Normal", "Faulty"
 | 
			
		||||
    temperature: string; // e.g., "35°C"
 | 
			
		||||
@ -56,6 +56,7 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
			
		||||
        gridImportPrice_RM_per_kWh: 0.50, // Example: RM 0.50 per kWh
 | 
			
		||||
        solarExportTariff_RM_per_kWh: 0.30, // Example: RM 0.30 per kWh
 | 
			
		||||
        theoreticalMaxGeneration_kWh: 80000, // Example: Theoretical max for 174.9 kWp over a month in Malaysia
 | 
			
		||||
        connectedDevices : [],
 | 
			
		||||
    },
 | 
			
		||||
    'Site B': {
 | 
			
		||||
        location: 'Kuala Lumpur, Wilayah Persekutuan',
 | 
			
		||||
@ -72,6 +73,7 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
			
		||||
        gridImportPrice_RM_per_kWh: 0.52,
 | 
			
		||||
        solarExportTariff_RM_per_kWh: 0.32,
 | 
			
		||||
        theoreticalMaxGeneration_kWh: 190000,
 | 
			
		||||
        connectedDevices: [],
 | 
			
		||||
    },
 | 
			
		||||
    'Site C': {
 | 
			
		||||
        location: 'Johor Bahru, Johor',
 | 
			
		||||
@ -88,5 +90,6 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
			
		||||
        gridImportPrice_RM_per_kWh: 0.48,
 | 
			
		||||
        solarExportTariff_RM_per_kWh: 0.28,
 | 
			
		||||
        theoreticalMaxGeneration_kWh: 180000, // Lower theoretical max due to fault or smaller system
 | 
			
		||||
        connectedDevices: [],
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user