-
{cats.map(catsis=>
import { useState } from 'react'; import './App.css'; import thunk from 'redux-thunk'; import {createStore, combineReducers, applyMiddleware} from 'redux'; import { Provider, connect } from 'react-redux'; const store = createStore(combineReducers({ auth: authReducer, promise: promiseReducer, cart: localStoreReducer(cartReducer, "cart") }), applyMiddleware(thunk)) function jwtDecode(token) { try { return JSON.parse(atob(token.split('.')[1])) } catch (e) { } } function authReducer(state = {}, { type, token }) { //{ // token, payload //} if (type === 'AUTH_LOGIN') { //пытаемся токен раскодировать const payload = jwtDecode(token) if (payload) { //и если получилось return { token, payload //payload - раскодированный токен; } } } if (type === 'AUTH_LOGOUT') { return {} } return state; } function countReducer(state = { count: 0 }, { type }) { if (type === "COUNT_INC") { return { count: state.count + 1 } } if (type === "COUNT_DEC") { return { count: state.count - 1 } } return state } function localStoreReducer(reducer, localStorageKey) { function localStoredReducer(state, action) { // Если state === undefined, то достать старый state из local storage if (state === undefined) { try { return JSON.parse(localStorage[localStorageKey]) } catch (e) { } } const newState = reducer(state, action) // Сохранить newState в local storage localStorage[localStorageKey] = JSON.stringify(newState) return newState } return localStoredReducer } function promiseReducer(state = {}, { type, name, status, payload, error }) { ////????? //ОДИН ПРОМИС: //состояние: PENDING/FULFILLED/REJECTED //результат //ошибка: //{status, payload, error} //{ // name1:{status, payload, error} // name2:{status, payload, error} // name3:{status, payload, error} //} if (type === 'PROMISE') { return { ...state, [name]: { status, payload, error } } } return state } const actionPending = (name) => ({ type: 'PROMISE', status: 'PENDING', name }) const actionFulfilled = (name, payload) => ({ type: 'PROMISE', status: 'FULFILLED', name, payload }) const actionRejected = (name, error) => ({ type: 'PROMISE', status: 'REJECTED', name, error }) const actionPromise = (name, promise) => async dispatch => { try { dispatch(actionPending(name)) let payload = await promise dispatch(actionFulfilled(name, payload)) return payload } catch (e) { dispatch(actionRejected(name, e)) } } // const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms)) // function combineReducers(reducers) { //пачку редьюсеров как объект {auth: authReducer, promise: promiseReducer} // function combinedReducer(combinedState = {}, action) { //combinedState - типа {auth: {...}, promise: {....}} // const newCombinedState = {} // for (const [reducerName, reducer] of Object.entries(reducers)) { // const newSubState = reducer(combinedState[reducerName], action) // if (newSubState !== combinedState[reducerName]) { // newCombinedState[reducerName] = newSubState // } // } // if (Object.keys(newCombinedState).length === 0) { // return combinedState // } // return { ...combinedState, ...newCombinedState } // } // return combinedReducer //нам возвращают один редьюсер, который имеет стейт вида {auth: {...стейт authReducer-а}, promise: {...стейт promiseReducer-а}} // } function cartReducer(state = {}, { type, count = 1, good }) { // type CART_ADD CART_REMOVE CART_CLEAR CART_DEL // { // id1: {count: 1, good: {name, price, images, id}} // } if (type === "CART_ADD") { return { ...state, [good._id]: { count: count + (state[good._id]?.count || 0), good }, }; } if (type === "CART_DELETE") { if (state[good._id].count > 1) { return { ...state, [good._id]: { count: -count + (state[good._id]?.count || 0), good, }, }; } if (state[good._id].count === 1) { let { [good._id]: id1, ...newState } = state; //o4en strashnoe koldunstvo //delete newState[good._id] return newState; } } if (type === "CART_CLEAR") { return {}; } if (type === "CART_REMOVE") { // let newState = {...state} let { [good._id]: id1, ...newState } = state; //o4en strashnoe koldunstvo //delete newState[good._id] return newState; } return state; } const backendURL = 'http://shop-roles.node.ed.asmer.org.ua/' const getGQL = (url) => (query, variables) => fetch(url, { method: "POST", headers: { "Content-Type": "application/json", ...(localStorage.authToken ? { Authorization: "Bearer " + localStorage.authToken } : {}), }, body: JSON.stringify({ query, variables }), }) .then((res) => res.json()) .then((data) => { if (data.data) { return Object.values(data.data)[0]; } else throw new Error(JSON.stringify(data.errors)); }); const gql = getGQL(backendURL + "graphql"); // const gql = (url, query, variables) => fetch(url, { // method: 'POST', // headers: { // "Content-Type": "application/json", // Accept: "application/json", // }, // body: JSON.stringify({ query, variables }) // }).then(res => res.json()) // const backendURL = 'http://shop-roles.node.ed.asmer.org.ua/graphql' const actionRootCats = () => actionPromise( 'rootCats', gql( `query { CategoryFind(query: "[{\\"parent\\":null}]"){ _id name } }` ) ) const actionCatById = (_id) => //добавить подкатегории actionPromise( 'catById', gql( `query catById($q: String){ CategoryFindOne(query: $q){ _id name goods { _id name price images { url } } } }`, { q: JSON.stringify([{ _id }]) } ) ) const actionGoodById = (_id) => actionPromise( 'goodByID', gql( `query goodByID($q:String){ GoodFindOne(query: $q){ _id name description price categories{ _id name } images{ url } } }`, { q: JSON.stringify([{ _id }]) } ) ) const actionRegistr = (login, password) => actionPromise( 'registr', gql( `mutation register($login:String, $password:String){ UserUpsert(user: {login:$login, password:$password}){ _id login } }`, { login: login, password: password } ) ) const actionLogin = (login, password) => actionPromise( 'login', gql( `query log($login:String, $password:String){ login(login:$login, password:$password) }`, { login: login, password: password } ) ) const actionOrder = () => async (dispatch, getState) => { let { cart } = getState(); const orderGoods = Object.entries(cart).map(([_id, { count }]) => ({ good: { _id }, count, })); let result = await dispatch( actionPromise( "order", gql( ` mutation newOrder($order:OrderInput){ OrderUpsert(order:$order) { _id total } } `, { order: { orderGoods } } ) ) ); if (result?._id) { dispatch(actionCartClear()); document.location.hash = "#/cart/"; alert("Покупка успішна") } }; const orderHistory = () => actionPromise( "history", gql(` query OrderFind{ OrderFind(query:"[{}]"){ _id total createdAt orderGoods{ count good{ _id name price images{ url } } owner{ _id login } } } } `) ); const actionAuthLogin = (token) => (dispatch, getState) => { const oldState = getState() dispatch({ type: 'AUTH_LOGIN', token }) const newState = getState() if (oldState !== newState) localStorage.authToken = token } const actionAuthLogout = () => dispatch => { dispatch({ type: 'AUTH_LOGOUT' }) localStorage.removeItem('authToken') } const actionCartAdd = (good, count = 1) => ({ type: "CART_ADD", good, count }); const actionCartChange = (good, count = 1) => ({ type: "CART_CHANGE", good, count, }); ///oninput меняяем полностью const actionCartDelete = (good) => ({ type: "CART_DELETE", good }); const actionCartClear = () => ({ type: "CART_CLEAR" }); const actionCartRemove = (good) =>({ type: "CART_REMOVE", good }) const actionFullLogin = (login, password) => async (dispatch) => { let token = await dispatch(actionLogin(login, password)) if (token) { dispatch(actionAuthLogin(token)) } } const actionFullRegistr = (login, password) => async (dispatch) => { try { await dispatch(actionRegistr(login, password)) } catch (e) { return console.log(e) } await dispatch(actionFullLogin(login, password)) } //не забудьте combineReducers если он у вас уже есть if (localStorage.authToken) { store.dispatch(actionAuthLogin(localStorage.authToken)) } //const store = createStore(combineReducers({promise: promiseReducer, auth: authReducer, cart: cartReducer})) store.subscribe(() => console.log(store.getState())) store.dispatch(actionRootCats()) // store.dispatch(actionLogin('test456', '123123')) const LoginForm = ({onLogin}) => { const [login, setLogin] = useState('') const [password, setPassword] = useState('') const disableButton = () => { return !(login !== '' && password !== '') } const Vhod = () => { onLogin(login,password) } return(
Id: {_id}