diff --git a/backend/automations.json b/backend/automations.json index b120baa..a2136fe 100644 --- a/backend/automations.json +++ b/backend/automations.json @@ -18,17 +18,9 @@ }, { "id": 3, - "name": "Test3", - "device_id": 1, - "triggers": "08:23", - "enabled": true, - "status": "off" - }, - { - "id": 4, "name": "Test4", - "device_id": 8, - "triggers": "23:00", + "device_id": 1, + "triggers": "21:45", "enabled": true, "status": "off" } diff --git a/backend/automations.py b/backend/automations.py index b692110..96b4945 100644 --- a/backend/automations.py +++ b/backend/automations.py @@ -89,10 +89,11 @@ async def automation_scheduler(): for automation in automations: automation_device_id = int(automation["device_id"]) trigger_time = automation["triggers"] + device_status = automation["status"] if automation["enabled"] and trigger_time == current_time: print(f"Triggering automation: {automation['name']} at {current_time}") - changeDeviceStatus(automation_device_id) + changeDeviceStatus(automation_device_id, device_status) now = datetime.now() next_minute = (now + timedelta(minutes=1)).replace(second=0, microsecond=0) diff --git a/backend/fastAPI.py b/backend/fastAPI.py index 6c4a2ae..9d194a5 100644 --- a/backend/fastAPI.py +++ b/backend/fastAPI.py @@ -125,6 +125,11 @@ def add_new_user(user: UserRequest): """Adds a new user with the given name, password, and optional allocated devices.""" return u.add_user(user.user_name, user.user_password, user.allocated_devices or []) +@app.put("/rename_user/{new_name}") +def rename_user(new_name: str): + """API endpoint to rename the selected user.""" + return u.rename_selected_user(new_name) + @app.delete("/delete_user/{user_name}/{user_password}") def delete_user(user_name: str, user_password: str): """Deletes a user with the given name and password.""" diff --git a/backend/users.py b/backend/users.py index 0e3c95f..cd1349e 100644 --- a/backend/users.py +++ b/backend/users.py @@ -71,6 +71,36 @@ def add_user(user_name: str, user_password: str, allocated_device_ids: list = No return {"success": message, "user": new_user} +def rename_selected_user(new_name: str): + """Rename the currently selected user and update both selected_user.json and users_db.json.""" + selected_user_data = get_selected_user() + current_name = selected_user_data.get("selected_user") + + if not current_name: + return {"error": "No user selected."} + + users = load_users() + + if any(user["user_name"] == new_name for user in users): + return {"error": f"Username '{new_name}' is already taken."} + + user = next((u for u in users if u["user_name"] == current_name), None) + + if not user: + return {"error": f"User {current_name} not found in database."} + + user["user_name"] = new_name + save_users(users) + + with open(SELECTED_USER_FILE, "w") as f: + json.dump({"selected_user": new_name, "user_role": user["user_role"]}, f) + + message = f"User {current_name} renamed to {new_name}." + updates.append(message) + + return {"success": message, "selected_user": new_name, "user_role": user["user_role"]} + + def delete_user(user_name: str, user_password: str): """Deletes a user from the system if the given password matches. If deleting the super user, assign the position to the next user. diff --git a/database/users_db.json b/database/users_db.json index ad68750..d240ca8 100644 --- a/database/users_db.json +++ b/database/users_db.json @@ -2,7 +2,7 @@ "users": [ { "user_id": 1, - "user_name": "Aditya", + "user_name": "Aditya S", "user_password": "7777", "allocated_devices": [ "1", @@ -57,25 +57,12 @@ 6, 5 ] - }, - { - "id": 5, - "name": "Idk what this is", - "status": "on", - "devices": [ - 1, - 2, - 3, - 4, - 7, - 8 - ] } ] }, { "user_id": 2, - "user_name": "David F", + "user_name": "David Farid", "user_password": "1415", "allocated_devices": [ "1", @@ -89,11 +76,20 @@ { "id": 2, "name": "Bedroom Devices", - "status": "off", + "status": "on", "devices": [ 2, 7 ] + }, + { + "id": 3, + "name": "Kitchen Devices", + "status": "on", + "devices": [ + 7, + 8 + ] } ] }, diff --git a/frontend/src/app/ui/dashboard/accountMenu.jsx b/frontend/src/app/ui/dashboard/accountMenu.jsx index af4b04c..b2b530c 100644 --- a/frontend/src/app/ui/dashboard/accountMenu.jsx +++ b/frontend/src/app/ui/dashboard/accountMenu.jsx @@ -15,6 +15,7 @@ import DevicesIcon from "@mui/icons-material/Devices"; import AddUserDialog from "../newUserDialogue"; import AllocateDevicesDialog from "../allocateDevices"; +import UserSettingsDialog from "../userSettingsDialogue"; import { signOut } from "firebase/auth"; import { auth } from "@/app/firebase/config"; @@ -28,13 +29,15 @@ export default function AccountMenu() { const [isSuperUser, setIsSuperUser] = React.useState(false); const [openUserDialog, setOpenUserDialog] = React.useState(false); const [openAllocateDialog, setOpenAllocateDialog] = React.useState(false); + const [openUserSettingsDialog, setOpenUserSettingsDialog] = + React.useState(false); const open = Boolean(anchorEl); - + const handleClick = (event) => { setAnchorEl(event.currentTarget); }; - + const handleClose = () => { setAnchorEl(null); }; @@ -84,7 +87,11 @@ export default function AccountMenu() { aria-haspopup="true" aria-expanded={open ? "true" : undefined} > - {selectedUser.charAt(0)} + + {selectedUser.charAt(0)} + @@ -133,11 +140,17 @@ export default function AccountMenu() { color: "primary.main", }} > - {selectedUser.charAt(0)} {selectedUser} + + {selectedUser.charAt(0)} + {" "} + {selectedUser} {isSuperUser && ( - setOpenAllocateDialog(true)} sx={{ fontFamily: "JetBrains Mono" }}> + setOpenAllocateDialog(true)} + sx={{ fontFamily: "JetBrains Mono" }} + > @@ -145,14 +158,20 @@ export default function AccountMenu() { )} {isSuperUser && ( - setOpenUserDialog(true)} sx={{ fontFamily: "JetBrains Mono" }}> + setOpenUserDialog(true)} + sx={{ fontFamily: "JetBrains Mono" }} + > Add another account )} - + setOpenUserSettingsDialog(true)} + sx={{ fontFamily: "JetBrains Mono" }} + > @@ -171,7 +190,14 @@ export default function AccountMenu() { onClose={() => setOpenUserDialog(false)} // onSave={handleSaveUser} /> - setOpenAllocateDialog(false)} /> + setOpenAllocateDialog(false)} + /> + setOpenUserSettingsDialog(false)} + /> ); } diff --git a/frontend/src/app/ui/userSettingsDialogue.jsx b/frontend/src/app/ui/userSettingsDialogue.jsx new file mode 100644 index 0000000..ca945c0 --- /dev/null +++ b/frontend/src/app/ui/userSettingsDialogue.jsx @@ -0,0 +1,187 @@ +import React, { useEffect, useState } from "react"; +import { + Dialog, + DialogTitle, + DialogContent, + Avatar, + Typography, + Chip, + Stack, + CircularProgress, + IconButton, + TextField, + Button, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import EditIcon from "@mui/icons-material/Edit"; + +const UserSettingsDialog = ({ open, onClose }) => { + const [userData, setUserData] = useState(null); + const [devices, setDevices] = useState([]); + const [loading, setLoading] = useState(true); + const [isEditing, setIsEditing] = useState(false); + const [editedName, setEditedName] = useState(""); + + useEffect(() => { + if (open) { + fetchUserData(); + fetchDevices(); + } + }, [open]); + + const fetchUserData = async () => { + try { + const response = await fetch("http://localhost:8000/selected_user"); + const data = await response.json(); + setUserData(data); + } catch (error) { + console.error("Error fetching user data:", error); + } + }; + + const fetchDevices = async () => { + try { + const response = await fetch("http://localhost:8000/device_info"); + const data = await response.json(); + setDevices(data.smart_home_devices || []); + } catch (error) { + console.error("Error fetching devices:", error); + } finally { + setLoading(false); + } + }; + + const handleSave = async () => { + if (!editedName.trim()) return; + + try { + const response = await fetch( + `http://localhost:8000/rename_user/${editedName}`, + { + method: "PUT", + } + ); + + const result = await response.json(); + + if (result.success) { + setUserData((prev) => ({ ...prev, selected_user: editedName })); + setIsEditing(false); + } else { + console.error("Error:", result.error); + } + } catch (error) { + console.error("Error updating username:", error); + } + }; + + return ( + + + User Settings + + setIsEditing(true)}> + + + + + + + + + {loading ? ( + + ) : ( + <> + + {userData?.selected_user?.charAt(0)} + + {/* Editable User Name */} + {isEditing ? ( + + setEditedName(e.target.value)} + variant="outlined" + size="small" + sx={{ fontFamily: "Jetbrains Mono", width: "80%" }} + /> + + + ) : ( + + {userData?.selected_user} + + )} + + Role:{" "} + {userData?.user_role === "sub_user" + ? "Sub User" + : userData?.user_role === "super_user" + ? "Super User" + : "Unknown Role"} + + + + Allocated Devices: + + + {devices.map((device) => ( + + ))} + + + )} + + + ); +}; + +export default UserSettingsDialog;