-
Power Plan
- {!reportData && !loading && (
-
-
Click On the Button to generate the power plan for this month
-
-
- )}
+
+
Power Plan
- {loading ? (
-
- ) : (
- reportData && (
-
-
Report Summary
-
{reportData.summary}
+ {!reportData && !loading && (
+
+
Click On the Button to generate the power plan for this month
+
+
+ )}
-
-
Voltage Insights
-
{reportData.voltageInsights}
-
+ {loading ? (
+
+ ) : (
+ reportData && (
+
+
Report Summary
+
{reportData.summary}
-
-
Power Insights
-
{reportData.powerInsights}
-
+
+
Voltage Insights
+
{reportData.voltageInsights}
+
-
-
Energy Insights
-
{reportData.energyInsights}
-
+
+
Power Insights
+
{reportData.powerInsights}
+
-
-
Recommendations
-
- {reportData.recommendations
- .split("\n")
- .map((recommendation, index) => (
- - {recommendation}
- ))}
-
-
-
+
+
Energy Insights
+
{reportData.energyInsights}
+
+
+
+
Recommendations
+
+ {reportData.recommendations
+ .split("\n")
+ .map((recommendation, index) => (
+ - {recommendation}
+ ))}
+
+
+
-
- )
- )}
-
- >
+
+ )
+ )}
+
);
};
diff --git a/amp-client/src/Pages/ClientPages/ClientProfile/ClientProfile.jsx b/amp-client/src/Pages/ClientPages/ClientProfile/ClientProfile.jsx
index aa8f694a..4681a10c 100644
--- a/amp-client/src/Pages/ClientPages/ClientProfile/ClientProfile.jsx
+++ b/amp-client/src/Pages/ClientPages/ClientProfile/ClientProfile.jsx
@@ -1,18 +1,17 @@
import "./styles.css";
import { useState } from "react";
import { toast } from "react-toastify";
-import { useNavigate } from "react-router-dom";
import "react-toastify/dist/ReactToastify.css";
-import axiosBaseUrl from "../../../Axios/axios";
import InputField from "../../../Components/CommonComponents/InputField/InputField";
import ActionButton from "../../../Components/CommonComponents/ActionButton/ActionButton";
+import ClientProfileService from "../Services/ClientProfileService/ClientProfileService";
const ClientProfile = () => {
const [currentPassword, setCurrentPassword] = useState("");
const [newPassword, setNewPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
- const navigate = useNavigate();
+ const { updatePassword } = ClientProfileService();
const handleSubmit = async (e) => {
e.preventDefault();
@@ -22,22 +21,7 @@ const ClientProfile = () => {
return;
}
- const password = newPassword;
-
- try {
- const response = await axiosBaseUrl.post("/clients/editProfile", {
- password,
- });
-
- if (response.data.success) {
- toast.success("Password updated successfully.");
- setTimeout(() => navigate("/client/dashboard"), 1000);
- } else {
- toast.error(response.data.message || "Failed to update password.");
- }
- } catch (error) {
- toast.error("An error occurred. Please try again.");
- }
+ await updatePassword({ password: newPassword });
};
return (
diff --git a/amp-client/src/Pages/ClientPages/Services/ClientDashboardService/ClientDashboardService.js b/amp-client/src/Pages/ClientPages/Services/ClientDashboardService/ClientDashboardService.js
new file mode 100644
index 00000000..73ea0090
--- /dev/null
+++ b/amp-client/src/Pages/ClientPages/Services/ClientDashboardService/ClientDashboardService.js
@@ -0,0 +1,15 @@
+// ClientDashboardService.js
+import axiosInstance from "../../../../Axios/axios";
+
+const ClientDashboardService = {
+ async fetchClientDashboardData(userId) {
+ try {
+ const response = await axiosInstance.get(`/clients/clientDashboardData/${userId}`);
+ return response.data.data;
+ } catch (error) {
+ throw new Error(error.response?.data?.message || error.message);
+ }
+ },
+};
+
+export default ClientDashboardService;
diff --git a/amp-client/src/Pages/ClientPages/Services/ClientPowerPlanService/ClientPowerPlanService.js b/amp-client/src/Pages/ClientPages/Services/ClientPowerPlanService/ClientPowerPlanService.js
new file mode 100644
index 00000000..572d3b5f
--- /dev/null
+++ b/amp-client/src/Pages/ClientPages/Services/ClientPowerPlanService/ClientPowerPlanService.js
@@ -0,0 +1,29 @@
+import { useDispatch } from "react-redux";
+import { toggleLoad } from "../../../../Redux/Slices/loadingSlice";
+import axiosInstance from "../../../../Axios/axios";
+
+const ClientPowerPlanService = () => {
+ const dispatch = useDispatch();
+
+ const fetchPowerPlanReport = async (userId, setReportData) => {
+ dispatch(toggleLoad(true));
+ setReportData(null);
+
+ try {
+ const response = await axiosInstance.get(
+ `clients/clientReport/${userId}`
+ );
+ const data = response.data;
+ setReportData(data.data);
+ } catch (error) {
+ console.error("Error fetching power plan report:", error);
+ setReportData(null);
+ } finally {
+ dispatch(toggleLoad(false));
+ }
+ };
+
+ return { fetchPowerPlanReport };
+};
+
+export default ClientPowerPlanService;
diff --git a/amp-client/src/Pages/ClientPages/Services/ClientProfileService/ClientProfileService.js b/amp-client/src/Pages/ClientPages/Services/ClientProfileService/ClientProfileService.js
new file mode 100644
index 00000000..a5ab912d
--- /dev/null
+++ b/amp-client/src/Pages/ClientPages/Services/ClientProfileService/ClientProfileService.js
@@ -0,0 +1,28 @@
+import { toast } from "react-toastify";
+import { useNavigate } from "react-router-dom";
+import axiosInstance from "../../../../Axios/axios";
+
+const ClientProfileService = () => {
+ const navigate = useNavigate();
+
+ const updatePassword = async ({ password }) => {
+ try {
+ const response = await axiosInstance.post("/clients/editProfile", {
+ password,
+ });
+
+ if (response.data.success) {
+ toast.success("Password updated successfully.");
+ setTimeout(() => navigate("/client/dashboard"), 1000);
+ } else {
+ toast.error(response.data.message || "Failed to update password.");
+ }
+ } catch (error) {
+ toast.error("An error occurred. Please try again.");
+ }
+ };
+
+ return { updatePassword };
+};
+
+export default ClientProfileService;
diff --git a/amp-client/src/Pages/ProviderPages/ProviderDashboard/ProviderDashboard.jsx b/amp-client/src/Pages/ProviderPages/ProviderDashboard/ProviderDashboard.jsx
index 71d2e650..4b227bd5 100644
--- a/amp-client/src/Pages/ProviderPages/ProviderDashboard/ProviderDashboard.jsx
+++ b/amp-client/src/Pages/ProviderPages/ProviderDashboard/ProviderDashboard.jsx
@@ -1,8 +1,8 @@
import "./styles.css";
-import axiosBaseUrl from "../../../Axios/axios";
import { useEffect, useState, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { toggleLoad } from "../../../Redux/Slices/loadingSlice";
+import ProviderDashboardService from "../Services/ProviderDashboardService/ProviderDashboardService";
import {
Chart as ChartJS,
CategoryScale,
@@ -41,112 +41,60 @@ ChartJS.register(
const ProviderDashboard = () => {
const userId = useSelector((state) => state.user.id);
const dispatch = useDispatch();
- const [overviewData, setOverviewData] = useState(null);
- const [powerUsageByClient, setPowerUsageByClient] = useState([]);
- const [voltageDistribution, setVoltageDistribution] = useState([]);
- const [metricsSummary, setMetricsSummary] = useState(null);
- const [totalPowerUsage, setTotalPowerUsage] = useState([]);
- const [averageVoltage, setAverageVoltage] = useState([]);
- const [totalUsers, setTotalUsers] = useState(null);
- const [allMetrics, setAllMetrics] = useState([]);
- const [totalLines, setTotalLines] = useState(null);
+
+ // State declarations
+ const [dashboardData, setDashboardData] = useState({
+ overviewData: null,
+ powerUsageByClient: [],
+ voltageDistribution: [],
+ metricsSummary: null,
+ totalPowerUsage: [],
+ averageVoltage: [],
+ totalUsers: null,
+ allMetrics: [],
+ totalLines: null,
+ });
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
- const powerByClientChartRef = useRef(null);
- const voltageDistributionChartRef = useRef(null);
- const metricsSummaryChartRef = useRef(null);
- const clientCountChartRef = useRef(null);
- const totalPowerUsageChartRef = useRef(null);
- const averageVoltageChartRef = useRef(null);
+ // Destructure data from state for easier access
+ const {
+ overviewData,
+ powerUsageByClient,
+ voltageDistribution,
+ metricsSummary,
+ totalPowerUsage,
+ averageVoltage,
+ totalUsers,
+ allMetrics,
+ totalLines,
+ } = dashboardData;
+
+ // Chart refs for cleanup
+ const chartRefs = {
+ powerByClientChart: useRef(null),
+ voltageDistributionChart: useRef(null),
+ metricsSummaryChart: useRef(null),
+ clientCountChart: useRef(null),
+ totalPowerUsageChart: useRef(null),
+ averageVoltageChart: useRef(null),
+ };
+ // Fetch data on component mount
useEffect(() => {
const fetchDashboardData = async () => {
dispatch(toggleLoad(true));
setLoading(true);
setError(null);
- try {
- const overviewResponse = await axiosBaseUrl.get(
- `/providers/overview/${userId}`
- );
- setOverviewData(overviewResponse.data.data);
- const powerByClientResponse = await axiosBaseUrl.get(
- `/providers/powerUsageByClient/${userId}`
- );
- setPowerUsageByClient(powerByClientResponse.data.data);
-
- const voltageDistributionResponse = await axiosBaseUrl.get(
- `/providers/voltageDistribution/${userId}`
- );
- const voltageData = voltageDistributionResponse.data.data.map(
- (v) => v.voltage
- );
- const voltageCounts = {};
- voltageData.forEach((v) => {
- const roundedVoltage = Math.round(v);
- voltageCounts[roundedVoltage] =
- (voltageCounts[roundedVoltage] || 0) + 1;
- });
- setVoltageDistribution(
- Object.entries(voltageCounts).sort(
- (a, b) => parseInt(a[0]) - parseInt(b[0])
- )
- );
-
- const metricsSummaryResponse = await axiosBaseUrl.get(
- `/providers/metricsSummary/${userId}`
- );
- setMetricsSummary(metricsSummaryResponse.data.data);
-
- const totalPowerUsageResponse = await axiosBaseUrl.get(
- `/providers/totalPowerUsage/${userId}`
- );
- const totalPowerUsageArray = Object.entries(
- totalPowerUsageResponse.data.data
- ).map(([date, power]) => ({
- timestamp: new Date(date).toISOString(),
- total_power: power,
- }));
- setTotalPowerUsage(totalPowerUsageArray);
-
- const averageVoltageResponse = await axiosBaseUrl.get(
- `/providers/averageVoltage/${userId}`
- );
- const averageVoltageArray = Object.entries(
- averageVoltageResponse.data.data
- ).map(([date, voltage]) => ({
- timestamp: new Date(date).toISOString(),
- average_voltage: voltage,
- }));
- setAverageVoltage(averageVoltageArray);
-
- const usersResponse = await axiosBaseUrl.get(
- `/providers/getAllUsers/${userId}`
- );
- setTotalUsers(usersResponse?.data?.data?.length);
-
- const allMetricsResponse = await axiosBaseUrl.get(
- `/providers/getAllMetrics/${userId}`
- );
- setAllMetrics(
- Array.isArray(allMetricsResponse?.data?.data)
- ? allMetricsResponse.data.data
- : []
- );
-
- const linesResponse = await axiosBaseUrl.get(
- `/providers/getAllLines/${userId}`
+ try {
+ const data = await ProviderDashboardService.fetchAllDashboardData(
+ userId
);
- setTotalLines(linesResponse?.data?.data?.length);
+ setDashboardData(data);
} catch (err) {
- if (err.code === "ECONNABORTED") {
- setError("Request timed out. Please try again.");
- } else {
- setError(err.message || "Failed to fetch dashboard data for charts");
- }
- // setError(err.message || "Failed to fetch dashboard data for charts");
- console.error("Error fetching dashboard data for charts:", err);
+ setError(err.message || "Failed to fetch dashboard data");
+ console.error("Error fetching dashboard data:", err);
} finally {
setLoading(false);
dispatch(toggleLoad(false));
@@ -155,334 +103,320 @@ const ProviderDashboard = () => {
fetchDashboardData();
+ // Cleanup function for chart instances
return () => {
- if (powerByClientChartRef.current) {
- powerByClientChartRef.current.destroy();
- }
- if (voltageDistributionChartRef.current) {
- voltageDistributionChartRef.current.destroy();
- }
- if (metricsSummaryChartRef.current) {
- metricsSummaryChartRef.current.destroy();
- }
- if (clientCountChartRef.current) {
- clientCountChartRef.current.destroy();
- }
- if (totalPowerUsageChartRef.current) {
- totalPowerUsageChartRef.current.destroy();
- }
- if (averageVoltageChartRef.current) {
- averageVoltageChartRef.current.destroy();
- }
+ Object.values(chartRefs).forEach((ref) => {
+ if (ref.current) {
+ ref.current.destroy();
+ }
+ });
};
}, [userId, dispatch]);
- const chartOptions = {
- responsive: true,
- maintainAspectRatio: true,
- plugins: {
- legend: {
- position: "bottom",
- },
- title: {
- display: true,
- text: "Chart",
- font: {
- size: 14,
+ // Chart configuration objects
+ const chartConfigs = {
+ standard: {
+ responsive: true,
+ maintainAspectRatio: true,
+ plugins: {
+ legend: { position: "bottom" },
+ title: {
+ display: true,
+ text: "Chart",
+ font: { size: 14 },
},
},
- },
- scales: {
- y: {
- beginAtZero: true,
+ scales: {
+ y: { beginAtZero: true },
},
},
- };
- const voltageLineChartOptions = {
- responsive: true,
- maintainAspectRatio: false,
- plugins: {
- legend: {
- position: "bottom",
- },
- title: {
- display: true,
- font: {
- size: 14,
+ voltage: {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: { position: "bottom" },
+ title: {
+ display: true,
+ font: { size: 14 },
},
},
- },
- scales: {
- y: {
- beginAtZero: true,
- min: 200,
- max: 250,
+ scales: {
+ y: {
+ beginAtZero: true,
+ min: 200,
+ max: 250,
+ },
},
},
- };
- const lineChartOptions = {
- responsive: true,
- maintainAspectRatio: false,
- plugins: {
- legend: {
- position: "bottom",
- },
- title: {
- display: true,
- font: {
- size: 14,
+ line: {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: { position: "bottom" },
+ title: {
+ display: true,
+ font: { size: 14 },
},
},
- },
- scales: {
- y: {
- beginAtZero: true,
- // min: 100,
+ scales: {
+ y: { beginAtZero: true },
},
},
};
- const powerByClientData = {
- labels: powerUsageByClient.map((client) => client.client_name),
- datasets: [
- {
- label: "Power Usage (kWh)",
- data: powerUsageByClient.map((client) => client.total_power),
- backgroundColor: [
- "rgba(255, 99, 132, 0.6)",
- "rgba(54, 162, 235, 0.6)",
- "rgba(255, 206, 86, 0.6)",
- "rgba(75, 192, 192, 0.6)",
- "rgba(153, 102, 255, 0.6)",
- "rgba(255, 159, 64, 0.6)",
- ],
- borderColor: [
- "rgba(255, 99, 132, 1)",
- "rgba(54, 162, 235, 1)",
- "rgba(255, 206, 86, 1)",
- "rgba(75, 192, 192, 1)",
- "rgba(153, 102, 255, 1)",
- "rgba(255, 159, 64, 1)",
- ],
- borderWidth: 1,
- },
- ],
- };
+ // Chart data preparation
+ const chartData = {
+ powerByClient: {
+ labels: powerUsageByClient.map((client) => client.client_name),
+ datasets: [
+ {
+ label: "Power Usage (kWh)",
+ data: powerUsageByClient.map((client) => client.total_power),
+ backgroundColor: [
+ "rgba(255, 99, 132, 0.6)",
+ "rgba(54, 162, 235, 0.6)",
+ "rgba(255, 206, 86, 0.6)",
+ "rgba(75, 192, 192, 0.6)",
+ "rgba(153, 102, 255, 0.6)",
+ "rgba(255, 159, 64, 0.6)",
+ ],
+ borderColor: [
+ "rgba(255, 99, 132, 1)",
+ "rgba(54, 162, 235, 1)",
+ "rgba(255, 206, 86, 1)",
+ "rgba(75, 192, 192, 1)",
+ "rgba(153, 102, 255, 1)",
+ "rgba(255, 159, 64, 1)",
+ ],
+ borderWidth: 1,
+ },
+ ],
+ },
- const voltageDistributionData = {
- labels: voltageDistribution.map((v) => v[0]),
- datasets: [
- {
- label: "Frequency",
- data: voltageDistribution.map((v) => v[1]),
- backgroundColor: "rgba(3, 60, 173, 0.8)",
- borderColor: "rgb(201, 203, 207)",
- borderWidth: 1,
- },
- ],
- };
+ voltageDistribution: {
+ labels: voltageDistribution.map((v) => v[0]),
+ datasets: [
+ {
+ label: "Frequency",
+ data: voltageDistribution.map((v) => v[1]),
+ backgroundColor: "rgba(3, 60, 173, 0.8)",
+ borderColor: "rgb(201, 203, 207)",
+ borderWidth: 1,
+ },
+ ],
+ },
- const metricsSummaryPieData = {
- labels: [
- "Min Power",
- "Max Power",
- "Avg Power",
- "Min Voltage",
- "Max Voltage",
- "Avg Voltage",
- ],
- datasets: [
- {
- label: "Metrics",
- data: [
- metricsSummary?.minPower,
- metricsSummary?.maxPower,
- metricsSummary?.avgPower,
- metricsSummary?.minVoltage,
- metricsSummary?.maxVoltage,
- metricsSummary?.avgVoltage,
- ],
- backgroundColor: [
- "rgba(255, 99, 132, 0.7)",
- "rgba(54, 162, 235, 0.7)",
- "rgba(255, 206, 86, 0.7)",
- "rgba(75, 192, 192, 0.7)",
- "rgba(153, 102, 255, 0.7)",
- "rgba(255, 159, 64, 0.7)",
- ],
- borderColor: [
- "rgba(255, 99, 132, 1)",
- "rgba(54, 162, 235, 1)",
- "rgba(255, 206, 86, 1)",
- "rgba(75, 192, 192, 1)",
- "rgba(153, 102, 255, 1)",
- "rgba(255, 159, 64, 1)",
- ],
- borderWidth: 1,
- },
- ],
- };
+ metricsSummary: {
+ labels: [
+ "Min Power",
+ "Max Power",
+ "Avg Power",
+ "Min Voltage",
+ "Max Voltage",
+ "Avg Voltage",
+ ],
+ datasets: [
+ {
+ label: "Metrics",
+ data: [
+ metricsSummary?.minPower,
+ metricsSummary?.maxPower,
+ metricsSummary?.avgPower,
+ metricsSummary?.minVoltage,
+ metricsSummary?.maxVoltage,
+ metricsSummary?.avgVoltage,
+ ],
+ backgroundColor: [
+ "rgba(255, 99, 132, 0.7)",
+ "rgba(54, 162, 235, 0.7)",
+ "rgba(255, 206, 86, 0.7)",
+ "rgba(75, 192, 192, 0.7)",
+ "rgba(153, 102, 255, 0.7)",
+ "rgba(255, 159, 64, 0.7)",
+ ],
+ borderColor: [
+ "rgba(255, 99, 132, 1)",
+ "rgba(54, 162, 235, 1)",
+ "rgba(255, 206, 86, 1)",
+ "rgba(75, 192, 192, 1)",
+ "rgba(153, 102, 255, 1)",
+ "rgba(255, 159, 64, 1)",
+ ],
+ borderWidth: 1,
+ },
+ ],
+ },
- const clientCountData = {
- labels: ["Total Clients"],
- datasets: [
- {
- label: "Number of Clients",
- data: [overviewData?.totalClients || 0],
- backgroundColor: ["rgba(99, 255, 132, 0.7)"],
- borderColor: ["rgba(99, 255, 132, 1)"],
- borderWidth: 1,
- },
- ],
- };
+ clientCount: {
+ labels: ["Total Clients"],
+ datasets: [
+ {
+ label: "Number of Clients",
+ data: [overviewData?.totalClients || 0],
+ backgroundColor: ["rgba(99, 255, 132, 0.7)"],
+ borderColor: ["rgba(99, 255, 132, 1)"],
+ borderWidth: 1,
+ },
+ ],
+ },
- const totalPowerUsageData = {
- labels: Array.isArray(totalPowerUsage)
- ? totalPowerUsage.map((item) =>
- item.timestamp
- ? new Date(item.timestamp).toLocaleDateString()
- : "Invalid"
- )
- : [],
- datasets: [
- {
- label: "Total Power Usage (kWh)",
- data: Array.isArray(totalPowerUsage)
- ? totalPowerUsage.map((item) => item.total_power)
- : [],
- fill: false,
- backgroundColor: "rgba(75, 192, 192, 0.6)",
- borderColor: "rgba(75, 192, 192, 1)",
- tension: 0.1,
- },
- ],
+ totalPowerUsage: {
+ labels: totalPowerUsage.map((item) =>
+ new Date(item.timestamp).toLocaleDateString()
+ ),
+ datasets: [
+ {
+ label: "Total Power Usage (kWh)",
+ data: totalPowerUsage.map((item) => item.total_power),
+ fill: false,
+ backgroundColor: "rgba(75, 192, 192, 0.6)",
+ borderColor: "rgba(75, 192, 192, 1)",
+ tension: 0.1,
+ },
+ ],
+ },
+
+ averageVoltage: {
+ labels: averageVoltage.map((item) =>
+ new Date(item.timestamp).toLocaleDateString()
+ ),
+ datasets: [
+ {
+ label: "Average Voltage (V)",
+ data: averageVoltage.map((item) => item.average_voltage),
+ fill: false,
+ backgroundColor: "rgba(255, 159, 64, 0.6)",
+ borderColor: "rgba(255, 159, 64, 1)",
+ tension: 0.1,
+ },
+ ],
+ },
};
- const averageVoltageData = {
- labels: Array.isArray(averageVoltage)
- ? averageVoltage.map((item) =>
- new Date(item.timestamp).toLocaleDateString()
- )
- : [],
- datasets: [
- {
- label: "Average Voltage (V)",
- data: Array.isArray(averageVoltage)
- ? averageVoltage.map((item) => item.average_voltage)
- : [],
- fill: false,
- backgroundColor: "rgba(255, 159, 64, 0.6)",
- borderColor: "rgba(255, 159, 64, 1)",
- tension: 0.1,
- },
- ],
+ // Helper function to check if data is available
+ const hasData = (data) => {
+ if (Array.isArray(data)) {
+ return data.length > 0;
+ }
+ return data !== null && data !== undefined;
};
return (
-
Dashboard
+
Dashboard
+
+ {/* Loading state */}
{loading && (
Loading dashboard data...
)}
+
+ {/* Error state */}
{error && (
Error loading dashboard data: {error}
)}
+
+ {/* Dashboard content */}
{!loading && !error && (
+ {/* Power Usage By Client Chart */}
Client Power Usage Distribution
- {powerUsageByClient.length > 0 ? (
+ {hasData(powerUsageByClient) ? (
) : (
No power usage data available for clients this month.
)}
+ {/* Voltage Distribution Chart */}
Voltage Frequency Distribution
- {voltageDistribution.length > 0 ? (
+ {hasData(voltageDistribution) ? (
) : (
No voltage distribution data available.
)}
+ {/* Metrics Summary Chart */}
Key Metrics Snapshot
- {metricsSummary ? (
+ {hasData(metricsSummary) ? (
) : (
No metrics summary data available.
)}
+ {/* Client Count Chart */}
Total Client Count
- {overviewData ? (
+ {hasData(overviewData) ? (
) : (
No overview data available to display client count.
)}
+ {/* Total Power Usage Chart */}
Total Power Usage Over Time
- {totalPowerUsage !== null && totalPowerUsage !== undefined ? (
+ {hasData(totalPowerUsage) ? (
) : (
No total power usage data available.
)}
+ {/* Average Voltage Chart */}
Average Voltage Over Time
- {averageVoltage !== null && averageVoltage !== undefined ? (
+ {hasData(averageVoltage) ? (
) : (
No average voltage data available.
)}
+ {/* Metric Cards */}
Total Users
@@ -497,9 +431,10 @@ const ProviderDashboard = () => {
+ {/* All Metrics Table */}
All Metrics
- {allMetrics && Object.keys(allMetrics).length > 0 ? (
+ {hasData(allMetrics) ? (
diff --git a/amp-client/src/Pages/ProviderPages/ProviderDashboard/styles.css b/amp-client/src/Pages/ProviderPages/ProviderDashboard/styles.css
index cf34789a..e6ddc0fb 100644
--- a/amp-client/src/Pages/ProviderPages/ProviderDashboard/styles.css
+++ b/amp-client/src/Pages/ProviderPages/ProviderDashboard/styles.css
@@ -6,6 +6,10 @@
margin-right: 15px;
}
+.un-centered {
+ text-align: left;
+}
+
.spinner-container {
display: flex;
flex-direction: column;
diff --git a/amp-client/src/Pages/ProviderPages/ProviderPowerPrediction/ProviderPowerPrediction.jsx b/amp-client/src/Pages/ProviderPages/ProviderPowerPrediction/ProviderPowerPrediction.jsx
index 4bafcda1..b5e0845e 100644
--- a/amp-client/src/Pages/ProviderPages/ProviderPowerPrediction/ProviderPowerPrediction.jsx
+++ b/amp-client/src/Pages/ProviderPages/ProviderPowerPrediction/ProviderPowerPrediction.jsx
@@ -1,8 +1,8 @@
import "./styles.css";
import { useState } from "react";
-import axiosBaseUrl from "../../../Axios/axios";
import { useDispatch, useSelector } from "react-redux";
import { toggleLoad } from "../../../Redux/Slices/loadingSlice";
+import ProviderPowerPredictionService from "../Services/ProviderPowerPredictionService/ProviderPowerPredictionService";
const ProviderPowerPrediction = () => {
const [predictionData, setPredictionData] = useState(null);
@@ -14,11 +14,10 @@ const ProviderPowerPrediction = () => {
setPredictionData(null);
try {
- const response = await axiosBaseUrl.get("/providers/providerReport");
- const data = response.data;
- setPredictionData(data.data);
+ const data = await ProviderPowerPredictionService.fetchPowerPrediction();
+ setPredictionData(data);
} catch (error) {
- console.error("Error fetching power prediction:", error);
+ console.error("Error fetching power prediction:", error.message);
setPredictionData(null);
} finally {
dispatch(toggleLoad(false));
@@ -27,9 +26,6 @@ const ProviderPowerPrediction = () => {
return (
- {/*
-
-
*/}
Power Prediction
@@ -83,8 +79,8 @@ const ProviderPowerPrediction = () => {
{predictionData.recommendations
.split("\n")
- .map((recommendation, index) => (
- - {recommendation}
+ .map((rec, idx) => (
+ - {rec}
))}
diff --git a/amp-client/src/Pages/ProviderPages/Services/ProviderDashboardService/ProviderDashboardService.js b/amp-client/src/Pages/ProviderPages/Services/ProviderDashboardService/ProviderDashboardService.js
new file mode 100644
index 00000000..97032e3d
--- /dev/null
+++ b/amp-client/src/Pages/ProviderPages/Services/ProviderDashboardService/ProviderDashboardService.js
@@ -0,0 +1,178 @@
+import axiosInstance from "../../../../Axios/axios";
+
+const ProviderDashboardService = {
+ getOverviewData: async (userId) => {
+ try {
+ const response = await axiosInstance.get(`/providers/overview/${userId}`);
+ return response.data.data;
+ } catch (error) {
+ throw ProviderDashboardService.formatError(error, "overview data");
+ }
+ },
+
+ getPowerUsageByClient: async (userId) => {
+ try {
+ const response = await axiosInstance.get(
+ `/providers/powerUsageByClient/${userId}`
+ );
+ return response.data.data;
+ } catch (error) {
+ throw ProviderDashboardService.formatError(
+ error,
+ "power usage by client"
+ );
+ }
+ },
+
+ getVoltageDistribution: async (userId) => {
+ try {
+ const response = await axiosInstance.get(
+ `/providers/voltageDistribution/${userId}`
+ );
+ const voltageData = response.data.data.map((v) => v.voltage);
+
+ // Process voltage data into frequency distribution
+ const voltageCounts = {};
+ voltageData.forEach((v) => {
+ const roundedVoltage = Math.round(v);
+ voltageCounts[roundedVoltage] =
+ (voltageCounts[roundedVoltage] || 0) + 1;
+ });
+
+ // Sort by voltage value (ascending)
+ return Object.entries(voltageCounts).sort(
+ (a, b) => parseInt(a[0]) - parseInt(b[0])
+ );
+ } catch (error) {
+ throw ProviderDashboardService.formatError(error, "voltage distribution");
+ }
+ },
+
+ getMetricsSummary: async (userId) => {
+ try {
+ const response = await axiosInstance.get(
+ `/providers/metricsSummary/${userId}`
+ );
+ return response.data.data;
+ } catch (error) {
+ throw ProviderDashboardService.formatError(error, "metrics summary");
+ }
+ },
+
+ getTotalPowerUsage: async (userId) => {
+ try {
+ const response = await axiosInstance.get(
+ `/providers/totalPowerUsage/${userId}`
+ );
+ return Object.entries(response.data.data).map(([date, power]) => ({
+ timestamp: new Date(date).toISOString(),
+ total_power: power,
+ }));
+ } catch (error) {
+ throw ProviderDashboardService.formatError(error, "total power usage");
+ }
+ },
+
+ getAverageVoltage: async (userId) => {
+ try {
+ const response = await axiosInstance.get(
+ `/providers/averageVoltage/${userId}`
+ );
+ return Object.entries(response.data.data).map(([date, voltage]) => ({
+ timestamp: new Date(date).toISOString(),
+ average_voltage: voltage,
+ }));
+ } catch (error) {
+ throw ProviderDashboardService.formatError(error, "average voltage");
+ }
+ },
+
+ getTotalUsers: async (userId) => {
+ try {
+ const response = await axiosInstance.get(
+ `/providers/getAllUsers/${userId}`
+ );
+ return response?.data?.data?.length || 0;
+ } catch (error) {
+ throw ProviderDashboardService.formatError(error, "total users");
+ }
+ },
+
+ getAllMetrics: async (userId) => {
+ try {
+ const response = await axiosInstance.get(
+ `/providers/getAllMetrics/${userId}`
+ );
+ return Array.isArray(response?.data?.data) ? response.data.data : [];
+ } catch (error) {
+ throw ProviderDashboardService.formatError(error, "all metrics");
+ }
+ },
+
+ getTotalLines: async (userId) => {
+ try {
+ const response = await axiosInstance.get(
+ `/providers/getAllLines/${userId}`
+ );
+ return response?.data?.data?.length || 0;
+ } catch (error) {
+ throw ProviderDashboardService.formatError(error, "total lines");
+ }
+ },
+
+ formatError: (error, dataType) => {
+ let errorMessage = `Failed to fetch ${dataType}`;
+
+ if (error.code === "ECONNABORTED") {
+ errorMessage = `Request for ${dataType} timed out. Please try again.`;
+ } else if (error.response) {
+ errorMessage = `Server error (${error.response.status}) while fetching ${dataType}`;
+ }
+
+ const formattedError = new Error(errorMessage);
+ formattedError.originalError = error;
+ return formattedError;
+ },
+
+ fetchAllDashboardData: async (userId) => {
+ try {
+ const [
+ overviewData,
+ powerUsageByClient,
+ voltageDistribution,
+ metricsSummary,
+ totalPowerUsage,
+ averageVoltage,
+ totalUsers,
+ allMetrics,
+ totalLines,
+ ] = await Promise.all([
+ ProviderDashboardService.getOverviewData(userId),
+ ProviderDashboardService.getPowerUsageByClient(userId),
+ ProviderDashboardService.getVoltageDistribution(userId),
+ ProviderDashboardService.getMetricsSummary(userId),
+ ProviderDashboardService.getTotalPowerUsage(userId),
+ ProviderDashboardService.getAverageVoltage(userId),
+ ProviderDashboardService.getTotalUsers(userId),
+ ProviderDashboardService.getAllMetrics(userId),
+ ProviderDashboardService.getTotalLines(userId),
+ ]);
+
+ return {
+ overviewData,
+ powerUsageByClient,
+ voltageDistribution,
+ metricsSummary,
+ totalPowerUsage,
+ averageVoltage,
+ totalUsers,
+ allMetrics,
+ totalLines,
+ };
+ } catch (error) {
+ throw error;
+ }
+ },
+};
+
+export default ProviderDashboardService;
diff --git a/amp-client/src/Pages/ProviderPages/Services/ProviderPowerPredictionService/ProviderPowerPredictionService.js b/amp-client/src/Pages/ProviderPages/Services/ProviderPowerPredictionService/ProviderPowerPredictionService.js
new file mode 100644
index 00000000..6685ed0f
--- /dev/null
+++ b/amp-client/src/Pages/ProviderPages/Services/ProviderPowerPredictionService/ProviderPowerPredictionService.js
@@ -0,0 +1,15 @@
+// ProviderPowerPredictionService.js
+import axiosInstance from "../../../../Axios/axios";
+
+const ProviderPowerPredictionService = {
+ async fetchPowerPrediction() {
+ try {
+ const response = await axiosInstance.get("/providers/providerReport");
+ return response.data.data;
+ } catch (error) {
+ throw new Error(error.response?.data?.message || error.message);
+ }
+ },
+};
+
+export default ProviderPowerPredictionService;
diff --git a/amp-client/src/Pages/ProviderPages/Services/ProviderProfile/ProviderProfile.js b/amp-client/src/Pages/ProviderPages/Services/ProviderProfile/ProviderProfile.js
new file mode 100644
index 00000000..a8045130
--- /dev/null
+++ b/amp-client/src/Pages/ProviderPages/Services/ProviderProfile/ProviderProfile.js
@@ -0,0 +1 @@
+import axiosInstance from "../../../../Axios/axios";
\ No newline at end of file
diff --git a/amp-client/src/Pages/ProviderPages/Services/ProviderUsersService/ProviderUsersService.js b/amp-client/src/Pages/ProviderPages/Services/ProviderUsersService/ProviderUsersService.js
new file mode 100644
index 00000000..a8045130
--- /dev/null
+++ b/amp-client/src/Pages/ProviderPages/Services/ProviderUsersService/ProviderUsersService.js
@@ -0,0 +1 @@
+import axiosInstance from "../../../../Axios/axios";
\ No newline at end of file
diff --git a/amp-laravel/app/Http/Requests/ContactMessageRequest.php b/amp-laravel/app/Http/Requests/ContactMessageRequest.php
index b8fe3386..aaa6b7f1 100644
--- a/amp-laravel/app/Http/Requests/ContactMessageRequest.php
+++ b/amp-laravel/app/Http/Requests/ContactMessageRequest.php
@@ -25,7 +25,7 @@ public function rules(): array
'name' => 'required|string|max:255',
'email' => 'required|email|max:255',
'phone_number' => 'required|string|max:20',
- 'message' => 'sometimes|required|string|max:1000',
+ 'message' => 'nullable|string|max:1000',
];
}
}
diff --git a/amp-laravel/app/Http/Requests/Provider/EditProfileRequest.php b/amp-laravel/app/Http/Requests/Provider/EditProfileRequest.php
index a531c093..4875858d 100644
--- a/amp-laravel/app/Http/Requests/Provider/EditProfileRequest.php
+++ b/amp-laravel/app/Http/Requests/Provider/EditProfileRequest.php
@@ -22,7 +22,6 @@ public function authorize(): bool
public function rules(): array
{
return [
- 'name' => 'sometimes|required|string|max:255',
'email' => 'sometimes|required|email|max:255',
'password' => 'sometimes|nullable|string|min:6',
'phone_number' => 'sometimes|required|string|max:20',
diff --git a/amp-laravel/app/Services/Provider/ProviderEditProfileService.php b/amp-laravel/app/Services/Provider/ProviderEditProfileService.php
index 14c37b6f..b78baeed 100644
--- a/amp-laravel/app/Services/Provider/ProviderEditProfileService.php
+++ b/amp-laravel/app/Services/Provider/ProviderEditProfileService.php
@@ -10,10 +10,6 @@ public static function editProfile(array $data)
{
$user = JWTAuth::user();
- if (isset($data['name'])) {
- $user->name = $data['name'];
- }
-
if (isset($data['email'])) {
$user->email = $data['email'];
}
diff --git a/amp-laravel/database/migrations/2025_04_28_175033_create_contact_forms_table.php b/amp-laravel/database/migrations/2025_04_28_175033_create_contact_forms_table.php
index a6f7c3f7..1d3c8cb5 100644
--- a/amp-laravel/database/migrations/2025_04_28_175033_create_contact_forms_table.php
+++ b/amp-laravel/database/migrations/2025_04_28_175033_create_contact_forms_table.php
@@ -16,7 +16,7 @@ public function up(): void
$table->string('name');
$table->string('email');
$table->string('phone_number');
- $table->text('message');
+ $table->text('message')->nullable();
$table->timestamps();
});
}
diff --git a/amp-laravel/routes/api.php b/amp-laravel/routes/api.php
index d762b32c..842dba67 100644
--- a/amp-laravel/routes/api.php
+++ b/amp-laravel/routes/api.php
@@ -58,7 +58,7 @@
Route::post("/lines", [IotController::class, "masterLines"]);
// Public Route for Contact Message Submission
- // Route::post("/insertMessage", [AuthController::class, "insertMessage"]);
+ Route::post("/insertMessage", [AuthController::class, "insertMessage"]);
//Unauthenticated Users
Route::post("/login", [AuthController::class, "login"])->name("login");