redux to react-redux

This commit is contained in:
2022-07-26 16:11:55 +02:00
parent c0b1a35e58
commit 69f5f98b2a
11 changed files with 172 additions and 377 deletions

View File

@@ -1,8 +1,10 @@
import axios from "axios"; import axios from "axios";
import * as toggles from "./toggles";
import { push } from "connected-react-router"; import { push } from "connected-react-router";
import { backend } from "../config.js"; import { backend } from "../config.js";
import store from "../index.js"; import store from "../index.js";
import * as restaurant from "../redux/slices/restaurantSlice";
import * as toggle from "../redux/slices/togglesSlice";
import * as notifications from "../redux/slices/notificationsSlice";
axios.defaults.withCredentials = true; axios.defaults.withCredentials = true;
@@ -12,26 +14,36 @@ axios.interceptors.response.use(
}, },
(error) => { (error) => {
return new Promise((resolve) => { return new Promise((resolve) => {
if (error.response && error.response.status === 401 && error.config && !error.config.__isRetryRequest) { if (
const response = axios.post(backend + "user/refreshtoken", {withCredentials: true}).then((res) => { error.response &&
const jwt = res.headers['x-auth-token']; error.response.status === 401 &&
store.dispatch(setNewToken(jwt)) error.config &&
error.config.__isRetryRequest = true !error.config.__isRetryRequest
error.config.headers['x-auth-token'] = jwt ) {
const response = axios
.post(backend + "user/refreshtoken", { withCredentials: true })
.then((res) => {
const jwt = res.headers["x-auth-token"];
store.dispatch(setNewToken(jwt));
error.config.__isRetryRequest = true;
error.config.headers["x-auth-token"] = jwt;
return axios(error.config); return axios(error.config);
}) });
resolve(response) resolve(response);
} else { } else {
if (error.response && error.response.status === 403) { if (error.response && error.response.status === 403) {
store.dispatch(logout("Podany użytkownik, lub hasło nie istnieje.", "error")); store.dispatch(
logout("Podany użytkownik, lub hasło nie istnieje.", "error")
);
} else if (error.response && error.response.status === 400) { } else if (error.response && error.response.status === 400) {
store.dispatch(logout("Dane nieprawidłowe.", "error")); store.dispatch(logout("Dane nieprawidłowe.", "error"));
} else { } else {
store.dispatch(logout("Sesja wygasła", "info")); store.dispatch(logout("Sesja wygasła", "info"));
} }
} }
})
}); });
}
);
const autocomplete = (input) => { const autocomplete = (input) => {
return { return {
@@ -49,9 +61,9 @@ export const clearAutocomplete = () => {
export const setNewToken = (token) => { export const setNewToken = (token) => {
return { return {
type: "SET_NEW_TOKEN", type: "SET_NEW_TOKEN",
payload: token payload: token,
} };
} };
export const fetchAutocomplete = (input) => { export const fetchAutocomplete = (input) => {
return function (dispatch) { return function (dispatch) {
@@ -100,20 +112,13 @@ export const setSearchQuery = (input) => {
}; };
}; };
export const setRestaurant = (restaurant) => {
return {
type: "SET_RESTAURANT",
payload: restaurant,
};
};
export const fetchRestaurant = (id) => { export const fetchRestaurant = (id) => {
return function (dispatch) { return function (dispatch) {
axios axios
.get(backend + "restaurant?restaurantId=" + id) .get(backend + "restaurant?restaurantId=" + id)
.then((response) => { .then((response) => {
dispatch(setRestaurant(response.data)); dispatch(restaurant.setRestaurant(response.data));
dispatch(toggles.hideDishes()); dispatch(toggle.hideDishes());
dispatch(fetchAllDishes(id)); dispatch(fetchAllDishes(id));
}) })
.catch((err) => .catch((err) =>
@@ -142,7 +147,7 @@ export const fetchAllDishes = (id) => {
.get(backend + "restaurant/dishes?restaurantId=" + id) .get(backend + "restaurant/dishes?restaurantId=" + id)
.then((response) => { .then((response) => {
dispatch(setDishes(response.data)); dispatch(setDishes(response.data));
dispatch(toggles.showDishes()); dispatch(toggle.showDishes());
}); });
}; };
}; };
@@ -163,7 +168,7 @@ export const fetchDish = (id) => {
export const refreshUserData = () => { export const refreshUserData = () => {
return function (dispatch) { return function (dispatch) {
const state = store.getState() const state = store.getState();
axios({ axios({
url: backend + "user/refresh", url: backend + "user/refresh",
method: "POST", method: "POST",
@@ -173,7 +178,7 @@ export const refreshUserData = () => {
}) })
.then((response) => { .then((response) => {
dispatch( dispatch(
toggles.setLoggedIn( toggle.setLoggedIn(
response.data.firstname, response.data.firstname,
response.data.lastname, response.data.lastname,
state.data.userData.jwt, state.data.userData.jwt,
@@ -195,180 +200,10 @@ export const refreshUserData = () => {
}; };
}; };
export const tryLogin = (username, password) => {
const data = { email: username, password: password };
return function (dispatch) {
dispatch(toggles.showBackdrop());
axios
.post(backend + "user/login", data)
.then((response) => {
if(response.data.isRestaurant === true){
const jwt = response.headers["x-auth-token"];
dispatch(
toggles.setLoggedIn(
response.data.firstname,
response.data.lastname,
jwt,
response.data.id,
response.data.email,
"",
response.data.NIP,
response.data.adress,
response.data.companyName,
response.data.restaurants,
response.data.isRestaurant
)
);
dispatch(toggles.hideBackdrop());
dispatch(notification(`Witaj ${response.data.firstname}!`, "success"));
dispatch(push("/"));
} else {
const jwt = response.headers["x-auth-token"];
dispatch(
toggles.setLoggedIn(
"",
"",
jwt,
response.data.id,
response.data.email,
response.data.login,
"",
"",
"",
[],
response.data.isRestaurant
)
);
dispatch(toggles.hideBackdrop());
dispatch(notification(`Witaj ${response.data.login}!`, "success"));
dispatch(push("/"));
}
})
.catch((err) => {
if (!err.response) {
console.log(err);
} else if (err.response.status === 404) {
dispatch(toggles.hideBackdrop());
dispatch(notification("Użytkownik nie istnieje :(", "error"));
} else if (err.response.status === 403) {
dispatch(toggles.hideBackdrop());
dispatch(notification("Błędne dane logowania :(", "error"));
} else {
dispatch(toggles.hideBackdrop());
dispatch(notification("Błąd serwera :(", "error"));
}
});
};
};
export const remindPassword = (email) => {
return function (dispatch) {
const data = { email: email };
dispatch(toggles.showBackdrop());
axios
.post(backend + "user/forgotpassword", data)
.then((response) => {
dispatch(toggles.hideBackdrop());
dispatch(notification(response.data, "info"));
})
.catch((e) => {
dispatch(toggles.hideBackdrop());
dispatch(notification(e.response.data, "error"));
});
};
};
export const changePassword = (email, password, token) => {
return function (dispatch) {
const data = {
token: token,
email: email,
newPass: password,
};
dispatch(toggles.showBackdrop());
axios
.post(backend + "user/resetpass", data)
.then((response) => {
dispatch(toggles.hideBackdrop());
dispatch(notification(response.data, "info"));
})
.catch((e) => {
dispatch(toggles.hideBackdrop());
dispatch(notification(e.response.data, "error"));
});
};
};
export const logout = (message, type) => {
return function (dispatch) {
if(message && type){
dispatch(notification(message, type));
} else {
dispatch(notification("Wylogowano.", "info"));
}
dispatch(toggles.hideBackdrop());
dispatch(toggles.setLoggedOut());
dispatch(push("/"));
};
};
export const tryRegister = (data) => {
return function (dispatch) {
dispatch(toggles.showBackdrop());
axios
.post(backend + "user/register", data)
.then((response) => {
if (response.status === 201) {
dispatch(
notification(
"Rejestracja przebiegła pomyślnie, możesz teraz zalogować się do swojego konta.",
"success"
)
);
dispatch(toggles.hideBackdrop());
dispatch(push("/"))
}
})
.catch((err) => {
if (err.response.status === 500) {
dispatch(
notification(
"Wystąpił nieoczekiwany błąd serwera, przepraszamy...",
"error"
)
);
dispatch(toggles.hideBackdrop());
} else if (err.response.status === 409) {
dispatch(
notification(
"Adres email jest już zajęty, proszę użyć innego.",
"error"
)
);
dispatch(toggles.hideBackdrop());
}
});
};
};
export const setTempData = (data) => {
return {
type: "SET_TEMP_DATA",
payload: data,
};
};
export const clearTempData = () => {
return {
type: "CLEAR_TEMP_DATA",
};
};
export const notification = (message, type) => { export const notification = (message, type) => {
return function (dispatch) { return function (dispatch) {
dispatch( dispatch(
toggles.enqueueSnackbar({ toggle.enqueueSnackbar({
message: message, message: message,
options: { options: {
key: new Date().getTime() + Math.random(), key: new Date().getTime() + Math.random(),
@@ -389,13 +224,13 @@ export const updateRestaurant = (restaurant) => {
export const setTags = (tags) => { export const setTags = (tags) => {
return { return {
type: "SET_TAGS", type: "SET_TAGS",
payload: tags payload: tags,
} };
} };
export const setTypes = (types) => { export const setTypes = (types) => {
return { return {
type: "SET_TYPES", type: "SET_TYPES",
payload: types payload: types,
} };
} };

View File

@@ -1,15 +1,3 @@
export const showDishes = () => {
return {
type: "SET_DISHLIST_VISIBLE",
};
};
export const hideDishes = () => {
return {
type: "SET_DISHLIST_HIDDEN",
};
};
export const setLoggedIn = ( export const setLoggedIn = (
firstname, firstname,
lastname, lastname,
@@ -36,7 +24,7 @@ export const setLoggedIn = (
adress: adress, adress: adress,
companyName: companyName, companyName: companyName,
restaurants: restaurants, restaurants: restaurants,
isRestaurant: isRestaurant isRestaurant: isRestaurant,
}, },
}; };
}; };
@@ -47,18 +35,6 @@ export const setLoggedOut = () => {
}; };
}; };
export const hideRegulamin = () => {
return {
type: "DIALOG_REGULAMIN_HIDE",
};
};
export const showRegulamin = () => {
return {
type: "DIALOG_REGULAMIN_SHOW",
};
};
export const enqueueSnackbar = (notification) => { export const enqueueSnackbar = (notification) => {
const key = notification.options && notification.options.key; const key = notification.options && notification.options.key;
@@ -70,20 +46,3 @@ export const enqueueSnackbar = (notification) => {
}, },
}; };
}; };
export const removeSnackbar = (key) => ({
type: "REMOVE_SNACKBAR",
key,
});
export const showBackdrop = () => {
return {
type: "SHOW_BACKDROP",
};
};
export const hideBackdrop = () => {
return {
type: "HIDE_BACKDROP",
};
};

View File

@@ -4,18 +4,17 @@ import DishList from "./DishList";
import CircularProgress from "@material-ui/core/CircularProgress"; import CircularProgress from "@material-ui/core/CircularProgress";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { extractTags } from "../../Services"; import { extractTags } from "../../Services";
import { useSelector, useDispatch } from "react-redux"; import { useAppDispatch, useAppSelector } from "../../redux/hooks";
import { fetchRestaurant } from "../../actions"; import { fetchRestaurant } from "../../actions";
import GoogleMapStatic from "./GoogleMapStatic"; import GoogleMapStatic from "./GoogleMapStatic";
import WorkingHours from "./WorkingHours"; import WorkingHours from "./WorkingHours";
import Social from "./Social"; import Social from "./Social";
import LunchMenu from "./LunchMenu";
export default function Restaurant(props) { export default function Restaurant(props) {
const restaurant = useSelector((state) => state.restaurant); const restaurant = useAppSelector((state) => state.restaurant);
const { id } = useParams(); const { id } = useParams();
const dispatch = useDispatch(); const dispatch = useAppDispatch();
const showDishList = useSelector((state) => state.data.showDishList); const showDishList = useAppSelector((state) => state.toggles.showDishList);
useEffect(() => { useEffect(() => {
dispatch(fetchRestaurant(id)); dispatch(fetchRestaurant(id));
@@ -61,7 +60,9 @@ export default function Restaurant(props) {
<WorkingHours hours={restaurant.workingHours} /> <WorkingHours hours={restaurant.workingHours} />
{restaurant.lunchHours && <h5>Lunch menu</h5>} {restaurant.lunchHours && <h5>Lunch menu</h5>}
{restaurant.lunchHours && ( {restaurant.lunchHours && (
<p style={{ color: "#bbbbbb", fontWeight: 400 }}>{restaurant.lunchHours}</p> <p style={{ color: "#bbbbbb", fontWeight: 400 }}>
{restaurant.lunchHours}
</p>
)} )}
<hr /> <hr />
<h5>Lokalizacja</h5> <h5>Lokalizacja</h5>
@@ -72,9 +73,6 @@ export default function Restaurant(props) {
</div> </div>
<div className="restaurant-content"> <div className="restaurant-content">
<div className="restaurant-dishes"> <div className="restaurant-dishes">
{!showDishList && <CircularProgress />}
{(showDishList && restaurant.lunchMenu) && <h3>Zestawy</h3>}
{(showDishList && restaurant.lunchMenu) && <LunchMenu restaurant={restaurant} />}
<h3>Menu</h3> <h3>Menu</h3>
{!showDishList && <CircularProgress />} {!showDishList && <CircularProgress />}
{showDishList && <DishList />} {showDishList && <DishList />}

View File

@@ -1,37 +1,5 @@
const initialState = {
showDishList: false,
loggedIn: false,
userData: {
jwt: "",
firstname: "",
lastname: "",
userId: "",
userEmail: "",
billing: {
NIP: "",
adress: "",
companyName: "",
},
restaurants: [],
isRestaurant: false
},
dialogs: {
regulamin: false,
},
backdrop: false,
tempData: {},
filters: {
types: [],
tags: []
}
};
const data = (state = initialState, action) => { const data = (state = initialState, action) => {
switch (action.type) { switch (action.type) {
case "SET_DISHLIST_VISIBLE":
return (state = { ...state, showDishList: true });
case "SET_DISHLIST_HIDDEN":
return (state = { ...state, showDishList: false });
case "SET_LOGGEDIN": case "SET_LOGGEDIN":
return (state = { return (state = {
...state, ...state,
@@ -49,7 +17,7 @@ const data = (state = initialState, action) => {
companyName: action.payload.companyName, companyName: action.payload.companyName,
}, },
restaurants: action.payload.restaurants, restaurants: action.payload.restaurants,
isRestaurant: action.payload.isRestaurant isRestaurant: action.payload.isRestaurant,
}, },
}); });
case "SET_LOGGEDOUT": case "SET_LOGGEDOUT":
@@ -68,29 +36,17 @@ const data = (state = initialState, action) => {
companyName: "", companyName: "",
}, },
restaurants: [], restaurants: [],
isRestaurant: false isRestaurant: false,
}, },
}); });
case "DIALOG_REGULAMIN_SHOW":
return (state = {
...state,
dialogs: { ...state.dialogs, regulamin: true },
});
case "DIALOG_REGULAMIN_HIDE":
return (state = {
...state,
dialogs: { ...state.dialogs, regulamin: false },
});
case "SET_TEMP_DATA": case "SET_TEMP_DATA":
return (state = { ...state, tempData: action.payload }); return (state = { ...state, tempData: action.payload });
case "CLEAR_TEMP_DATA": case "CLEAR_TEMP_DATA":
return (state = { ...state, tempData: {} }); return (state = { ...state, tempData: {} });
case "SHOW_BACKDROP":
return (state = { ...state, backdrop: true });
case "HIDE_BACKDROP":
return (state = { ...state, backdrop: false });
case "UPDATE_RESTAURANT": case "UPDATE_RESTAURANT":
const index = state.userData.restaurants.findIndex((restaurant) => restaurant._id === action.payload._id); const index = state.userData.restaurants.findIndex(
(restaurant) => restaurant._id === action.payload._id
);
return (state = { return (state = {
...state, ...state,
userData: { userData: {
@@ -98,16 +54,25 @@ const data = (state = initialState, action) => {
restaurants: [ restaurants: [
...state.userData.restaurants.slice(0, index), ...state.userData.restaurants.slice(0, index),
action.payload, action.payload,
...state.userData.restaurants.slice(index + 1) ...state.userData.restaurants.slice(index + 1),
], ],
}, },
}); });
case "SET_NEW_TOKEN": case "SET_NEW_TOKEN":
return (state = {...state, userData: {...state.userData, jwt: action.payload}}) return (state = {
...state,
userData: { ...state.userData, jwt: action.payload },
});
case "SET_TYPES": case "SET_TYPES":
return (state = {...state, filters: {...state.filters, types: action.payload}}) return (state = {
...state,
filters: { ...state.filters, types: action.payload },
});
case "SET_TAGS": case "SET_TAGS":
return (state = {...state, filters: {...state.filters, tags: action.payload}}) return (state = {
...state,
filters: { ...state.filters, tags: action.payload },
});
default: default:
return state; return state;
} }

View File

@@ -1,16 +1,25 @@
import { createSlice } from "@reduxjs/toolkit"; import { createSlice } from "@reduxjs/toolkit";
const initialState = []; const initialState: any[] = [];
export const userSlice = createSlice({ export const notificationsSlice = createSlice({
name: "notifications", name: "notifications",
initialState: initialState, initialState: initialState,
reducers: { reducers: {
addNotification: (state, action) => { addNotification: (state, action) => {
state = [...state, { key: action.key }]; state = [
...state,
{ key: action.payload.key, ...action.payload.notification },
];
},
removeNotification: (state, action) => {
state = state.filter(
(notification) => notification.key != action.payload.key
);
}, },
}, },
}); });
export const { clearUserData } = userSlice.actions; export const { addNotification, removeNotification } =
export default userSlice.reducer; notificationsSlice.actions;
export default notificationsSlice.reducer;

View File

@@ -0,0 +1,21 @@
import { createSlice } from "@reduxjs/toolkit";
import { Restaurant } from "../../typescript/interfaces";
import axios from "axios";
const initialState: Restaurant = {} as Restaurant;
export const restaurantSlice = createSlice({
name: "restaurant",
initialState: initialState,
reducers: {
clearRestaurant: (state) => {
state = initialState;
},
setRestaurant: (state, action) => {
state = action.payload;
},
},
});
export const { clearRestaurant, setRestaurant } = restaurantSlice.actions;
export default restaurantSlice.reducer;

View File

@@ -1,29 +0,0 @@
import { User } from "../../typescript/interfaces";
import { createSlice } from "@reduxjs/toolkit";
const initialState: User = {
id: "",
username: "",
email: "",
isRestaurant: true,
trialUsed: false,
billing: {
NIP: "",
adress: "",
companyName: "",
},
restaurants: [],
};
export const tempDataSlice = createSlice({
name: "tempData",
initialState: initialState,
reducers: {
clearTempData: (state) => {
state = initialState;
},
},
});
export const { clearTempData } = tempDataSlice.actions;
export default tempDataSlice.reducer;

View File

@@ -0,0 +1,42 @@
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
backdrop: false,
showDishList: false,
regulamin: false,
};
export const togglesSlice = createSlice({
name: "toggles",
initialState: initialState,
reducers: {
showBackdrop: (state) => {
state = { ...state, backdrop: true };
},
hideBackdrop: (state) => {
state = { ...state, backdrop: false };
},
showDishes: (state) => {
state = { ...state, showDishList: true };
},
hideDishes: (state) => {
state = { ...state, showDishList: false };
},
showRegulamin: (state) => {
state = { ...state, showDishList: true };
},
hideRegulamin: (state) => {
state = { ...state, showDishList: false };
},
},
});
export const {
showBackdrop,
hideBackdrop,
showDishes,
hideDishes,
showRegulamin,
hideRegulamin,
} = togglesSlice.actions;
export default togglesSlice.reducer;

View File

@@ -1,4 +1,4 @@
import { User } from "../../typescript/interfaces"; import { Restaurant, User } from "../../typescript/interfaces";
import { createSlice } from "@reduxjs/toolkit"; import { createSlice } from "@reduxjs/toolkit";
const initialState: User = { const initialState: User = {
@@ -22,6 +22,20 @@ export const userSlice = createSlice({
clearUserData: (state) => { clearUserData: (state) => {
state = initialState; state = initialState;
}, },
updateRestaurant: (state, action) => {
const index = state.restaurants?.findIndex(
(restaurant) => restaurant.id === action.payload.id
);
let restaurants: Restaurant[] = state.restaurants || [];
state = {
...state,
restaurants: [
...restaurants.slice(0, index),
action.payload,
...restaurants.slice(index + 1),
],
};
},
}, },
}); });

View File

@@ -1,21 +0,0 @@
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
backdrop: false,
};
export const viewportSlice = createSlice({
name: "viewport",
initialState: initialState,
reducers: {
showBackdrop: (state) => {
state = { ...state, backdrop: true };
},
hideBackdrop: (state) => {
state = { ...state, backdrop: false };
},
},
});
export const { showBackdrop, hideBackdrop } = viewportSlice.actions;
export default viewportSlice.reducer;

View File

@@ -1,13 +1,15 @@
import { configureStore } from "@reduxjs/toolkit"; import { configureStore } from "@reduxjs/toolkit";
import userReducer from "./slices/userSlice"; import userReducer from "./slices/userSlice";
import tempDataReducer from "./slices/tempDataSlice"; import restaurantReducer from "./slices/restaurantSlice";
import viewportReducer from "./slices/viewportSlice"; import togglesReducer from "./slices/togglesSlice";
import notificationsReducer from "./slices/notificationsSlice";
const store = configureStore({ const store = configureStore({
reducer: { reducer: {
user: userReducer, user: userReducer,
tempData: tempDataReducer, restaurant: restaurantReducer,
viewport: viewportReducer, toggles: togglesReducer,
notifications: notificationsReducer,
}, },
}); });