From 33f9119a646e05aeadbde7de977ad4f99d320f95 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 4 Feb 2026 12:56:58 +0000 Subject: [PATCH] v1 --- frontend/src/menuAside.ts | 8 +- frontend/src/pages/configurator.tsx | 253 ++++++++++++++++++++++++++++ frontend/src/pages/index.tsx | 211 +++++++++-------------- 3 files changed, 337 insertions(+), 135 deletions(-) create mode 100644 frontend/src/pages/configurator.tsx diff --git a/frontend/src/menuAside.ts b/frontend/src/menuAside.ts index 4bfe054..38d5bcb 100644 --- a/frontend/src/menuAside.ts +++ b/frontend/src/menuAside.ts @@ -7,6 +7,12 @@ const menuAside: MenuAsideItem[] = [ icon: icon.mdiViewDashboardOutline, label: 'Dashboard', }, + { + href: '/configurator', + icon: icon.mdiSolarPanelLarge, + label: 'Configurator Nou', + permissions: 'CREATE_CONFIGURATIONS' + }, { href: '/users/users-list', @@ -152,4 +158,4 @@ const menuAside: MenuAsideItem[] = [ }, ] -export default menuAside +export default menuAside \ No newline at end of file diff --git a/frontend/src/pages/configurator.tsx b/frontend/src/pages/configurator.tsx new file mode 100644 index 0000000..d78d138 --- /dev/null +++ b/frontend/src/pages/configurator.tsx @@ -0,0 +1,253 @@ +import { mdiSolarPanelLarge, mdiChevronRight, mdiChevronLeft, mdiCheckCircleOutline, mdiInformationOutline } from '@mdi/js'; +import Head from 'next/head'; +import React, { ReactElement, useState, useEffect } from 'react'; +import CardBox from '../components/CardBox'; +import LayoutAuthenticated from '../layouts/Authenticated'; +import SectionMain from '../components/SectionMain'; +import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'; +import { getPageTitle } from '../config'; +import BaseButton from '../components/BaseButton'; +import BaseButtons from '../components/BaseButtons'; +import FormField from '../components/FormField'; +import BaseIcon from '../components/BaseIcon'; +import { useAppDispatch, useAppSelector } from '../stores/hooks'; +import { create as createProject } from '../stores/projects/projectsSlice'; +import { fetch as fetchProducts } from '../stores/products/productsSlice'; +import { fetch as fetchCategories } from '../stores/product_categories/product_categoriesSlice'; +import { create as createConfiguration } from '../stores/configurations/configurationsSlice'; +import { useRouter } from 'next/router'; + +const ConfiguratorPage = () => { + const dispatch = useAppDispatch(); + const router = useRouter(); + const [step, setStep] = useState(1); + + // Form State + const [projectData, setProjectData] = useState({ + name: '', + address: '', + avg_monthly_consumption_kwh: '', + roof_type: 'tabla', + }); + + const [selection, setSelection] = useState({ + panelId: '', + panelQuantity: 10, + inverterId: '', + batteryId: '', + }); + + const { products } = useAppSelector((state) => state.products); + const { product_categories } = useAppSelector((state) => state.product_categories); + + useEffect(() => { + dispatch(fetchCategories({})); + dispatch(fetchProducts({})); + }, [dispatch]); + + const panels = products.filter(p => { + const cat = product_categories.find(c => c.id === p.categoryId); + return cat?.name?.toLowerCase().includes('panel') || cat?.name?.toLowerCase().includes('panouri'); + }); + + const inverters = products.filter(p => { + const cat = product_categories.find(c => c.id === p.categoryId); + return cat?.name?.toLowerCase().includes('inverter') || cat?.name?.toLowerCase().includes('invertor'); + }); + + const nextStep = () => setStep(step + 1); + const prevStep = () => setStep(step - 1); + + const handleProjectChange = (e: React.ChangeEvent) => { + setProjectData({ ...projectData, [e.target.name]: e.target.value }); + }; + + const handleSelectionChange = (e: React.ChangeEvent) => { + setSelection({ ...selection, [e.target.name]: e.target.value }); + }; + + const calculateTotalPower = () => { + const selectedPanel = panels.find(p => p.id === selection.panelId); + if (selectedPanel && selection.panelQuantity) { + return (parseFloat(selectedPanel.rated_power_kw || '0') * parseInt(selection.panelQuantity as any)).toFixed(2); + } + return '0.00'; + }; + + const handleSubmit = async () => { + // 1. Create Project + const projectResult = await dispatch(createProject(projectData)); + if (createProject.fulfilled.match(projectResult)) { + const projectId = (projectResult.payload as any).id; + + // 2. Create Configuration + const configData = { + projectId, + status: 'draft', + panel_quantity: selection.panelQuantity, + total_power_kw: calculateTotalPower(), + }; + const configResult = await dispatch(createConfiguration(configData)); + if (createConfiguration.fulfilled.match(configResult)) { + router.push('/configurations/configurations-list'); + } + } + }; + + const renderStep = () => { + switch (step) { + case 1: + return ( +
+
+ +

Informații Proiect & Client

+
+ + + + +