diff --git a/client/react/src/forms/NewLightForm.js b/client/react/src/forms/NewLightForm.js new file mode 100644 index 0000000..c2dbb9f --- /dev/null +++ b/client/react/src/forms/NewLightForm.js @@ -0,0 +1,140 @@ +import React, { useState, useEffect } from 'react'; +import Modal from '@mui/material/Modal'; +import TextField from '@mui/material/TextField'; +import Box from '@mui/material/Box'; +import IconButton from '@mui/material/IconButton'; +import ButtonGroup from '@mui/material/ButtonGroup'; +import CheckSharpIcon from '@mui/icons-material/CheckSharp'; +import CloseSharpIcon from '@mui/icons-material/CloseSharp'; +import Autocomplete from '@mui/material/Autocomplete'; +import TungstenSharpIcon from '@mui/icons-material/TungstenSharp'; + + +const NewLightForm = ({ isOpen, onRequestClose }) => { + + const [name, setName] = useState(''); + const [system, setSystem] = useState(null); + const [cost, setCost] = useState(0); + + const [allSystems, setAllSystems] = useState([]); + + const [submitted, setSubmitted] = useState(false); + + useEffect(() => { + fetch('http://127.0.0.1:5000/system') + .then((response) => response.json()) + .then((data) => setAllSystems(data)) + .catch((error) => console.error('Error fetching all system data:', error)); + + }, []); + + useEffect(() => { + if (submitted) { + const requestOptions = { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({name: name, cost: cost, system_id: system.id }) + }; + fetch('http://127.0.0.1:5000/light', requestOptions) + .then(response => response.json()) + .then(data => { + // handle the response data if needed + // maybe update some state based on the response + console.log(data); + }) + .catch(error => console.error('Error posting plants data:', error)); + clearForm(); + onRequestClose(); + } + }, [submitted, name, cost, system, onRequestClose]); + + const handleSubmit = (event) => { + event.preventDefault(); + setSubmitted(true); // Update submitted state + }; + + const handleCancel = () => { + clearForm(); + onRequestClose(); + }; + + const clearForm = () => { + setName(''); + setCost(0); + setSystem(null); + setSubmitted(false); + }; + + return ( + + +
+
+ + + + + + + + + +
+
+ setName(event.target.value)} + /> + option.name)} + onChange={(event) => setSystem(allSystems[event.target.value])} + renderInput={(params) => ( + + )} + /> + setCost(event.target.value)} + variant="standard" + /> +
+
+
+
+ ); +}; + +export default NewLightForm; diff --git a/client/react/src/forms/NewSystemForm.js b/client/react/src/forms/NewSystemForm.js index 5f5c8f7..c363aa6 100644 --- a/client/react/src/forms/NewSystemForm.js +++ b/client/react/src/forms/NewSystemForm.js @@ -13,7 +13,11 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { const [name, setName] = useState(''); const [humidity, setHumidity] = useState(0); const [temperature, setTempurature] = useState(0); + const [duration, setDuration] = useState(0); + const [distance, setDistance] = useState(0); + const [allSystems, setAllSystems] = useState([]); + const [submitted, setSubmitted] = useState(false); useEffect(() => { @@ -31,7 +35,7 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name: name, humidity: humidity, temperature: temperature }) + body: JSON.stringify({ name: name, humidity: humidity, temperature: temperature, distance: distance, duration: duration }) }; fetch('http://127.0.0.1:5000/system', requestOptions) .then(response => response.json()) @@ -44,7 +48,7 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { clearForm(); onRequestClose(); } - }, [submitted, name, temperature, humidity, onRequestClose]); + }, [submitted, name, temperature, humidity, distance, duration, onRequestClose]); const handleSubmit = (event) => { event.preventDefault(); @@ -60,6 +64,8 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { setName(''); setTempurature(0); setHumidity(0); + setDistance(0); + setDuration(0); setSubmitted(false); }; @@ -120,6 +126,26 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => { onChange={(event) => setTempurature(event.target.value)} variant="standard" /> + setDuration(event.target.value)} + variant="standard" + /> + setDistance(event.target.value)} + variant="standard" + /> diff --git a/client/react/src/pages/Home.js b/client/react/src/pages/Home.js index 182c082..9c5375e 100644 --- a/client/react/src/pages/Home.js +++ b/client/react/src/pages/Home.js @@ -15,6 +15,9 @@ import Box from '@mui/material/Box'; import CloseSharpIcon from '@mui/icons-material/CloseSharp'; import VisibilitySharpIcon from '@mui/icons-material/VisibilitySharp'; import ReportGmailerrorredSharpIcon from '@mui/icons-material/ReportGmailerrorredSharp'; +import NewLightForm from '../forms/NewLightForm'; +import TungstenSharpIcon from '@mui/icons-material/TungstenSharp'; + const Home = () => { // Navigation @@ -30,6 +33,7 @@ const Home = () => { const [isNewPlantFormOpen, setIsNewPlantFormOpen] = useState(false); const [isNewSystemFormOpen, setIsNewSystemFormOpen] = useState(false); const [isNewGenusFormOpen, setIsNewGenusFormOpen] = useState(false); + const [isNewLightFormOpen, setIsNewLightFormOpen] = useState(false); useEffect(() => { // Fetch plant data from the server @@ -76,6 +80,9 @@ const Home = () => { setIsNewGenusFormOpen(true)}> + setIsNewLightFormOpen(true)}> + + setIsCreateButtonsOpen(false)}> @@ -108,6 +115,10 @@ const Home = () => { isOpen={isNewGenusFormOpen} onRequestClose={() => setIsNewGenusFormOpen(false)} /> + setIsNewLightFormOpen(false)} + /> ); diff --git a/server/app.py b/server/app.py index ff0dc47..2f015be 100644 --- a/server/app.py +++ b/server/app.py @@ -16,7 +16,7 @@ # Local application imports from models.plant import Plant, Genus -from models.system import System +from models.system import System, Light # Load database configuration from JSON file with open("db.json", encoding="utf-8") as json_data_file: @@ -32,6 +32,7 @@ port=db_config["port"], ) engine = create_engine(url) + # Base.metadata.drop_all(engine) # Base.metadata.create_all(engine) @@ -173,6 +174,8 @@ def create_system(): name=new_system_json["name"], temperature=new_system_json["temperature"], humidity=new_system_json["humidity"], + duration=new_system_json["duration"], + distance=new_system_json["distance"] ) # Add the new system object to the session @@ -183,6 +186,44 @@ def create_system(): return jsonify({"message": "System added successfully"}), 201 +@app.route("/light", methods=["GET"]) +def get_light(): + """ + Retrieve all lights from the database. + """ + logger.info("Received request to retrieve all lights") + + session = Session() + lights = session.query(Light).all() + session.close() + # Transform lights to JSON format + lights_json = [light.to_json() for light in lights] + # Return JSON response + return jsonify(lights_json) + +@app.route("/light", methods=["POST"]) +def create_light(): + """ + Create a new light and add it to the database. + """ + logger.info("Attempting to create light") + + new_light_json = request.get_json() + + # Create a new Light object + new_light = Light( + name=new_light_json["name"], + cost=new_light_json["cost"], + system_id=new_light_json["system_id"], + ) + + # Add the new Light object to the session + db = Session() + db.add(new_light) + db.commit() + db.close() + + return jsonify({"message": "Light added successfully"}), 201 if __name__ == "__main__": # Run the Flask app diff --git a/server/models/system.py b/server/models/system.py index 5a629c3..b5ef602 100644 --- a/server/models/system.py +++ b/server/models/system.py @@ -6,8 +6,8 @@ from typing import List # Third-party imports -from sqlalchemy import Column, Integer, String, DateTime -from sqlalchemy.orm import relationship, Mapped +from sqlalchemy import Column, Integer, String, DateTime, Boolean, ForeignKey +from sqlalchemy.orm import relationship, Mapped, mapped_column from models.plant import Base @@ -31,9 +31,11 @@ class System(Base): ) # Available plants of this system # Lighting - # duration = Column(Integer()) # hours - # distance = Column(Integer()) # inches - # light: Mapped["Light"] = relationship(back_populates="plants") + duration = Column(Integer(), nullable=False) # hours + distance = Column(Integer(), nullable=False) # inches + lights: Mapped[List["Light"]] = relationship( + "Light", backref="system", passive_deletes=True + ) # Available plants of this system def __repr__(self) -> str: return f"{self.name}" @@ -47,24 +49,41 @@ def to_json(self): "updated_on": self.updated_on, "humidity": self.humidity, "temperature": self.temperature, - # "duration": self.duration, - # "distance": self.distance + "duration": self.duration, + "distance": self.distance } -# class Light(Base): -# """Light model.""" +class Light(Base): + """Light model.""" + + __tablename__ = "light" -# __tablename__ = "light" + id = Column(Integer(), primary_key=True) + name = Column(String(100), nullable=False) + created_on = Column(DateTime(), default=datetime.now) + updated_on = Column(DateTime(), default=datetime.now) + cost = Column(Integer()) + system_id: Mapped[int] = mapped_column( + ForeignKey("system.id", ondelete="CASCADE") + ) # System this light belongs to -# id = Column(Integer(), primary_key=True) -# name = Column(String(100), nullable=False) -# created_on = Column(DateTime(), default=datetime.now) -# cost = Column(Integer()) + # Death Info + dead_on = Column(DateTime(), default=None, nullable=True) + dead = Column(Boolean, default=False, nullable=False) -# # Death Info -# dead_on = Column(DateTime(), default=None, nullable=True) -# dead = Column(Boolean, default=False, nullable=False) + def __repr__(self) -> str: + return f"{self.name}" -# def __repr__(self) -> str: -# return f"{self.name}" + def to_json(self): + """Convert to json.""" + return { + "id": self.id, + "name": self.name, + "cost": self.cost, + "created_on": self.created_on, + "updated_on": self.updated_on, + "system_id": self.system_id, + "dead": self.dead, + "dead_on": self.dead_on + }