diff --git a/frontend/src/lib/api.js b/frontend/src/lib/api.js
index ef18fd4..e3d9c37 100644
--- a/frontend/src/lib/api.js
+++ b/frontend/src/lib/api.js
@@ -65,15 +65,44 @@ async function request(endpoint, token, options = {}) {
}
export function createProject(token, { name, city_input }) {
+ if (!name.trim() || !city_input.trim()) {
+ console.error("Field cannot be empty")
+ return
+ }
return request("/projects", token, {
method: "POST",
body: JSON.stringify({ name, city_input })
})
}
-export function updateProject(token, projectId, updates) {
- return request(`/projects/${projectId}`, token, {
+export function updateResource(token, endpoint, updates) {
+ if (!updates || typeof updates !== "object" || Object.keys(updates).length === 0) {
+ console.error("No updates provided")
+ return
+ }
+
+ return request(endpoint, token, {
method: "PATCH",
body: JSON.stringify(updates)
})
+}
+
+export function updateResourceField(token, endpoint, field, value, options = {}) {
+ const { trim = false, normalize = (currentValue) => currentValue } = options
+
+ if (value === null || value === undefined) {
+ return
+ }
+
+ let normalizedValue = normalize(value)
+
+ if (trim && typeof normalizedValue === "string") {
+ normalizedValue = normalizedValue.trim()
+ }
+
+ return updateResource(token, endpoint, { [field]: normalizedValue })
+}
+
+export function updateProject(token, projectId, updates) {
+ return updateResource(token, `/projects/${projectId}`, updates)
}
\ No newline at end of file
diff --git a/frontend/src/screens/CreateScenario.jsx b/frontend/src/screens/CreateScenario.jsx
index ef8dd69..4235fdf 100644
--- a/frontend/src/screens/CreateScenario.jsx
+++ b/frontend/src/screens/CreateScenario.jsx
@@ -37,6 +37,19 @@ export default function CreateScenario() {
const { token } = useContext(AuthContext)
const { data: project, loading: loading, error: error } = useApi(`/api/projects/${projectId}`)
+ const [scenarioName, setScenarioName] = useState("Scenario Name")
+
+ async function handleNameSubmit(e) {
+ e?.preventDefault?.()
+
+ try {
+ await updateResourceField(token, `/projects/${projectId}/scenarios/${scenarioId}`, "name", scenarioName, { trim: true })
+ } catch (error) {
+ console.error("Error updating scenario name:", error)
+ }
+ console.log("Scenario name updated:", scenarioName)
+ }
+
if (loading) return
Loading...
if (error) return Something went wrong.
@@ -62,9 +75,9 @@ export default function CreateScenario() {
@@ -76,17 +89,9 @@ export default function CreateScenario() {
System configuration
- {/* */}
-
Module amount
-
+
Quantity of modules in the system
@@ -99,10 +104,10 @@ export default function CreateScenario() {
- Orientation
+ Azimuth
- The angle relative to the South, in degrees. South orientation is 0°
+ Orientation relative to the South, in degrees. South orientation is 0°
@@ -125,12 +130,6 @@ export default function CreateScenario() {
Selected solar module
- {/*
-
- Technology
- Nominal power
-
- */}
Technology
diff --git a/frontend/src/screens/Project.jsx b/frontend/src/screens/Project.jsx
index 02c79a9..845f724 100644
--- a/frontend/src/screens/Project.jsx
+++ b/frontend/src/screens/Project.jsx
@@ -14,20 +14,23 @@ import Header from "../components/Header";
import ScenarioCard from "../components/ScenarioCard";
import { AuthContext } from "../lib/AuthContext"
-import { useApi } from "../lib/api"
+import { useApi, updateResourceField } from "../lib/api"
const Project = () => {
const { projectId, scenarioId } = useParams();
const { token } = useContext(AuthContext)
- const { data: project, loading: projLoading, error: projError } = useApi(`/api/projects/${params.projectId}`)
- const { data: scenarios, loading: scenLoading, error: scenError } = useApi(`/api/projects/${params.projectId}/scenarios`)
+ const { data: project, loading: projLoading, error: projError } = useApi(`/api/projects/${projectId}`)
+ const { data: scenarios, loading: scenLoading, error: scenError } = useApi(`/api/projects/${projectId}/scenarios`)
const [projectName, setProjectName] = useState("")
const [projectLocation, setProjectLocation] = useState("")
useEffect(() => {
- if (project) setProjectName(project.name)
+ if (project) {
+ setProjectName(project.name ?? "")
+ setProjectLocation(project.location ?? "")
+ }
}, [project])
useEffect(() => {
@@ -40,53 +43,23 @@ const Project = () => {
async function handleNameSubmit(e) {
e.preventDefault()
- if (!projectName.trim()) {
- console.error("Project name cannot be empty")
- return
- }
-
try {
- const response = await fetch(`/api/projects/${params.projectId}`, {
- method: "PATCH",
- headers: {
- "Content-Type": "application/json",
- Authorization: `Bearer ${token}`
- },
- body: JSON.stringify({ name: projectName.trim() })
- })
-
- if (!response.ok) {
- console.error("Failed to update project name")
- }
+ await updateResourceField(token, `/projects/${projectId}`, "name", projectName, { trim: true })
} catch (error) {
console.error("Error updating project name:", error)
}
+ console.log("Project name updated:", projectName)
}
- async function handleLocationSubmit(e) {
+ async function handleLocationSubmit(e) {
e.preventDefault()
- if (!projectLocation.trim()) {
- console.error("Project location cannot be empty")
- return
- }
-
try {
- const response = await fetch(`/api/projects/${params.projectId}`, {
- method: "PATCH",
- headers: {
- "Content-Type": "application/json",
- Authorization: `Bearer ${token}`
- },
- body: JSON.stringify({ location: projectLocation.trim() })
- })
-
- if (!response.ok) {
- console.error("Failed to update project location")
- }
+ await updateResourceField(token, `/projects/${projectId}`, "location", projectLocation, { trim: true })
} catch (error) {
console.error("Error updating project location:", error)
}
+ console.log("Location updated:", projectLocation)
}
return (
diff --git a/frontend/src/screens/Scenario.jsx b/frontend/src/screens/Scenario.jsx
index f7266de..47c1dbd 100644
--- a/frontend/src/screens/Scenario.jsx
+++ b/frontend/src/screens/Scenario.jsx
@@ -1,3 +1,198 @@
+import { useContext, useEffect, useState } from "react";
+import { Link, useParams } from "react-router"
+
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+} from "@/components/ui/breadcrumb"
+import { Button } from "@/components/ui/button"
+import {
+ Field,
+ FieldDescription,
+ FieldGroup,
+ FieldLabel,
+} from "@/components/ui/field"
+import Header from "../components/Header";
+import { Input } from "@/components/ui/input"
+import {
+ Table,
+ TableBody,
+ TableCaption,
+ TableCell,
+ TableFooter,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+
+import { AuthContext } from "../lib/AuthContext"
+import { useApi, updateResourceField } from "../lib/api"
+
export default function Scenario() {
- return Scenario Screen ;
-}
+ const { projectId, scenarioId } = useParams();
+ const { token } = useContext(AuthContext)
+ const { data: project, loading: projLoading, error: projError } = useApi(`/api/projects/${projectId}`)
+ const { data: scenario, loading: scenLoading, error: scenError } = useApi(`/api/projects/${projectId}/scenarios/${scenarioId}`)
+
+ const [scenarioName, setScenarioName] = useState("")
+ const [moduleAmount, setModuleAmount] = useState("")
+ const [tilt, setTilt] = useState("")
+ const [orientation, setOrientation] = useState("")
+ const [manufacturer, setManufacturer] = useState("")
+ const [model, setModel] = useState("")
+
+ useEffect(() => {
+ if (scenario) {
+ setScenarioName(scenario.name ?? "")
+ setModuleAmount(scenario.module_amount ?? "")
+ setTilt(scenario.tilt ?? "")
+ setOrientation(scenario.azimuth ?? "")
+ setManufacturer(scenario.manufacturer ?? "")
+ setModel(scenario.model ?? "")
+ }
+ }, [scenario])
+
+ async function handleNameSubmit(e) {
+ e?.preventDefault?.()
+
+ try {
+ await updateResourceField(token, `/projects/${projectId}/scenarios/${scenarioId}`, "name", scenarioName, { trim: true })
+ } catch (error) {
+ console.error("Error updating scenario name:", error)
+ }
+ console.log("Scenario name updated:", scenarioName)
+ }
+
+ async function handleScenarioFieldUpdate(field, value, options = {}) {
+ try {
+ await updateResourceField(token, `/projects/${projectId}/scenarios/${scenarioId}`, field, value, options)
+ } catch (error) {
+ console.error(`Error updating scenario ${field}:`, error)
+ }
+ }
+
+ if (projLoading || scenLoading) return Loading...
+ if (projError || scenError) return Something went wrong.
+
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+}
\ No newline at end of file