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
+144 -74

No files matched your search

+88 -49
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 { 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 (
<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>
);
})
);
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 (
<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 (
<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>
);
})}
<Route component={NotFound} />
</Switch>
</Router>
</EVENT_CONTEXT.Provider>
<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} />
</Switch>
</Router>
);
};
-2
View File
@@ -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: {
+2 -2
View File
@@ -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(
<React.StrictMode>
<App events={dbEvents} />
<App />
</React.StrictMode>,
document.getElementById("root")
);
+4 -8
View File
@@ -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());
+30 -6
View File
@@ -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 <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);
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) => {
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();
+18 -5
View File
@@ -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;
}
}
+2 -2
View File
@@ -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) => {