diff --git a/client/src/App.js b/client/src/App.js index 21858f8..30359ee 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; import { Home } from "./pages/Home"; import { About } from "./pages/About"; @@ -8,57 +8,96 @@ import { NotFound } from "./pages/NotFound"; import { Navbar } from "./components/Navbar"; import { CreateEvent } from "./pages/CreateEvent"; import { Event } from "./pages/Event"; -import { EVENT_CONTEXT } from "./constants"; +import { API_CLIENT } from "./constants"; import { LoginPage } from "./pages/Login"; -export const App = (props) => { - const [context, setContext] = useState({ - events: props.events, - updateEvents: function (events = []) { - if (!Array.isArray(events)) throw new TypeError("Events must come in array"); - setContext({ - events: events, - updateEvents: this.updateEvents, - }); - }, - }); +export const App = () => { + const [routes, setRoutes] = useState( + API_CLIENT.events.map((e) => { + return ( + + + + ); + }) + ); + + useEffect(() => { + API_CLIENT.on("EVENT_RELOAD", (list) => { + setRoutes( + list.map((e) => { + return ( + + + + ); + }) + ); + }); + API_CLIENT.on("EVENT_CREATE", (list) => { + setRoutes( + list.map((e) => { + return ( + + + + ); + }) + ); + }); + }, []); return ( - - - - - - - - - - - - - {Array.isArray(props.events) && - props.events.map((e) => { - return ( - - - - ); - })} - - - - + + + + + + + + + + + + {routes} + + + ); }; diff --git a/client/src/constants.js b/client/src/constants.js index b0097b8..f241070 100644 --- a/client/src/constants.js +++ b/client/src/constants.js @@ -1,10 +1,8 @@ -import { createContext } from "react"; import { APIClient } from "./utils/APIClient"; require("dotenv").config(); export const APP_NAME = "eco-meet"; export const BACKEND_URL = "http://localhost:5000"; -export const EVENT_CONTEXT = createContext(); export const API_CLIENT = new APIClient(process.env.DEPLOY ? "" : BACKEND_URL); export const EVENT_TYPES = { colors: { diff --git a/client/src/index.js b/client/src/index.js index 74823c3..118170c 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -6,11 +6,11 @@ import "bootstrap/dist/css/bootstrap.min.css"; import { API_CLIENT } from "./constants"; (async () => { - const dbEvents = await API_CLIENT.getEvents(); + await API_CLIENT.fetchEvents(); ReactDOM.render( - + , document.getElementById("root") ); diff --git a/client/src/pages/CreateEvent/index.js b/client/src/pages/CreateEvent/index.js index 4ff7174..84266a0 100644 --- a/client/src/pages/CreateEvent/index.js +++ b/client/src/pages/CreateEvent/index.js @@ -1,10 +1,10 @@ import { useTitle } from "../../utils/useTitle"; import { useFormik } from "formik"; -import { useContext, useState } from "react"; +import { useState } from "react"; import { Stack } from "react-bootstrap"; import { BIcon } from "../../components/BIcon"; import { useHistory } from "react-router"; -import { API_CLIENT, EVENT_CONTEXT } from "../../constants"; +import { API_CLIENT } from "../../constants"; import { container } from "../../global.module.scss"; import styles from "./index.module.scss"; import { spawnPopup } from "../../utils/popups/spawnPopup"; @@ -14,7 +14,6 @@ import { MapPopup } from "./MapPopup"; export const CreateEvent = () => { useTitle("Tworzenie wydarzenia"); - const context = useContext(EVENT_CONTEXT); const history = useHistory(); const [locationText, setLocationText] = useState("Brak lokalizacji"); const formik = useFormik({ @@ -46,7 +45,7 @@ export const CreateEvent = () => { const rqObj = { name: data.name, type: parseInt(data.type), - description: data.description, + description: data.description ?? null, lon: mapPos?.[0] ?? null, lat: mapPos?.[1] ?? null, address: locationText, @@ -54,10 +53,7 @@ export const CreateEvent = () => { }; API_CLIENT.createEvent(rqObj) .then(() => { - API_CLIENT.getEvents().then((r) => { - context.updateEvents(r); - history.push("/"); - }); + history.push("/"); }) .catch(async (e) => { await spawnError(e.toString()); diff --git a/client/src/pages/Home/index.js b/client/src/pages/Home/index.js index bc5a759..caafeed 100644 --- a/client/src/pages/Home/index.js +++ b/client/src/pages/Home/index.js @@ -1,32 +1,56 @@ import { useTitle } from "../../utils/useTitle"; -import { useState, useRef, useEffect, useContext } from "react"; +import { useState, useRef, useEffect } from "react"; import { Stack } from "react-bootstrap"; import { EventPreview } from "../../components/EventPreview"; import { container } from "../../global.module.scss"; import styles from "./index.module.scss"; import { BIcon } from "../../components/BIcon"; // import HoldingPlant from "../../components/Pop-up/AnimatedHand"; -import { EVENT_CONTEXT } from "../../constants"; +import { API_CLIENT } from "../../constants"; // import { calculateDistance } from "../../utils/map/calculateDistance"; import { useHistory } from "react-router"; import Button from "@restart/ui/esm/Button"; export const Home = () => { useTitle(); - const context = useContext(EVENT_CONTEXT); const [list, updateList] = useState( - context.events.map((e, i) => { + API_CLIENT.events.map((e, i) => { return ; }) ); const sortDropdown = useRef(null); useEffect(() => { + API_CLIENT.on("EVENT_RELOAD", (list) => { + updateList( + list.map((e, i) => { + return ( + + ); + }) + ); + }); + API_CLIENT.on("EVENT_CREATE", (list) => { + updateList( + list.map((e, i) => { + return ( + + ); + }) + ); + }); + sortDropdown.current.addEventListener("input", (e) => { const value = e.target.value; const type = value.split(":")[0]; const direction = value.split(":")[1]; - const newOrder = context.events.sort((a, b) => { + const newOrder = API_CLIENT.events.sort((a, b) => { switch (type) { case "event-date": return direction === "ascending" ? a.time - b.time : b.time - a.time; @@ -51,7 +75,7 @@ export const Home = () => { }) ); }); - }, [context.events]); + }, []); const history = useHistory(); diff --git a/client/src/utils/APIClient.js b/client/src/utils/APIClient.js index a34bbdb..b32a7e9 100644 --- a/client/src/utils/APIClient.js +++ b/client/src/utils/APIClient.js @@ -1,22 +1,33 @@ import axios from "axios"; +import { EventEmitter } from "events"; -export class APIClient { +export class APIClient extends EventEmitter { #dbUrl = ""; + #events = []; constructor(dbUrl) { + super(); if (typeof dbUrl !== "string") throw new Error("Database URL is not a string"); this.#dbUrl = dbUrl; } - async getEvents() { + + get events() { + return this.#events; + } + + async fetchEvents() { const rq = await axios.get(`${this.#dbUrl}/api/getEvents`); if (rq.status !== 200) throw new Error(`Request failed with status code ${rq.status}: ${rq.statusText}`); + this.#events = rq.data; + this.emit("EVENT_RELOAD", this.#events, rq.data); return rq.data; } + async getEvent(id) { if (typeof id !== "string") throw new TypeError("Invalid ID type"); - const events = await this.getEvents(); - return events.find((e) => e.id === id) ?? null; + return this.#events.find((e) => e.id === id) ?? null; } + async createEvent(data) { //Check types if (typeof data !== "object") throw new TypeError("Data object is required"); @@ -27,6 +38,8 @@ export class APIClient { //Make POST request const rq = await axios.post(`${this.#dbUrl}/api/createEvent`, data); if (rq.status !== 200) throw new Error(`Request failed with status code ${rq.status}: ${rq.statusText}`); - return rq; + this.#events.push(rq.data); + this.emit("EVENT_CREATE", this.#events, rq.data); + return rq.data; } } diff --git a/index.js b/index.js index 6c27765..50ca4b0 100644 --- a/index.js +++ b/index.js @@ -51,10 +51,10 @@ app.post("/api/createEvent", (req, res) => { lat: req.body.lat, lon: req.body.lon, }; - events.create(data, (err) => { + events.create(data, (err, data) => { if (err) return res.status(400).json({ msg: err }); // saved! - res.status(200).json("ok"); + res.status(200).json(data); }); }); app.use((req, res, next) => {