new event state management

MAJOR!!!
This commit is contained in:
mmacierzanka committed 2021-10-05 21:35:42 +02:00
1 parent 44645884c2
commit 81e0f81157
7 files changed
+125 -55

No files matched your search

+70 -31
View File
@@ -1,4 +1,4 @@
import { useState } from "react"; import { useEffect, useState } from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { Home } from "./pages/Home"; import { Home } from "./pages/Home";
import { About } from "./pages/About"; import { About } from "./pages/About";
@@ -8,36 +8,12 @@ import { NotFound } from "./pages/NotFound";
import { Navbar } from "./components/Navbar"; import { Navbar } from "./components/Navbar";
import { CreateEvent } from "./pages/CreateEvent"; import { CreateEvent } from "./pages/CreateEvent";
import { Event } from "./pages/Event"; import { Event } from "./pages/Event";
import { EVENT_CONTEXT } from "./constants"; import { API_CLIENT } from "./constants";
import { LoginPage } from "./pages/Login"; import { LoginPage } from "./pages/Login";
export const App = (props) => { export const App = () => {
const [context, setContext] = useState({ const [routes, setRoutes] = useState(
events: props.events, API_CLIENT.events.map((e) => {
updateEvents: function (events = []) {
if (!Array.isArray(events)) throw new TypeError("Events must come in array");
setContext({
events: events,
updateEvents: this.updateEvents,
});
},
});
return (
<EVENT_CONTEXT.Provider value={context}>
<Router>
<Navbar />
<Switch>
<Route exact path="/about" component={About} />
<Route exact path="/credits" component={Credits} />
<Route exact path="/users" component={Users} />
<Route exact path="/">
<Home />
</Route>
<Route exact path="/create" component={CreateEvent} />
<Route exact path="/login" component={LoginPage} />
{Array.isArray(props.events) &&
props.events.map((e) => {
return ( return (
<Route key={e._id} exact path={`/event/${e._id}`}> <Route key={e._id} exact path={`/event/${e._id}`}>
<Event <Event
@@ -55,10 +31,73 @@ export const App = (props) => {
></Event> ></Event>
</Route> </Route>
); );
})} })
);
useEffect(() => {
API_CLIENT.on("EVENT_RELOAD", (list) => {
setRoutes(
list.map((e) => {
return (
<Route key={e._id} exact path={`/event/${e._id}`}>
<Event
data={{
name: e.name,
type: e.type,
description: e.description,
address: e.address,
time: e.time,
lat: e.lat,
lon: e.lon,
id: e._id,
createdTime: e.created.time,
}}
></Event>
</Route>
);
})
);
});
API_CLIENT.on("EVENT_CREATE", (list) => {
setRoutes(
list.map((e) => {
return (
<Route key={e._id} exact path={`/event/${e._id}`}>
<Event
data={{
name: e.name,
type: e.type,
description: e.description,
address: e.address,
time: e.time,
lat: e.lat,
lon: e.lon,
id: e._id,
createdTime: e.created.time,
}}
></Event>
</Route>
);
})
);
});
}, []);
return (
<Router>
<Navbar />
<Switch>
<Route exact path="/about" component={About} />
<Route exact path="/credits" component={Credits} />
<Route exact path="/users" component={Users} />
<Route exact path="/">
<Home />
</Route>
<Route exact path="/create" component={CreateEvent} />
<Route exact path="/login" component={LoginPage} />
{routes}
<Route component={NotFound} /> <Route component={NotFound} />
</Switch> </Switch>
</Router> </Router>
</EVENT_CONTEXT.Provider>
); );
}; };
-2
View File
@@ -1,10 +1,8 @@
import { createContext } from "react";
import { APIClient } from "./utils/APIClient"; import { APIClient } from "./utils/APIClient";
require("dotenv").config(); require("dotenv").config();
export const APP_NAME = "eco-meet"; export const APP_NAME = "eco-meet";
export const BACKEND_URL = "http://localhost:5000"; 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 API_CLIENT = new APIClient(process.env.DEPLOY ? "" : BACKEND_URL);
export const EVENT_TYPES = { export const EVENT_TYPES = {
colors: { colors: {
+2 -2
View File
@@ -6,11 +6,11 @@ import "bootstrap/dist/css/bootstrap.min.css";
import { API_CLIENT } from "./constants"; import { API_CLIENT } from "./constants";
(async () => { (async () => {
const dbEvents = await API_CLIENT.getEvents(); await API_CLIENT.fetchEvents();
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<App events={dbEvents} /> <App />
</React.StrictMode>, </React.StrictMode>,
document.getElementById("root") document.getElementById("root")
); );
+3 -7
View File
@@ -1,10 +1,10 @@
import { useTitle } from "../../utils/useTitle"; import { useTitle } from "../../utils/useTitle";
import { useFormik } from "formik"; import { useFormik } from "formik";
import { useContext, useState } from "react"; import { useState } from "react";
import { Stack } from "react-bootstrap"; import { Stack } from "react-bootstrap";
import { BIcon } from "../../components/BIcon"; import { BIcon } from "../../components/BIcon";
import { useHistory } from "react-router"; import { useHistory } from "react-router";
import { API_CLIENT, EVENT_CONTEXT } from "../../constants"; import { API_CLIENT } from "../../constants";
import { container } from "../../global.module.scss"; import { container } from "../../global.module.scss";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import { spawnPopup } from "../../utils/popups/spawnPopup"; import { spawnPopup } from "../../utils/popups/spawnPopup";
@@ -14,7 +14,6 @@ import { MapPopup } from "./MapPopup";
export const CreateEvent = () => { export const CreateEvent = () => {
useTitle("Tworzenie wydarzenia"); useTitle("Tworzenie wydarzenia");
const context = useContext(EVENT_CONTEXT);
const history = useHistory(); const history = useHistory();
const [locationText, setLocationText] = useState("Brak lokalizacji"); const [locationText, setLocationText] = useState("Brak lokalizacji");
const formik = useFormik({ const formik = useFormik({
@@ -46,7 +45,7 @@ export const CreateEvent = () => {
const rqObj = { const rqObj = {
name: data.name, name: data.name,
type: parseInt(data.type), type: parseInt(data.type),
description: data.description, description: data.description ?? null,
lon: mapPos?.[0] ?? null, lon: mapPos?.[0] ?? null,
lat: mapPos?.[1] ?? null, lat: mapPos?.[1] ?? null,
address: locationText, address: locationText,
@@ -54,10 +53,7 @@ export const CreateEvent = () => {
}; };
API_CLIENT.createEvent(rqObj) API_CLIENT.createEvent(rqObj)
.then(() => { .then(() => {
API_CLIENT.getEvents().then((r) => {
context.updateEvents(r);
history.push("/"); history.push("/");
});
}) })
.catch(async (e) => { .catch(async (e) => {
await spawnError(e.toString()); await spawnError(e.toString());
+30 -6
View File
@@ -1,32 +1,56 @@
import { useTitle } from "../../utils/useTitle"; import { useTitle } from "../../utils/useTitle";
import { useState, useRef, useEffect, useContext } from "react"; import { useState, useRef, useEffect } from "react";
import { Stack } from "react-bootstrap"; import { Stack } from "react-bootstrap";
import { EventPreview } from "../../components/EventPreview"; import { EventPreview } from "../../components/EventPreview";
import { container } from "../../global.module.scss"; import { container } from "../../global.module.scss";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import { BIcon } from "../../components/BIcon"; import { BIcon } from "../../components/BIcon";
// import HoldingPlant from "../../components/Pop-up/AnimatedHand"; // import HoldingPlant from "../../components/Pop-up/AnimatedHand";
import { EVENT_CONTEXT } from "../../constants"; import { API_CLIENT } from "../../constants";
// import { calculateDistance } from "../../utils/map/calculateDistance"; // import { calculateDistance } from "../../utils/map/calculateDistance";
import { useHistory } from "react-router"; import { useHistory } from "react-router";
import Button from "@restart/ui/esm/Button"; import Button from "@restart/ui/esm/Button";
export const Home = () => { export const Home = () => {
useTitle(); useTitle();
const context = useContext(EVENT_CONTEXT);
const [list, updateList] = useState( const [list, updateList] = useState(
context.events.map((e, i) => { API_CLIENT.events.map((e, i) => {
return <EventPreview data={{ name: e.name, type: e.type, lon: e.lon, lat: e.lat, createdTime: e.created.time, time: e.time, id: e._id, address: e.address }} key={i} />; return <EventPreview data={{ name: e.name, type: e.type, lon: e.lon, lat: e.lat, createdTime: e.created.time, time: e.time, id: e._id, address: e.address }} key={i} />;
}) })
); );
const sortDropdown = useRef(null); const sortDropdown = useRef(null);
useEffect(() => { useEffect(() => {
API_CLIENT.on("EVENT_RELOAD", (list) => {
updateList(
list.map((e, i) => {
return (
<EventPreview
data={{ name: e.name, type: e.type, lon: e.lon, lat: e.lat, createdTime: e.created.time, time: e.time, id: e._id, address: e.address }}
key={i}
/>
);
})
);
});
API_CLIENT.on("EVENT_CREATE", (list) => {
updateList(
list.map((e, i) => {
return (
<EventPreview
data={{ name: e.name, type: e.type, lon: e.lon, lat: e.lat, createdTime: e.created.time, time: e.time, id: e._id, address: e.address }}
key={i}
/>
);
})
);
});
sortDropdown.current.addEventListener("input", (e) => { sortDropdown.current.addEventListener("input", (e) => {
const value = e.target.value; const value = e.target.value;
const type = value.split(":")[0]; const type = value.split(":")[0];
const direction = value.split(":")[1]; const direction = value.split(":")[1];
const newOrder = context.events.sort((a, b) => { const newOrder = API_CLIENT.events.sort((a, b) => {
switch (type) { switch (type) {
case "event-date": case "event-date":
return direction === "ascending" ? a.time - b.time : b.time - a.time; return direction === "ascending" ? a.time - b.time : b.time - a.time;
@@ -51,7 +75,7 @@ export const Home = () => {
}) })
); );
}); });
}, [context.events]); }, []);
const history = useHistory(); const history = useHistory();
+18 -5
View File
@@ -1,22 +1,33 @@
import axios from "axios"; import axios from "axios";
import { EventEmitter } from "events";
export class APIClient { export class APIClient extends EventEmitter {
#dbUrl = ""; #dbUrl = "";
#events = [];
constructor(dbUrl) { constructor(dbUrl) {
super();
if (typeof dbUrl !== "string") throw new Error("Database URL is not a string"); if (typeof dbUrl !== "string") throw new Error("Database URL is not a string");
this.#dbUrl = dbUrl; this.#dbUrl = dbUrl;
} }
async getEvents() {
get events() {
return this.#events;
}
async fetchEvents() {
const rq = await axios.get(`${this.#dbUrl}/api/getEvents`); 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}`); 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; return rq.data;
} }
async getEvent(id) { async getEvent(id) {
if (typeof id !== "string") throw new TypeError("Invalid ID type"); if (typeof id !== "string") throw new TypeError("Invalid ID type");
const events = await this.getEvents(); return this.#events.find((e) => e.id === id) ?? null;
return events.find((e) => e.id === id) ?? null;
} }
async createEvent(data) { async createEvent(data) {
//Check types //Check types
if (typeof data !== "object") throw new TypeError("Data object is required"); if (typeof data !== "object") throw new TypeError("Data object is required");
@@ -27,6 +38,8 @@ export class APIClient {
//Make POST request //Make POST request
const rq = await axios.post(`${this.#dbUrl}/api/createEvent`, data); 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}`); 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;
} }
} }
+2 -2
View File
@@ -51,10 +51,10 @@ app.post("/api/createEvent", (req, res) => {
lat: req.body.lat, lat: req.body.lat,
lon: req.body.lon, lon: req.body.lon,
}; };
events.create(data, (err) => { events.create(data, (err, data) => {
if (err) return res.status(400).json({ msg: err }); if (err) return res.status(400).json({ msg: err });
// saved! // saved!
res.status(200).json("ok"); res.status(200).json(data);
}); });
}); });
app.use((req, res, next) => { app.use((req, res, next) => {