Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
a35fecb
request form for services
MonikaaMoanes Apr 6, 2024
7140b4b
Merge branch 'dev' of https://github.com/SOEN390-Team16/Butler into F…
MonikaaMoanes Apr 7, 2024
079fc51
Merge branch 'dev' of https://github.com/SOEN390-Team16/Butler into F…
MonikaaMoanes Apr 11, 2024
167a87c
Implemented services dashboard with functionality to fetch and displa…
MonikaaMoanes Apr 13, 2024
f7c88e4
Merge branch 'dev' of https://github.com/SOEN390-Team16/Butler into F…
MonikaaMoanes Apr 13, 2024
273961f
add table to display service requests for CO. add CreateRequestForm f…
yousfino Apr 2, 2024
fa9d411
add the following
yousfino Apr 2, 2024
7c63755
added the folder Facility and 3 core classes
Apr 12, 2024
866781b
endpoints for facility operations
Apr 12, 2024
6c136e7
create request form. condo owner is now able to create a new service …
yousfino Apr 12, 2024
5fe1be0
CO_7 and CO_12 done
yousfino Apr 12, 2024
8b56d89
CMC can now see service requests by condo owners. CMC can view, edit,…
yousfino Apr 12, 2024
ec37b56
checkpoint
yousfino Apr 13, 2024
3306342
CMC_26 done
yousfino Apr 14, 2024
aaa0897
request form for services
MonikaaMoanes Apr 6, 2024
64c564d
Implemented services dashboard with functionality to fetch and displa…
MonikaaMoanes Apr 13, 2024
ad6a34f
checkpoint
yousfino Apr 14, 2024
d1729e2
added the operation routes to server.js
Apr 11, 2024
ba3e219
created operation routes
Apr 11, 2024
6df59bf
implemented all the basic queries and calculating the total cost
Apr 11, 2024
13ce154
implemented all the basic functions and readOperationalCost
Apr 11, 2024
bc4082f
changed the query and readOperationalCosts so that it returns total o…
Apr 12, 2024
22b3912
endpoints for reservation operations
Apr 12, 2024
69288ef
added getReservationsByPropertyId
Apr 12, 2024
9e1b095
lint fix
Apr 12, 2024
377d05a
query fix for checking if reservation exits
Apr 12, 2024
f74d343
added getPropertyByCompanyId
Apr 12, 2024
f68c913
refactor(client): switched account creation to use zustand
walidoow Apr 8, 2024
db4fef3
refactor(client): switched company account creation to use zustand
walidoow Apr 8, 2024
7801a1d
refactor(client): added public user service
walidoow Apr 8, 2024
29ea933
fix(client): load axios interceptors
walidoow Apr 8, 2024
42a6471
refactor(client): toast error message returned from API
walidoow Apr 8, 2024
c94037f
fix(server): get public user by Id endpoint returns a single object
walidoow Apr 8, 2024
a81b840
fix(server): change the generate key controller
walidoow Apr 8, 2024
a301505
fix(client): getAllUser returns a proper list of public users
walidoow Apr 8, 2024
8e7ca60
feature(client): implement public user store
walidoow Apr 8, 2024
7d63496
feature(client): implement public user store for login of public user…
walidoow Apr 8, 2024
d585877
refactor(client): remove unnecessary console.log statements
walidoow Apr 8, 2024
5df29e5
feature(client): add condo management company model
walidoow Apr 8, 2024
3bf9483
feature(client): add condo management company service
walidoow Apr 8, 2024
9ff2d97
feature(client): get company by id endpoint returns a single object
walidoow Apr 9, 2024
ff53f4f
fix(client): Sign In button now redirects to sign in page
walidoow Apr 9, 2024
39037a6
feature(client): implement condo management company store
walidoow Apr 9, 2024
329c5d0
feature(client): implement condo management company store for login o…
walidoow Apr 9, 2024
ec4d443
fix(server): patch method of public user returns the updated user
walidoow Apr 9, 2024
997476f
feat(client): persist Zustand store in localStorage to maintain state…
walidoow Apr 9, 2024
45125a3
fix(client): update public user using the right userid variable
walidoow Apr 9, 2024
5ca28e5
feat(client): update edit user using zustand
walidoow Apr 11, 2024
b80431d
fix(server): adapt unit tests to changes in public user
walidoow Apr 12, 2024
2b550e9
feat(server): add endpoint to upload images
walidoow Apr 12, 2024
a62a73b
feat(client): add image service to project
walidoow Apr 12, 2024
8354441
fix(client): profile picture is saved correctly
walidoow Apr 12, 2024
a87314f
revert(client): brought back userData in localstorage
walidoow Apr 12, 2024
e2e53d0
fix(client): remove new keyword from copy in models
walidoow Apr 12, 2024
949cb9f
fix(client): remove wrongly called toast notification from edit accou…
walidoow Apr 12, 2024
4e835bd
fix(server): update user role by registration key and user id returns…
walidoow Apr 12, 2024
b1e72a6
feat(client): add registration key service
walidoow Apr 12, 2024
059534c
refactor(client): implement account activation with zustand
walidoow Apr 12, 2024
0cbff3a
fix(client): remove ES6 linting issue
walidoow Apr 12, 2024
59a65c1
generate annual report (#243)
DanDuguay Apr 12, 2024
76a9a6e
added read and set costs by operation id (#247)
Apr 12, 2024
94c0b08
added the route, query, and the function to calculate total operation…
Apr 12, 2024
db5b1fd
changed the endpoint getEverythingByC to also return the property nam…
DanDuguay Apr 13, 2024
5485a0c
CO_7, CO_11, CO_12, CMC_26 done:
yousfino Apr 14, 2024
c29e9b1
pull from dev
yousfino Apr 14, 2024
d3c8bc0
pull from dev
yousfino Apr 14, 2024
9091347
pull from bug/cmc_26
MonikaaMoanes Apr 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import EditAccount from "./Components/EditAccount/EditAccount";
import EditAccountCMC from "./Components/EditAccount/EditAccountCMC";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import "./config/axios.config.js"
import "./config/axios.config.js";
import DashBoardHomeCO from "./Components/Dashboard/DashBoardHomeCO";
import ServicesDashBoard from "./Components/Dashboard/ServicesDashBoard";
import DashBoardHomeCR from "./Components/Dashboard/DashBoardHomeCR";
import PropertyPage from "./Components/Dashboard/Property/PropertyPage";
import { ChakraProvider } from "@chakra-ui/react";

import ServiceRequestCMC from "./Components/ServiceRequestPageCMC/ServiceRequestCMC";
import ServiceRequestCMC2 from "./Components/ServiceRequestPageCMC/ServiceRequestCMC2";
function App() {
return (
<>
Expand All @@ -33,10 +35,17 @@ function App() {
/>
<Route path="/DashBoardHomeCO" element={<DashBoardHomeCO />} />
<Route path="/DashBoardHomeCR" element={<DashBoardHomeCR />} />
<Route path="/ServicesDashBoard" element={<ServicesDashBoard />} />

<Route
path="/DashBoardHomeCMC/property/:id"
element={<PropertyPage />}
/>
<Route path="/ServiceRequestCMC" element={<ServiceRequestCMC />} />
<Route
path="/ServiceRequestCMC2"
element={<ServiceRequestCMC2 />}
/>
</Routes>
</BrowserRouter>
<ToastContainer />
Expand All @@ -46,3 +55,4 @@ function App() {
}

export default App;

23 changes: 23 additions & 0 deletions client/src/Components/Buttons/SubmitRequestButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Link } from "react-router-dom";
import PropTypes from "prop-types";
import { IoMdAddCircleOutline } from "react-icons/io";

export default function SubmitRequestButton(props) {
return (
<Link
className="flex flex-row items-center gap-2.5 text-white font-semibold bg-[#34A853] hover:bg-green-600
px-8 py-4 rounded-md shadow-md"
onClick={props.onClick}
to={props.to}
>
<IoMdAddCircleOutline className="font-extrabold" fontWeight={1} size={24} />
{props.children}
</Link>
);
}

SubmitRequestButton.propTypes = {
children: PropTypes.node,
to: PropTypes.string.isRequired,
onClick: PropTypes.func,
};
93 changes: 93 additions & 0 deletions client/src/Components/Dashboard/CreateRequestForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import Input from "../Forms/Input.jsx";
import Label from "../Forms/Label.jsx";
import { useFormik } from "formik";
import { useModal } from "../Modals/Modal.jsx";
import { object, string } from "yup";
import AddButton from "../Buttons/AddButton.jsx";
import { toast } from "react-toastify";
import axios from "axios";
import PropTypes from "prop-types";

export default function CreateRequestForm({ requestList }) {
const { toggle } = useModal();
const token = localStorage.getItem("token");
const userData = JSON.parse(localStorage.getItem("userData"));
const userDataArray = userData ? Object.entries(userData) : [];
const userID = userDataArray.length > 1 ? userDataArray[0][1] : "";

console.log("requests: ", requestList);
let requestSchema = object({
description: string().required("A description is required"),
type: string().required("A request type is required"),
});

const formik = useFormik({
initialValues: {
user_id: userID,
description: "",
type: "",
},
validationSchema: requestSchema,
onSubmit: (values) => handleSubmit(values),
});

const errorMessage = (fieldName) => {
if (formik.touched[fieldName] && formik.errors[fieldName]) {
return (
<span className="text-red-400 text-sm">{formik.errors[fieldName]}</span>
);
}
return null;
};

const handleSubmit = async (values) => {
console.log(values);
await axios
.post("http://hortzcloud.com:3000/api/v1/req", values, {
headers: {
authorization: `Bearer ${token}`,
},
})
.then((res) => {
toast.success("Request created successfully!");
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
toggle();
// alert(JSON.stringify(values, null, 2));
};

return (
<>
<form onSubmit={formik.handleSubmit} className="flex flex-col gap-2">
<div className="flex flex-col gap-2 w-[360px] font-inter h-fit">
<Label htmlFor="type">Request Type</Label>
{errorMessage("type")}
<Input onChange={formik.handleChange} id="type" name="type" />
</div>
<div className="flex flex-col gap-2 w-[360px] font-inter h-fit">
<Label htmlFor="description">Description</Label>
{errorMessage("description")}
<Input
onChange={formik.handleChange}
id="description"
name="description"
/>
</div>
</form>

<AddButton onClick={formik.submitForm}>Submit Request</AddButton>
</>
);
}

CreateRequestForm.propTypes = {
requestList: PropTypes.arrayOf(
PropTypes.shape({
description: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
})
),
};
30 changes: 27 additions & 3 deletions client/src/Components/Dashboard/DashBoardHomeCO.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,28 @@ const DashBoardHomeCO = () => {
const userID = userDataArray.length > 1 ? userDataArray[0][1] : "";
const token = localStorage.getItem("token");

const [request, setRequest] = useState([]);
const getRequestByUserID = () => {
axios
.get(`http://hortzcloud.com:3000/api/v1/req?userid=${userID}`, {
headers: {
authorization: `Bearer ${token}`,
},
})
.then((requestResponse) => {
setRequest(requestResponse.data);
})
.catch((error) => {
console.error("Error fetching requests:", error);
});
};

useEffect(() => {
if (request.length > 0) {
console.log("requests:", request);
}
}, [request]);

// Fetch parking spots data
const fetchParkingSpots = () => {
axios
Expand All @@ -46,7 +68,6 @@ const DashBoardHomeCO = () => {
})
.then((parkingSpotsResponse) => {
setParkingSpots(parkingSpotsResponse.data);
// console.log(parkingSpotsResponse.data[0]);
console.log("parking:");
console.log(parkingSpots);
})
Expand All @@ -65,8 +86,6 @@ const DashBoardHomeCO = () => {
})
.then((lockersResponse) => {
setLockers(lockersResponse.data);
// console.log("locker id");
// console.log(lockers[0].lockerid);
})
.catch((error) => {
console.error("Error fetching lockers:", error);
Expand Down Expand Up @@ -107,12 +126,17 @@ const DashBoardHomeCO = () => {
fetchLockers();
fetchCondos();
fetchCondo();
getRequestByUserID();
}, [token, userID]);

const addPropertyToState = (newProperty) => {
setProperties((prevProperties) => [...prevProperties, newProperty]);
};

const addRequestToState = (newRequest) => {
setRequest((prevRequest) => [...prevRequest, newRequest]);
};

const toggleDrawer = () => {
setDrawerOpen(!isDrawerOpen);
};
Expand Down
137 changes: 137 additions & 0 deletions client/src/Components/Dashboard/ServicesDashBoard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { useState, useEffect } from "react";
import { RxHamburgerMenu } from "react-icons/rx";
import "./DashBoardHome.css";
import Table from "../Tables/Table.jsx";
import TableHeader from "../Tables/TableHeader.jsx";
import TableRow from "../Tables/TableRow.jsx";
import TableCard from "../Cards/Tables/TableCard.jsx";
import TableCardHeader from "../Cards/Tables/TableCardHeader.jsx";
import axios from "axios";
import ModalToggler from "../Modals/ModalToggler.jsx";
import AddButton from "../Buttons/AddButton.jsx";
import ModalContent from "../Modals/ModalContent.jsx";
import Modal from "../Modals/Modal.jsx";
import ServicesDashBoardHeader from "../Tables/ServicesDashBoardHeader.jsx";
import CompanyContactDisplayForm from "./CompanyContactDisplayForm.jsx";
import SideNav from "../SideNav/SideNav.jsx";
import { IconButton } from "@chakra-ui/react";
import CreateRequestForm from "./CreateRequestForm.jsx";

const ServicesDashBoard = () => {
const [isDrawerOpen, setDrawerOpen] = useState(false);
const userData = JSON.parse(localStorage.getItem("userData"));
const userDataArray = userData ? Object.entries(userData) : [];
const userID = userDataArray.length > 1 ? userDataArray[0][1] : "";
const token = localStorage.getItem("token");

const [request, setRequest] = useState([]);

const getRequestByUserID = () => {
// const userIdToFetch = 19;
axios
.get(`http://hortzcloud.com:3000/api/v1/req?userid=${userID}`, {
headers: {
authorization: `Bearer ${token}`,
},
})
.then((requestResponse) => {
setRequest(requestResponse.data);

// console.log("requestResponse.data:");
// console.log(requestResponse);
// console.log("request:");
// console.log(request);
})
.catch((error) => {
console.error("Error fetching requests:", error);
});
};

useEffect(() => {
getRequestByUserID();
}, [token, userID]);

const addRequestToState = (newRequest) => {
setRequest((prevRequest) => [...prevRequest, newRequest]);
};

const toggleDrawer = () => {
setDrawerOpen(!isDrawerOpen);
};

return (
<div className="dashboard__home">
<div className="sidedrawer__open"></div>
<IconButton
onClick={toggleDrawer}
icon={<RxHamburgerMenu />}
className="fixed top-10 shadow z-50"
backgroundColor={"#FFFFFF"}
rounded={"0 10px 10px 0"}
_hover={{ backgroundColor: "#CCCCCC" }}
/>
<SideNav isOpen={isDrawerOpen} toggleDrawer={toggleDrawer} />
<ServicesDashBoardHeader />
<div className="container flex flex-col items-center px-24">
<div className="flex flex-col justify-center items-center w-full">
<Modal>
<ModalToggler>
<h2 style={{ marginBottom: "20px", fontSize: "20px" }}>
Having an issue or want to ask question? Submit a Request <br />
<span style={{ marginLeft: "60px" }}>and</span> one of our employees will get back to you
</h2>
</ModalToggler>
<ModalContent
title="Company Contact Info"
description=""
onExit={() => console.log("exit")}
>
<CompanyContactDisplayForm />
</ModalContent>
</Modal>
<TableCard className={"gap-4"}>
<TableCardHeader title={"Your Service Requests"}>
<div className="flex items-center gap-4">
<Modal>
<ModalToggler>
<AddButton>Submit a Request</AddButton>
</ModalToggler>
<ModalContent
title="Submit a Service Request"
description="Fill the form to submit a service request"
onExit={() => console.log("exit")}
>
<CreateRequestForm onAddProperty={addRequestToState} />
</ModalContent>
</Modal>
</div>
</TableCardHeader>
<div>
{request.length > 0 && (
<Table>
<TableHeader>
<th>Request ID</th>
<th>Request Type</th>
<th>Request Description</th>
<th>Request Status</th>
</TableHeader>
{request.map((req, index) => (
<TableRow key={index}>
<td>{req.request_id}</td>
<td>{req.type}</td>
<td>{req.description}</td>
<td>{req.status}</td>
</TableRow>
))}
</Table>
)}
</div>
</TableCard>
</div>
</div>
</div>
);
};

export default ServicesDashBoard;

15 changes: 15 additions & 0 deletions client/src/Components/Dropdown/Dropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";

const Dropdown = ({ options, value, onChange }) => {
return (
<select value={value} onChange={onChange} className="dropdown">
{options.map((option, index) => (
<option key={index} value={option}>
{option}
</option>
))}
</select>
);
};

export default Dropdown;
Loading