Parcourir la source

rtk_cart start

Gennadysht il y a 2 ans
Parent
commit
d88af85fc2

+ 7 - 3
src/App.js

@@ -3,8 +3,8 @@ import { configureStore } from '@reduxjs/toolkit';
 import { Router, Route, Switch } from 'react-router-dom';
 import { createBrowserHistory } from "history";
 import { Provider } from 'react-redux';
-import { authReducer, promiseReducer, actionAuthLogin, frontEndReducer, actionRootCats, goodsReducer } from './reducers';
-import { CGood, CGoodsList, CLoginForm, CMainAppBar, COrder, COrdersList, exampleOrder, goodsExample, GoodsList, Order } from "./Components";
+import { authReducer, promiseReducer, actionAuthLogin, frontEndReducer, actionRootCats, goodsReducer, cartReducer, actionRestoreCart } from './reducers';
+import { CGood, CGoodsList, CLoginForm, CMainAppBar, COrder, COrdersList, exampleOrder, goodsExample, GoodsList, MyLink, Order } from "./Components";
 import { CLogout } from './Components';
 import { CSidebar } from './Components/Sidebar';
 import { CRootCats } from './Components';
@@ -13,6 +13,7 @@ import './App.css';
 import { CCategory } from './Components/Category';
 import { categoryReducer } from './reducers/categoryReducer';
 import { ordersReducer } from './reducers/ordersReducer';
+import { CCart } from './Components/Cart';
 
 export const history = createBrowserHistory();
 //export const store = createStore(combineReducers({ promise: promiseReducer, auth: authReducer, frontend: frontEndReducer }), applyMiddleware(thunk));
@@ -23,7 +24,8 @@ export const store = configureStore({
     frontend: frontEndReducer,
     category: categoryReducer,
     orders: ordersReducer,
-    goods: goodsReducer
+    goods: goodsReducer,
+    cart: cartReducer
   }
 });
 store.subscribe(() => console.log(store.getState()))
@@ -31,6 +33,7 @@ store.subscribe(() => console.log(store.getState()))
 //console.log(useParams)
 store.dispatch(actionAuthLogin(localStorage.authToken));
 store.dispatch(actionRootCats());
+store.dispatch(actionRestoreCart());
 console.log('TTTTT' + performance.now())
 
 
@@ -62,6 +65,7 @@ function App() {
               <Route path="/good/:_id" component={CGood} />
               <Route path="/category/:_id" component={CCategory} />
               <Route path="/order/:_id" component={COrder} />
+              <Route path="/cart" component={CCart} />
               <Route path="/login" component={CLoginForm} />
               <Route path="/logout" component={CLogout} />
               <Route path="*" component={NotFound} />

+ 44 - 0
src/Components/Cart.js

@@ -0,0 +1,44 @@
+import React, { useEffect } from 'react';
+import { Typography } from "@mui/material"
+import { Box, Container } from "@mui/system"
+import { connect } from "react-redux"
+import { actionLoadCart, getCart } from "../reducers"
+import { CartGoodsList } from "./CartGoodsList"
+import { findObjectIndexById } from '../utills';
+
+const mapCountToGood = (goodData, goodsCounts) => {
+    let count = 0;
+    let goodIdx = findObjectIndexById(goodsCounts, goodData._id);
+    if (goodIdx >= 0)
+        count = goodsCounts[goodIdx].count;
+    return count;
+}
+
+const Cart = ({ goods, goodsData, uniqueId, loadData }) => {
+    goodsData = goodsData?.map(gd => ({ ...gd, count: mapCountToGood(gd, goods) })) ?? [];
+
+    useEffect(() => {
+        loadData();
+    }, [uniqueId, loadData]);
+    return (
+        <>
+            <Container>
+                <Box>
+                    <Typography paragraph gutterBottom component={'h3'} variant={'h3'}>
+                        Cart
+                    </Typography>
+                    <CartGoodsList goods={goodsData ?? []} />
+                </Box>
+            </Container>
+        </>
+    )
+}
+const CCart = connect(state => ({
+    goods: state.cart.goods,
+    goodsData: state.goods?.goods?.payload,
+    uniqueId: state.cart.uniqueId,
+    //cart: getCart(state) 
+}),
+    { loadData: actionLoadCart })(Cart);
+
+export { CCart };

+ 54 - 0
src/Components/CartGood.js

@@ -0,0 +1,54 @@
+import { Typography } from "@mui/material";
+import { getFullImageUrl } from "../utills";
+import { AvatarImage } from "./AvatarAnimated";
+import { StyledTableCell, StyledTableRow } from "./StyledTableElements";
+import "./cartGood.css"
+import { MyLink } from "./MyLink";
+
+const CartGood = ({ good, goodNum }) => {
+    return (
+        <>
+            <StyledTableRow>
+                <StyledTableCell item align="right" xs={1}>
+                    <Typography>
+                        {goodNum + 1}.
+                    </Typography>
+                </StyledTableCell>
+                <StyledTableCell item xs={2}>
+                    {good.images?.length > 0 ?
+                        <AvatarImage sx={{ width: 70, height: 70 }} variant='rounded' src={getFullImageUrl(good.images[0])} /> :
+                        null}
+                </StyledTableCell>
+                <StyledTableCell item xs={3}>
+                    {good?.good?._id ?
+                        <MyLink to={`/good/${good?.good._id}`}>
+                            <Typography >
+                                {good.name}
+                            </Typography>
+                        </MyLink>
+                        :
+                        <Typography >
+                            {good.name}
+                        </Typography>
+                    }
+                </StyledTableCell>
+                <StyledTableCell item align="right" xs={2}>
+                    <Typography>
+                        {good.price}
+                    </Typography>
+                </StyledTableCell>
+                <StyledTableCell item align="right" xs={2}>
+                    <Typography>
+                        {good.count}
+                    </Typography>
+                </StyledTableCell>
+                <StyledTableCell item align="right" xs={2}>
+                    <Typography>
+                        {good.price * good.count}
+                    </Typography>
+                </StyledTableCell>
+            </StyledTableRow>
+        </>
+    )
+}
+export { CartGood };

+ 60 - 0
src/Components/CartGoodsList.js

@@ -0,0 +1,60 @@
+import React from 'react';
+import { Paper } from '@mui/material';
+import { CartGood } from './CartGood';
+import { Table, TableBody, TableContainer, TableHead, TableRow, TableCell } from "@mui/material";
+import { StyledTableCell } from './StyledTableElements';
+
+const CartGoodsList = ({ goods = [], tax_rate = 0 }) => {
+    function ccyFormat(num) {
+        return `${num.toFixed(2)}`;
+    }
+    function subtotal(items) {
+        return items.map(({ price, count }) => price * count).reduce((sum, i) => sum + i, 0);
+    }
+    const invoiceSubtotal = subtotal(goods);
+    const invoiceTaxes = tax_rate * invoiceSubtotal;
+    const invoiceTotal = invoiceTaxes + invoiceSubtotal;
+
+    return (
+        <>
+            <TableContainer component={Paper} sx={{ minWidth: 700, maxWidth: 1200 }} >
+                <Table aria-label="customized table">
+                    <TableHead>
+                        <TableRow>
+                            <StyledTableCell align="right">#</StyledTableCell>
+                            <StyledTableCell></StyledTableCell>
+                            <StyledTableCell>Name</StyledTableCell>
+                            <StyledTableCell align="right">Price ($)</StyledTableCell>
+                            <StyledTableCell align="right">Count</StyledTableCell>
+                            <StyledTableCell align="right">Total</StyledTableCell>
+                        </TableRow>
+                    </TableHead>
+                    <TableBody>
+                        {
+                            goods.map((good, index) => {
+                                return (
+                                    <CartGood key={good._id} good={good} goodNum={index} maxWidth='xs' />
+                                )
+                            })
+                        }
+                        <TableRow>
+                            <TableCell rowSpan={3} colSpan={3} />
+                            <TableCell colSpan={2}>Subtotal</TableCell>
+                            <TableCell align="right">{ccyFormat(invoiceSubtotal)}</TableCell>
+                        </TableRow>
+                        <TableRow>
+                            <TableCell>Tax</TableCell>
+                            <TableCell align="right">{`${(tax_rate * 100).toFixed(0)} %`}</TableCell>
+                            <TableCell align="right">{ccyFormat(invoiceTaxes)}</TableCell>
+                        </TableRow>
+                        <TableRow>
+                            <TableCell colSpan={2}>Total</TableCell>
+                            <TableCell align="right">{ccyFormat(invoiceTotal)}</TableCell>
+                        </TableRow>
+                    </TableBody>
+                </Table>
+            </TableContainer>
+        </>
+    )
+}
+export { CartGoodsList };

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 140
src/Components/Good copy.js


+ 7 - 7
src/Components/Good.js

@@ -5,7 +5,7 @@ import { Container, Typography, Grid, CardActionArea, Card, CardContent, CardMed
 import { getFullImageUrl } from "./../utills";
 import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
 import { AvatarAnimated } from './AvatarAnimated';
-import { actionGoodFindOne } from '../reducers';
+import { actionAddGoodToCart, actionGoodFindOne } from '../reducers';
 import { connect } from 'react-redux';
 import { getCurrentGood } from '../reducers/goodsReducer';
 import { useParams } from 'react-router-dom';
@@ -37,7 +37,7 @@ export const AvatarGroupOriented = styled((props) => {
     },
     ".MuiAvatar-root": { /*width: 20, height: 20,*/ marginLeft: 1 }
 }));
-const Good = ({ good = {}, maxWidth = 'md', showAddToCard = true, loadData = undefined }) => {
+const Good = ({ good = {}, maxWidth = 'md', showAddToCard = true, loadData = undefined, addToCart = undefined }) => {
     const params = useParams();
     const currentGoodId = params._id;
     useEffect(() => {
@@ -99,7 +99,9 @@ const Good = ({ good = {}, maxWidth = 'md', showAddToCard = true, loadData = und
                     </ExpandMore>
                     {
                         showAddToCard && (
-                            <Button size='small' color='primary'>
+                            <Button size='small' color='primary'
+                                onClick={() => alert("Clicked")/*addToCart(good)*/}
+                            >
                                 Add to cart
                             </Button>
                         )
@@ -118,9 +120,7 @@ const Good = ({ good = {}, maxWidth = 'md', showAddToCard = true, loadData = und
     )
 }
 
-const CGoodItem = connect(state => ({ /*good: getCurrentGood(state)*/ }),
-    {})(GoodItem);
 const CGood = connect(state => ({ good: getCurrentGood(state) }),
-    { loadData: actionGoodFindOne })(Good);
+    { loadData: actionGoodFindOne, addToCart: actionAddGoodToCart })(Good);
 
-export { CGoodItem, CGood };
+export { CGood };

+ 10 - 2
src/Components/GoodItem.js

@@ -6,8 +6,10 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
 import { AvatarAnimated } from './AvatarAnimated';
 import { MyLink } from './MyLink';
 import { AvatarGroupOriented, ExpandMore } from './Good';
+import { connect } from 'react-redux';
+import { actionAddGoodToCart } from '../reducers';
 
-export const GoodItem = ({ good = {}, maxWidth = 'md', showAddToCard = true }) => {
+export const GoodItem = ({ good = {}, maxWidth = 'md', showAddToCard = true, addToCart = undefined }) => {
     let [currentImageIndex, setCurrentImageIndex] = useState(0);
     let [expanded, setExpanded] = useState(false);
     const handleExpandClick = () => setExpanded(!expanded);
@@ -61,7 +63,9 @@ export const GoodItem = ({ good = {}, maxWidth = 'md', showAddToCard = true }) =
                         <ExpandMoreIcon />
                     </ExpandMore>
                     {showAddToCard && (
-                        <Button size='small' color='primary'>
+                        <Button size='small' color='primary'
+                            onClick={() => addToCart(good)}
+                        >
                             Add to cart
                         </Button>
                     )}
@@ -78,3 +82,7 @@ export const GoodItem = ({ good = {}, maxWidth = 'md', showAddToCard = true }) =
         </Container>
     );
 };
+
+const CGoodItem = connect(state => ({ /*good: getCurrentGood(state)*/ }),
+    { addToCart: actionAddGoodToCart })(GoodItem);
+export { CGoodItem };

+ 1 - 1
src/Components/GoodsList.js

@@ -1,6 +1,6 @@
 import React, { useEffect } from 'react';
 import { Container, Box } from '@mui/material';
-import { CGoodItem } from './Good';
+import { CGoodItem } from './GoodItem';
 import { connect } from 'react-redux';
 import { actionGoodFind, actionGoodsCount } from '../reducers';
 import { CGoodsSearchInput } from './SearchInput';

+ 2 - 2
src/Components/MainAppBar.js

@@ -44,11 +44,11 @@ const MainAppBar = ({ token, openSidebar }) => {
                             <MyLink to="/orders"><Button color="inherit">Orders</Button></MyLink>
                         </>
                     }
-                    <Button color="inherit">Cart</Button>
+                    <MyLink to="/cart"><Button color="inherit">Cart</Button></MyLink>
                 </Toolbar>
             </AppBar>
         </Box>
     );
 }
 
-export const CMainAppBar = connect(state => ({ token: state.auth?.token, sidebarOpened: state.frontend.sidebar.opened }), { openSidebar: actionSetSidebar }) (MainAppBar);
+export const CMainAppBar = connect(state => ({ token: state.auth?.token, sidebarOpened: state.frontend.sidebar.opened }), { openSidebar: actionSetSidebar })(MainAppBar);

+ 4 - 0
src/Components/cartGood.css

@@ -0,0 +1,4 @@
+.MuiAvatar-img{
+    object-fit: contain;
+  }
+  

+ 3 - 2
src/Components/index.js

@@ -1,7 +1,8 @@
 export { CLoginForm } from './LoginForm';
-export { CGood, CGoodItem } from './Good';
+export { CGoodItem } from './GoodItem';
+export { CGood } from './Good';
 export { CGoodsList } from './GoodsList';
-export { OrderGood} from './OrderGood';
+export { OrderGood } from './OrderGood';
 export { OrderGoodsList, exampleOrderGoodsList } from './OrderGoodsList'
 export { COrder } from './Order';
 export { COrdersList } from './OrderList';

+ 2 - 3
src/gql/gqlOrders.js

@@ -1,6 +1,5 @@
 import { gql } from "../utills/gql";
-import { actionPromise } from "../reducers";
-import { actionCartClear } from '../reducers';
+import { actionClearCart, actionPromise } from "../reducers";
 import { createFullQuery } from "./gqlUtils";
 
 const orderUpsert = (order, id = null) => {
@@ -30,7 +29,7 @@ const orderFullUpsert = (then) => {
             if (res && res.errors && res.errors.length > 0) {
                 throw res.errors[0];
             }
-            dispatch(actionCartClear());
+            dispatch(actionClearCart());
         }
         if (then)
             then();

Fichier diff supprimé car celui-ci est trop grand
+ 52 - 0
src/reducers/_cartReducer.js


Fichier diff supprimé car celui-ci est trop grand
+ 114 - 43
src/reducers/cartReducer.js


+ 1 - 1
src/reducers/index.js

@@ -1,6 +1,6 @@
 export { promiseReducer, actionPromise, actionFulfilled, actionPending, actionRejected } from "./promiseReducer";
 export { authReducer, actionAuthLogin, actionAuthLogout, actionAuthLoginThunk } from "./authReducer";
-export { cartReducer, actionCartAdd, actionCartClear, actionCartDel, actionCartSet, actionCartShow, actionCartSub } from "./cartReducer";
+export {cartReducer, actionAddGoodToCart, actionDeleteGoodFromCart, actionRestoreCart, actionClearCart, actionLoadCart, getCart, } from "./cartReducer";
 export { localStoredReducer, } from "./localStoredReducer";
 export { frontEndReducer, } from "./frontEndReducer";
 export { actionRootCats, actionCategoryFindOne } from './categoryReducer';

+ 1 - 1
src/utills/index.js

@@ -1,2 +1,2 @@
-export {getFullImageUrl} from './utils';
+export {getFullImageUrl, findObjectIndexById} from './utils';
 export {gql, jwtDecode} from './gql';

+ 6 - 3
src/utills/utils.js

@@ -1,6 +1,9 @@
+const getFullImageUrl = (image) =>
+    `http://shop-roles.node.ed.asmer.org.ua/${image?.url}`;
 
+const findObjectIndexById = (objs, goodId) => {
+    return (objs.findIndex(g => g._id === goodId))
+}
 
+export { getFullImageUrl, findObjectIndexById };
 
-const getFullImageUrl = (image) =>
-    `http://shop-roles.node.ed.asmer.org.ua/${image?.url}`;
-export { getFullImageUrl };