Skip to content

Commit

Permalink
Merge pull request #29 from mseng10/light_model_support
Browse files Browse the repository at this point in the history
ENH: Light creation endpoint
  • Loading branch information
mseng10 authored Jun 9, 2024
2 parents 4aba8dc + 25ddcd5 commit d76839a
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 22 deletions.
140 changes: 140 additions & 0 deletions client/react/src/forms/NewLightForm.js
Original file line number Diff line number Diff line change
@@ -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 (
<Modal
open={isOpen}
onClose={onRequestClose}
aria-labelledby="new-bobby-form"
disableAutoFocus={true}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'inherit',
border: 'none',
}}
>
<Box sx={{ width: 560, bgcolor: 'background.paper', borderRadius: 2 }}>
<form onSubmit={handleSubmit}>
<div className='left'>
<TungstenSharpIcon sx={{ color: '#ffeb3b'}} className={submitted ? 'home_icon_form_submit' : 'home_icon_form'}/>
<ButtonGroup>
<IconButton className="left_button" type="submit" color="primary">
<CheckSharpIcon className="left_button"/>
</IconButton>
<IconButton className="left_button" color="error" onClick={handleCancel}>
<CloseSharpIcon className="left_button"/>
</IconButton>
</ButtonGroup>
</div>
<div className='right'>
<TextField
margin="normal"
fullWidth
required
label="Name"
value={name}
variant="standard"
onChange={(event) => setName(event.target.value)}
/>
<Autocomplete
freeSolo
disableClearable
value={system ? system.name : ''}
options={allSystems.map((option) => option.name)}
onChange={(event) => setSystem(allSystems[event.target.value])}
renderInput={(params) => (
<TextField
variant="standard"
{...params}
label="System"
InputProps={{
...params.InputProps,
type: 'search',
}}
/>
)}
/>
<TextField
margin="normal"
fullWidth
required
type="number"
label="Cost"
value={cost}
onChange={(event) => setCost(event.target.value)}
variant="standard"
/>
</div>
</form>
</Box>
</Modal>
);
};

export default NewLightForm;
30 changes: 28 additions & 2 deletions client/react/src/forms/NewSystemForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand All @@ -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())
Expand All @@ -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();
Expand All @@ -60,6 +64,8 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => {
setName('');
setTempurature(0);
setHumidity(0);
setDistance(0);
setDuration(0);
setSubmitted(false);
};

Expand Down Expand Up @@ -120,6 +126,26 @@ const NewSystemForm = ({ isOpen, onRequestClose }) => {
onChange={(event) => setTempurature(event.target.value)}
variant="standard"
/>
<TextField
margin="normal"
fullWidth
required
type="number"
label="Duration (hours)"
value={duration}
onChange={(event) => setDuration(event.target.value)}
variant="standard"
/>
<TextField
margin="normal"
fullWidth
required
type="number"
label="Distance (inches)"
value={distance}
onChange={(event) => setDistance(event.target.value)}
variant="standard"
/>
</div>
</form>
</Box>
Expand Down
11 changes: 11 additions & 0 deletions client/react/src/pages/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -76,6 +80,9 @@ const Home = () => {
<IconButton size="small" color="secondary" onClick={() => setIsNewGenusFormOpen(true)}>
<FingerprintSharpIcon className={`small_home_button `} />
</IconButton>
<IconButton size="small" sx={{ color: '#ffeb3b'}} onClick={() => setIsNewLightFormOpen(true)}>
<TungstenSharpIcon className="small_home_button"/>
</IconButton>
<IconButton size="small" color="error" onClick={() => setIsCreateButtonsOpen(false)}>
<CloseSharpIcon className="small_home_button"/>
</IconButton>
Expand Down Expand Up @@ -108,6 +115,10 @@ const Home = () => {
isOpen={isNewGenusFormOpen}
onRequestClose={() => setIsNewGenusFormOpen(false)}
/>
<NewLightForm
isOpen={isNewLightFormOpen}
onRequestClose={() => setIsNewLightFormOpen(false)}
/>
</div>
</>
);
Expand Down
43 changes: 42 additions & 1 deletion server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -32,6 +32,7 @@
port=db_config["port"],
)
engine = create_engine(url)

# Base.metadata.drop_all(engine)
# Base.metadata.create_all(engine)

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
57 changes: 38 additions & 19 deletions server/models/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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}"
Expand All @@ -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
}

0 comments on commit d76839a

Please sign in to comment.