Archived
MAJOR data flow change (login)
Made LoginManager stateless, used context to distribute data over the application
This commit is contained in:
1 parent
88bfa0056d
commit
e027979f9b
10 files changed
+82
-61
No files matched your search
@@ -5,6 +5,7 @@ import { useEffect, useRef } from "react";
|
||||
import { LOGIN_MANAGER } from "../../constants";
|
||||
import { spawnError } from "../../utils/popups/spawnError";
|
||||
import { BIcon } from "../BIcon";
|
||||
import { updateLogin } from "../../context/Login";
|
||||
|
||||
export const LoginPanel = (props) => {
|
||||
const form = useRef(null);
|
||||
@@ -13,7 +14,7 @@ export const LoginPanel = (props) => {
|
||||
e.preventDefault();
|
||||
LOGIN_MANAGER.login({ email: e.srcElement[0].value, password: e.srcElement[1].value })
|
||||
.then((r) => {
|
||||
console.log(r);
|
||||
updateLogin(r);
|
||||
props.close(r);
|
||||
})
|
||||
.catch((e) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Link } from "react-router-dom";
|
||||
import { BIcon } from "../BIcon";
|
||||
import styles from "./index.module.scss";
|
||||
import title from "../../assets/title.svg";
|
||||
import { LOGIN_MANAGER } from "../../constants";
|
||||
import { useLogin } from "../../context/Login";
|
||||
import { spawnPopup } from "../../utils/popups/spawnPopup";
|
||||
import { LoginPanel } from "../LoginPanel";
|
||||
import { UserPanel } from "../UserPanel";
|
||||
@@ -10,6 +10,7 @@ import { useHistory } from "react-router";
|
||||
|
||||
export const Navbar = () => {
|
||||
const history = useHistory();
|
||||
const login = useLogin();
|
||||
|
||||
return (
|
||||
<nav className={styles.nav}>
|
||||
@@ -20,10 +21,10 @@ export const Navbar = () => {
|
||||
aria-label="Zarządzanie kontem"
|
||||
className={styles.navBtn}
|
||||
onClick={async () => {
|
||||
if (LOGIN_MANAGER.state) {
|
||||
if (login) {
|
||||
await spawnPopup(
|
||||
(close) => {
|
||||
return <UserPanel history={history} close={close} />;
|
||||
return <UserPanel state={login} history={history} close={close} />;
|
||||
},
|
||||
{ minWidth: "30vw" }
|
||||
);
|
||||
|
||||
@@ -2,9 +2,10 @@ import styles from "./index.module.scss";
|
||||
import { LOGIN_MANAGER } from "../../constants";
|
||||
import { BIcon } from "../BIcon";
|
||||
import { Stack } from "react-bootstrap";
|
||||
import { updateLogin } from "../../context/Login";
|
||||
|
||||
export const UserPanel = (props) => {
|
||||
if (!LOGIN_MANAGER.state) props.close();
|
||||
if (!props.state) props.close();
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
@@ -12,7 +13,7 @@ export const UserPanel = (props) => {
|
||||
<BIcon icon="x" size={"20px"} />
|
||||
</button>
|
||||
<h3>Zalogowano jako</h3>
|
||||
<h1>{LOGIN_MANAGER.state.email ?? "Nieznany użytkownik"}</h1>
|
||||
<h1>{props.state.email ?? "Nieznany użytkownik"}</h1>
|
||||
<Stack gap={2}>
|
||||
<button
|
||||
aria-label="Dashboard"
|
||||
@@ -27,6 +28,8 @@ export const UserPanel = (props) => {
|
||||
aria-label="Wyloguj się"
|
||||
onClick={async () => {
|
||||
await LOGIN_MANAGER.logout();
|
||||
updateLogin(null);
|
||||
props.history?.push("/");
|
||||
props.close();
|
||||
}}
|
||||
className={styles.logoutBtn}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { createContext, useContext, useState } from "react";
|
||||
|
||||
const login = {
|
||||
state: null,
|
||||
setter: null,
|
||||
};
|
||||
|
||||
const validateData = (data) => {
|
||||
if (data === null) return false;
|
||||
if (typeof data !== "object") throw new TypeError("Incorrect argument");
|
||||
if (typeof data._id !== "string") throw new TypeError("Incorrect value type: _id");
|
||||
if (typeof data.email !== "string") throw new TypeError("Incorrect value type: email");
|
||||
return true;
|
||||
};
|
||||
|
||||
export const LoginContext = createContext(login.state);
|
||||
|
||||
export const useLogin = () => {
|
||||
return useContext(LoginContext);
|
||||
};
|
||||
|
||||
export const updateLogin = (data) => {
|
||||
switch (validateData(data)) {
|
||||
case true:
|
||||
login.setter({
|
||||
_id: data._id,
|
||||
email: data.email,
|
||||
});
|
||||
return;
|
||||
case false:
|
||||
login.setter(null);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
export const Login = (props) => {
|
||||
[login.state, login.setter] = useState(props.initial ?? null);
|
||||
return <LoginContext.Provider value={login.state}>{props.children}</LoginContext.Provider>;
|
||||
};
|
||||
+7
-4
@@ -5,16 +5,19 @@ import { App } from "./App.js";
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
import { API_CLIENT, LOGIN_MANAGER } from "./constants";
|
||||
import { Events } from "./context/Events";
|
||||
import { Login } from "./context/Login";
|
||||
|
||||
(async () => {
|
||||
const events = await API_CLIENT.fetchEvents();
|
||||
await LOGIN_MANAGER.fetchSession();
|
||||
const loginState = await LOGIN_MANAGER.fetchSession();
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<Events initial={events}>
|
||||
<App />
|
||||
</Events>
|
||||
<Login initial={loginState ?? null}>
|
||||
<Events initial={events}>
|
||||
<App />
|
||||
</Events>
|
||||
</Login>
|
||||
</React.StrictMode>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState } from "react";
|
||||
import { Stack } from "react-bootstrap";
|
||||
import { BIcon } from "../../components/BIcon";
|
||||
import { useHistory } from "react-router";
|
||||
import { API_CLIENT, LOGIN_MANAGER } 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";
|
||||
@@ -12,10 +12,12 @@ import { spawnError } from "../../utils/popups/spawnError";
|
||||
import { getPlace } from "../../utils/map/getPlace";
|
||||
import { MapPopup } from "./MapPopup";
|
||||
import { addEvent } from "../../context/Events";
|
||||
import { useLogin } from "../../context/Login";
|
||||
|
||||
export const CreateEvent = () => {
|
||||
const login = useLogin();
|
||||
const history = useHistory();
|
||||
if (LOGIN_MANAGER.state === null) {
|
||||
if (login === null) {
|
||||
history.push("/");
|
||||
}
|
||||
useTitle("Tworzenie wydarzenia");
|
||||
@@ -54,7 +56,7 @@ export const CreateEvent = () => {
|
||||
lat: mapPos?.[1] ?? null,
|
||||
address: locationText,
|
||||
time: date.getTime(),
|
||||
user: LOGIN_MANAGER.state.email,
|
||||
user: login.email,
|
||||
};
|
||||
API_CLIENT.createEvent(rqObj)
|
||||
.then((res) => {
|
||||
|
||||
@@ -10,11 +10,12 @@ import { useHistory } from "react-router";
|
||||
import { spawnPopup } from "../../utils/popups/spawnPopup";
|
||||
import { spawnError } from "../../utils/popups/spawnError";
|
||||
import { getUserPos } from "../../utils/getUserPos";
|
||||
import { useLoginState } from "../../utils/useLoginState";
|
||||
import { useEvents } from "../../context/Events";
|
||||
import { useLogin } from "../../context/Login";
|
||||
|
||||
export const Home = () => {
|
||||
const events = useEvents();
|
||||
const login = useLogin();
|
||||
const history = useHistory();
|
||||
const sortDropdown = useRef(null);
|
||||
const createEventButton = useRef(null);
|
||||
@@ -56,10 +57,9 @@ export const Home = () => {
|
||||
el.removeEventListener("input", cb);
|
||||
};
|
||||
}, [events, list]);
|
||||
|
||||
useLoginState((state) => {
|
||||
if (createEventButton.current) createEventButton.current.disabled = state === null;
|
||||
});
|
||||
useEffect(() => {
|
||||
createEventButton.current.disabled = !login;
|
||||
}, [createEventButton, login]);
|
||||
|
||||
return (
|
||||
<div className={container}>
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
import axios from "axios";
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
export class LoginManager extends EventEmitter {
|
||||
export class LoginManager {
|
||||
#dbUrl = "";
|
||||
#loginState = null;
|
||||
|
||||
get state() {
|
||||
return this.#loginState;
|
||||
}
|
||||
|
||||
constructor(dbUrl) {
|
||||
super();
|
||||
if (typeof dbUrl !== "string") throw new TypeError("dbUrl must be a string");
|
||||
this.#dbUrl = dbUrl;
|
||||
}
|
||||
@@ -22,16 +15,12 @@ export class LoginManager extends EventEmitter {
|
||||
|
||||
const rq = await axios.post(`${this.#dbUrl}/api/auth/register_login`, data);
|
||||
if (rq.status !== 200) throw new Error(`Request failed with status code ${rq.status}: ${rq.statusText}`);
|
||||
this.#loginState = rq.data ?? null;
|
||||
this.emit("STATE_CHANGE", this.#loginState);
|
||||
return rq.data ?? null;
|
||||
}
|
||||
|
||||
async logout() {
|
||||
const rq = await axios.get(`${this.#dbUrl}/api/logout`);
|
||||
if (rq.status !== 200) throw new Error(`Request failed with status code ${rq.status}: ${rq.statusText}`);
|
||||
this.#loginState = null;
|
||||
this.emit("STATE_CHANGE", null);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -39,9 +28,9 @@ export class LoginManager extends EventEmitter {
|
||||
const rq = await axios.get(`${this.#dbUrl}/api/isLogged`);
|
||||
if (rq.status !== 200) throw new Error(`Request failed with status code ${rq.status}: ${rq.statusText}`);
|
||||
if (rq.data !== "not logged") {
|
||||
this.#loginState = rq.data ?? null;
|
||||
this.emit("STATE_CHANGE", this.#loginState);
|
||||
return rq.data ?? null;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { LOGIN_MANAGER } from "../constants";
|
||||
|
||||
export const useLoginState = (callback) => {
|
||||
if (callback && typeof callback !== "function") throw new TypeError("Invalid callback");
|
||||
const [componentState, updateComponentState] = useState(LOGIN_MANAGER.state);
|
||||
useEffect(() => {
|
||||
const listenerFn = (state) => {
|
||||
callback && callback(state);
|
||||
updateComponentState(state);
|
||||
};
|
||||
LOGIN_MANAGER.on("STATE_CHANGE", listenerFn);
|
||||
return () => {
|
||||
LOGIN_MANAGER.removeListener("STATE_CHANGE", listenerFn);
|
||||
};
|
||||
}, [callback]);
|
||||
return componentState;
|
||||
};
|
||||
Reference in new issue
Block a user