Archived
new event state management
MAJOR!!!
This commit is contained in:
1 parent
44645884c2
commit
81e0f81157
7 files changed
+144
-74
No files matched your search
+88
-49
@@ -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,57 +8,96 @@ 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 = []) {
|
return (
|
||||||
if (!Array.isArray(events)) throw new TypeError("Events must come in array");
|
<Route key={e._id} exact path={`/event/${e._id}`}>
|
||||||
setContext({
|
<Event
|
||||||
events: events,
|
data={{
|
||||||
updateEvents: this.updateEvents,
|
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 (
|
return (
|
||||||
<EVENT_CONTEXT.Provider value={context}>
|
<Router>
|
||||||
<Router>
|
<Navbar />
|
||||||
<Navbar />
|
<Switch>
|
||||||
<Switch>
|
<Route exact path="/about" component={About} />
|
||||||
<Route exact path="/about" component={About} />
|
<Route exact path="/credits" component={Credits} />
|
||||||
<Route exact path="/credits" component={Credits} />
|
<Route exact path="/users" component={Users} />
|
||||||
<Route exact path="/users" component={Users} />
|
<Route exact path="/">
|
||||||
<Route exact path="/">
|
<Home />
|
||||||
<Home />
|
</Route>
|
||||||
</Route>
|
<Route exact path="/create" component={CreateEvent} />
|
||||||
<Route exact path="/create" component={CreateEvent} />
|
<Route exact path="/login" component={LoginPage} />
|
||||||
<Route exact path="/login" component={LoginPage} />
|
{routes}
|
||||||
{Array.isArray(props.events) &&
|
<Route component={NotFound} />
|
||||||
props.events.map((e) => {
|
</Switch>
|
||||||
return (
|
</Router>
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -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
@@ -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")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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) => {
|
history.push("/");
|
||||||
context.updateEvents(r);
|
|
||||||
history.push("/");
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(async (e) => {
|
.catch(async (e) => {
|
||||||
await spawnError(e.toString());
|
await spawnError(e.toString());
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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) => {
|
||||||
|
|||||||
Reference in new issue
Block a user