import logo from './logo.svg'; import './App.scss'; import thunk from 'redux-thunk'; import {createStore, combineReducers, applyMiddleware} from 'redux'; import {Provider, connect} from 'react-redux'; import {useEffect, useState} from 'react'; import {Router, Route, Link, Redirect, match} from 'react-router-dom'; import {createBrowserHistory} from 'history'; const actionPending = name => ({type: 'PROMISE', status: 'PENDING', name}); const actionResolved = (name, payload) => ({type: 'PROMISE', status: 'RESOLVED', name, payload}); const actionRejected = (name, error) => ({type: 'PROMISE', status: 'REJECTED', name, error}); const actionPromise = (name, promise) => async dispatch => { dispatch(actionPending(name)); // 1. {delay1000: {status: 'PENDING'}} try { let payload = await promise; dispatch(actionResolved(name, payload)); return payload; } catch (error) { dispatch(actionRejected(name, error)); } }; const getGQL = url => (query, variables = {}) => fetch(url, { //метод method: 'POST', headers: { //заголовок content-type 'Content-Type': 'application/json', ...(localStorage.authToken ? {'Authorization': 'Bearer ' + localStorage.authToken} : {}) }, //body с ключами query и variables body: JSON.stringify({query, variables}) }) .then(res => res.json()) .then(data => { if (data.errors && !data.data) throw new Error(JSON.stringify(data.errors)); return data.data[Object.keys(data.data)[0]]; }); const backendURL = 'http://shop-roles.asmer.fs.a-level.com.ua'; const gql = getGQL(backendURL + '/graphql'); function jwtDecode(token) { try { let decoded = token.split('.'); decoded = decoded[1]; decoded = atob(decoded); decoded = JSON.parse(decoded); return decoded; } catch (e) { return; } } //скопировать //3 редьюсера //экшоны к ним // const actionRootCats = () => actionPromise('rootCats', gql(`query { CategoryFind(query: "[{\\"parent\\":null}]"){ _id name } }`)); const actionCartAdd = (good, count = 1) => ({type: 'CART_ADD', good, count}); const actionCartRemove = (good, count = 1) => ({type: 'CART_REMOVE', good, count}); const actionCartChange = (good, count = 1) => ({type: 'CART_CHANGE', good, count}); const actionCartClear = (good, count = 1) => ({type: 'CART_CLEAR', good, count}); function cartReducer(state = {}, {type, good = {}, count = 1}) { const {_id} = good; const types = { CART_ADD() { return { ...state, [_id]: {good, count: count + (state[_id]?.count || 0)} }; }, CART_REMOVE() { let newState = {...state}; delete newState[_id]; return { ...newState }; }, CART_CHANGE() { return { ...state, [_id]: {good, count} }; }, CART_CLEAR() { return {}; }, }; if (type in types) return types[type](); return state; } function authReducer(state, {type, token}) { if (!state) { if (localStorage.authToken) { type = 'AUTH_LOGIN'; token = localStorage.authToken; } else { return {}; } } if (type === 'AUTH_LOGIN') { let auth = jwtDecode(token); if (auth) { localStorage.authToken = token; return {token, payload: auth}; } } if (type === 'AUTH_LOGOUT') { localStorage.authToken = ''; return {}; } return state; } function promiseReducer(state = {}, {type, name, status, payload, error}) { if (type === 'PROMISE') { return { ...state, [name]: {status, payload, error} }; } return state; } // Actions ============================= // Логин и логаут const actionAuthLogin = (token) => ({type: 'AUTH_LOGIN', token}); const actionAuthLogout = () => ({type: 'AUTH_LOGOUT'}); const actionLogin = (login = 'tst', password = '123') => actionPromise('login', gql(`query ($login:String, $password:String){ login(login:$login, password:$password)}`, { 'login': login, 'password': password })); const actionFullLogin = (login = 'tst', password = '123') => async dispatch => { let token = await dispatch(actionLogin(login, password)); console.log(token); if (token) { dispatch(actionAuthLogin(token)); } }; // Регистрация const actionRegister = (login = 'tst', password = '123') => actionPromise('login', gql(`mutation reg($login:String, $password:String) { UserUpsert(user:{login:$login, password:$password, nick:$login}){ _id login } }`, {'login': login, 'password': password})); const actionFullRegister = (login = 'tst', password = '123') => async dispatch => { console.log(login, password); await dispatch(actionRegister(login, password)); await dispatch(actionFullLogin(login, password)); }; // Корневые категории // Товары категории const actionCatById = (_id) => actionPromise('catById', gql(`query ($q: String){ CategoryFindOne(query: $q){ _id name goods { _id name price images { url } } subCategories { _id name } } }`, {q: JSON.stringify([{_id}])})); const actionGoodById = (_id) => actionPromise('goodById', gql(`query ($good:String) { GoodFindOne(query:$good) { _id name price images { url } } }`, {good: JSON.stringify([{_id}])})); const store = createStore(combineReducers( { promise: promiseReducer, auth: authReducer, cart: cartReducer }), applyMiddleware(thunk)); store.subscribe(() => console.log(store.getState())); store.dispatch(actionRootCats()); const Logo = () => logo ; const Header = () =>
; const CategoryListItem = ({_id, name}) =>
  • {name}
  • ; const CategoryList = ({cats}) => { return ( ); }; const CCategoryList = connect(state => ({cats: state.promise.rootCats?.payload || []}))(CategoryList); const PageGood = ({good: {name, price, images}, match: {params: {_id}}, getData}) => { const isFirstImgExists = images && images[0] && images[0].url; useEffect(() => { getData(_id); }, []); return (

    {name}

    {isFirstImgExists && {name}/} {price} грн
    ); }; const CPageGood = connect(state => ({ good: state.promise.goodById?.payload ?? [], }), {getData: actionGoodById})(PageGood); const Aside = () => ; const GoodCard = ({good: {_id, name, price, images}, onAdd}) =>
  • {name}

    {images && images[0] && images[0].url && } {price} грн Подробнее
  • ; const Login = () =>

    Личный кабинет

    ; const CGoodCard = connect(null, { onAdd: actionCartAdd })(GoodCard); const Koshik = ({cart}) => { let goodsInCart = cart; let allGoodsInCart = 0; for (let key in goodsInCart) { allGoodsInCart += goodsInCart[key].count; } return (

    В корзине:{allGoodsInCart}

    ); }; const CKoshik = connect(({cart}) => ({cart}))(Koshik); const Category = ({cat: {name, goods = []} = {}}) => { return (

    {name}

    ); }; const CCategory = connect(state => ({cat: state.promise.catById?.payload || {}}))(Category); const Cart = ({cart, onCartChange, onCartRemove}) => { const error = typeof cart === 'undefined'; return (

    Корзина

    {error === false && (cart.map((good) => { return (
    {good.good.name}
    ); }) ) }
    {error === false && (cart.map((good) => { return { onCartChange(good.good, +e.target.value); } } key={good.good._id} />; }) )}
    {error === false && (cart.map((good) => { return ( ); }) ) }
    ); }; const CCart = connect( state => ({cart: Object.values(state.cart) || []}), { onCartChange: actionCartChange, onCartRemove: actionCartRemove })(Cart); const LoginForm = ({onCartLogin}) => { const [login, setLogin] = useState(''); const [password, setPassword] = useState(''); const isDisabled = login === '' || password === ''; console.log(login, password, isDisabled); const onChange = (event) => { event.target.name === 'login' ? setLogin(event.target.value) : setPassword(event.target.value); }; return (

    Вход в личный кабинет

    Вы еще не зарегистрированы?

    Зарегистрироваться
    ); }; const CLoginForm = connect( null, { onCartLogin: actionFullLogin })(LoginForm); const RegisterForm = ({onCartRegister}) => { const [login, setLogin] = useState(''); const [password, setPassword] = useState(''); const isDisabled = login === '' || password === ''; console.log(login, password, isDisabled); const onChange = (event) => { event.target.name === 'login' ? setLogin(event.target.value) : setPassword(event.target.value); }; return (

    Регистрация

    Войти в личный кабинет
    ); }; const CRegisterForm = connect( null, { onCartRegister: actionFullRegister })(RegisterForm); const PageMain = () =>

    Главная страничка

    ; const PageCategory = ({match: {params: {_id}}, getData}) => { useEffect(() => { getData(_id); }, [_id]); return (
    ); }; const CPageCategory = connect(null, {getData: actionCatById})(PageCategory); const Main = () =>
    ; const Content = ({children}) =>
    {children}
    ; const Footer = () => ; const history = createBrowserHistory(); //import {Provider, connect} from 'react-redux'; function App() { return (
    ); } export default App;