CartPage.jsx 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import Breadcrumb from "../components/Breadcrumbs";
  2. import {connect} from "react-redux";
  3. import {actionCardChange, actionCardClear, actionCardRemove} from "../reducers/CartReducer";
  4. import {ActionFullOrder} from "../actions/ActionOrder";
  5. import {Box, Button, Container, Divider, Grid, Typography, useMediaQuery} from "@mui/material";
  6. import {ItemHeaderLine, LinkProductItem, RemoveFromList, TableLine} from "../components/TableLine";
  7. import {NotFoundBlock} from "../components/NotFoundBlock";
  8. import imgUrl from "../img/not-found/3.png";
  9. import AddShoppingCartIcon from "@mui/icons-material/AddShoppingCart";
  10. import {SetCount} from "../components/SetCount";
  11. import {useEffect, useState} from "react";
  12. import {actionClearPromise} from "../reducers/PromiseReducer";
  13. import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
  14. const CartGoodLine = ({item, onCartRemove, onCardChange}) => {
  15. let [count, setCount] = useState(item?.count)
  16. useEffect(() => {
  17. onCardChange(item?.good, count)
  18. }, [count])
  19. return(
  20. <Grid container alignItems='center' marginBottom='20px'>
  21. <Grid item xs={6}>
  22. <LinkProductItem item={[item?.good?._id, item?.good?.name, item?.good?.images]} children={<Typography>${item?.good?.price}</Typography>}/>
  23. </Grid>
  24. <Grid item xs={3} display='flex' justifyContent="center">
  25. <SetCount height={40} width={40} defaultValue={item?.count} onCount={value => setCount(value)}/>
  26. </Grid>
  27. <Grid item xs={2}>
  28. <ItemHeaderLine align={'center'} text={(`$${parseFloat(item?.good?.price * count).toFixed(2)}`) || 'NaN'}/>
  29. </Grid>
  30. <Grid item xs={1}>
  31. <RemoveFromList good={item?.good} onRemove={onCartRemove}/>
  32. </Grid>
  33. </Grid>
  34. )
  35. }
  36. const TotalPriceLine = ({title, subtitle, sizeSubtitle='body2'}) => {
  37. return (
  38. <Grid container display='flex' flexDirection='row' justifyContent='space-between' alignItems='center' padding='20px'>
  39. <Grid item xs={6}>
  40. <Typography
  41. variant='body2'
  42. color='#616161'
  43. textAlign='left'
  44. >
  45. {title}
  46. </Typography>
  47. </Grid>
  48. <Grid item xs={6}>
  49. <Typography
  50. variant={sizeSubtitle}
  51. color='#000'
  52. textAlign='right'
  53. >
  54. {subtitle}
  55. </Typography>
  56. </Grid>
  57. </Grid>
  58. )
  59. }
  60. const BlockTotal = ({auth ,cart, rows, onOrderUpsert, onCartClear}) => {
  61. return (
  62. <>
  63. <Typography
  64. padding='20px'
  65. variant='h4'
  66. fontFamily='sarif'
  67. letterSpacing='2px'
  68. textAlign='center'
  69. >
  70. TOTAL
  71. </Typography>
  72. <Divider/>
  73. <TotalPriceLine title={`${rows.length || 1} goods for the amount`} subtitle={`$${rows.reduce((a, i) => a + (i.good.price * i.count), 0)}`}/>
  74. <TotalPriceLine title={'Cost of delivery'} subtitle={'according to the carrier\'s tariffs'}/>
  75. <Divider/>
  76. <TotalPriceLine title={'To pay'} subtitle={`$${rows.reduce((a, i) => a + (i.good.price * i.count), 0)}`} sizeSubtitle={'h6'}/>
  77. <Divider sx={{marginBottom: '20px'}}/>
  78. <Box display='flex' justifyContent='center' flexDirection='column' alignItems='center'>
  79. <Button sx={{borderRadius: '0', width:'80%', padding: '10px 20px', marginBottom: '20px'}}
  80. color='success'
  81. variant="outlined"
  82. onClick={() => {onOrderUpsert(cart); onCartClear()}}
  83. disabled={Object.entries(auth).length === 0}
  84. >
  85. {Object.entries(auth).length === 0 ? 'you need to log in' : 'confirm the order'}
  86. </Button>
  87. <Button sx={{borderRadius: '0', width:'80%', padding: '10px 20px'}}
  88. color='warning'
  89. variant="outlined"
  90. onClick={() => onCartClear()}
  91. >
  92. cart clear
  93. </Button>
  94. </Box>
  95. </>
  96. )
  97. }
  98. const CBlockTotal = connect(state=>({auth: state.auth}))(BlockTotal)
  99. const CartPage = ({order, cart, onCardChange, onCartClear, onCartRemove, onOrderUpsert, actionClearOrder}) => {
  100. const matches = useMediaQuery('(max-width:768px)')
  101. let rows = []
  102. for (const key of Object.values(cart)) {
  103. rows.push(key)
  104. }
  105. useEffect(() => {
  106. if (order && Object.entries(order).length > 0) {
  107. actionClearOrder('order')
  108. }
  109. },[cart])
  110. return (
  111. <>
  112. <Breadcrumb links={['cart']}/>
  113. {Object.values(cart).length > 0 || order ?
  114. <main style={{backgroundColor: "#f3f3f3", padding: matches ? "20px 0" : "50px 0", minHeight:'300px'}}>
  115. <Container maxWidth="lg">
  116. {order && Object.entries(order).length > 0 ?
  117. <Box display='flex' height='300px' flexDirection='column' alignItems='center' justifyContent='space-around'>
  118. {order.error ?
  119. <Typography variant='h5' textAlign='center'>Error, try again</Typography> :
  120. <>
  121. <Typography
  122. variant='h5'
  123. textAlign='center'
  124. >
  125. Order successfully completed
  126. </Typography>
  127. <CheckCircleOutlineIcon/>
  128. <Typography
  129. variant='h4'
  130. textAlign='center'
  131. fontFamily='sarif'
  132. letterSpacing='2px'
  133. sx={{textTransform: 'uppercase'}}
  134. >
  135. Thanks for your order!
  136. </Typography>
  137. <Typography
  138. variant='body1'
  139. textAlign='center'
  140. color="#616161"
  141. >
  142. Attention! Shipping is paid separately upon receipt of the goods.
  143. </Typography>
  144. <Typography
  145. variant='body1'
  146. textAlign='center'
  147. color="#616161"
  148. >
  149. Your order number: {order.payload?._id || 1}
  150. </Typography>
  151. <Typography
  152. variant='body1'
  153. textAlign='center'
  154. color="#616161"
  155. >
  156. For the amount: ${+order.payload?.total || 0}
  157. </Typography>
  158. </>
  159. }
  160. </Box>:
  161. <Grid container justifyContent='space-between'>
  162. <Grid item xs={8.5}>
  163. <TableLine columnName={['PRODUCT', 'QUANTITY', 'REMOVE', 'SUBTOTAL']}
  164. customSizeCol={[6, 3, 2, 1]}/>
  165. <Divider sx={{marginBottom: '20px'}}/>
  166. {rows.map(item => <CartGoodLine item={item} onCartRemove={onCartRemove}
  167. onCardChange={onCardChange}/>)}
  168. <Divider/>
  169. </Grid>
  170. <Grid item xs={3} sx={{backgroundColor: '#fff'}} height='100%' paddingBottom='20px'>
  171. <CBlockTotal cart={cart} rows={rows} onCartClear={onCartClear}
  172. onOrderUpsert={onOrderUpsert}/>
  173. </Grid>
  174. </Grid>
  175. }
  176. </Container>
  177. </main>:
  178. <NotFoundBlock img={imgUrl} headerText={'YOUR CART IS CURRENTLY EMPTY'} text={<Box display='flex' alignItems='center'><Typography component='span'>Click the</Typography><AddShoppingCartIcon sx={{margin: '0 10px'}}/><Typography component='span'>icons to add products</Typography></Box>}/>
  179. }
  180. </>
  181. )
  182. }
  183. const CCartPage = connect(state=>({cart: state.cart, order: state.promise?.order}), {onCardChange: actionCardChange, onCartClear: actionCardClear, onCartRemove: actionCardRemove, onOrderUpsert: ActionFullOrder, actionClearOrder: actionClearPromise})(CartPage)
  184. export default CCartPage