Browse Source

+ delete button in goodGorm

ilya_shyian 2 years ago
parent
commit
5f771925fe

+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
   "name": "diploma",
   "version": "0.1.0",
-  "proxy":"https://diploma-back-django.herokuapp.com/",
+  "proxy":"http://127.0.0.1:8000/api",
   "private": true,
   "dependencies": {
     "@dnd-kit/core": "^5.0.3",

+ 1 - 0
src/actions/actionCatAll.js

@@ -9,6 +9,7 @@ export const actionCatAll =
                 promiseName,
                 fetch(`${backendURL}/categories/?limit=${limit}&skip=${skip}${orderBy && `&orderBy=` + orderBy}`, {
                     method: 'GET',
+                    mode: 'cors',
                     headers: {
                         'Content-Type': 'application/json',
                         accept: 'application/json',

+ 23 - 0
src/actions/actionGoodDelete.js

@@ -0,0 +1,23 @@
+import { backendURL, getQuery, mock, query } from '../helpers';
+
+import { actionPromise } from '../reducers';
+
+export const actionGoodDelete = ({ _id, promiseName = 'goodDelete' } = {}) =>
+    actionPromise(
+        promiseName,
+        fetch(`${backendURL}/good/${_id}/delete/`, {
+            method: 'GET',
+            headers: {
+                'Content-Type': 'application/json',
+                Accept: 'application/json',
+
+                ...(localStorage.authToken ? { Authorization: 'Bearer ' + localStorage.authToken } : {}),
+            },
+        })
+            .then((res) => res.json())
+            .then((data) => {
+                if (data.errors) {
+                    throw new Error(JSON.stringify(data.errors));
+                } else return data.data;
+            })
+    );

+ 4 - 0
src/components/CartPage/CartItem.js

@@ -47,6 +47,10 @@ export const CartItem = ({ order, onDeleteClick }) => {
                     component="img"
                     src={images && images[0]?.url ? `${images ? images[0]?.url : ''}` : defaultGoodImage}
                     sx={{ width: 50 }}
+                    onError={({ currentTarget }) => {
+                        currentTarget.onerror = null; // prevents looping
+                        currentTarget.src = defaultGoodImage;
+                    }}
                 />
             </TableCell>
             <TableCell>

+ 7 - 1
src/components/GoodPage/index.js

@@ -16,7 +16,13 @@ export const GoodPage = () => {
                 <Grid item xs={12} md={4}>
                     <Carousel showIndicators={false} showStatus={false} showArrows={true}>
                         {(good.images || [{ url: defaultGoodImage }]).map((image) => (
-                            <img src={image?.url ? `${image?.url}` : defaultGoodImage} />
+                            <img
+                                src={image?.url ? `${image?.url}` : defaultGoodImage}
+                                onError={({ currentTarget }) => {
+                                    currentTarget.onerror = null; // prevents looping
+                                    currentTarget.src = defaultGoodImage;
+                                }}
+                            />
                         ))}
                     </Carousel>
                 </Grid>

+ 46 - 4
src/components/admin/AdminGoodPage/GoodForm.js

@@ -1,4 +1,4 @@
-import { connect } from 'react-redux';
+import { connect, useDispatch } from 'react-redux';
 import React, { useState, useEffect, useContext } from 'react';
 import { actionPromise, actionPromiseClear } from '../../../reducers';
 import Select from 'react-select';
@@ -24,6 +24,9 @@ import {
 import { useFormik } from 'formik';
 import * as Yup from 'yup';
 import { Error } from '../../common/Error';
+import { ConfirmModal } from '../../common/ConfirmModal';
+import { actionGoodDelete } from '../../../actions/actionGoodDelete';
+import { Navigate, useNavigate } from 'react-router-dom';
 
 const goodSchema = Yup.object().shape({
     name: Yup.string().required("Обов'язкове"),
@@ -47,13 +50,18 @@ export const GoodForm = ({
     onSaveClick,
     onSave,
     onClose,
+    onDelete,
     promiseStatus,
+    deletePromiseStatus,
     catList = [],
     good = {},
 } = {}) => {
     const [inputCategories, setInputCategories] = useState([]);
     const [inputImages, setInputImages] = useState([]);
+    const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
     const { setAlert } = useContext(UIContext);
+    const navigate = useNavigate();
+    const dispatch = useDispatch();
     const formik = useFormik({
         initialValues: {
             name: '',
@@ -97,6 +105,22 @@ export const GoodForm = ({
         }
     }, [promiseStatus]);
 
+    useEffect(() => {
+        if (deletePromiseStatus === 'FULFILLED') {
+            navigate('/admin/goods/');
+        }
+        if (deletePromiseStatus === 'REJECTED') {
+            setAlert({
+                show: true,
+                severity: 'error',
+                message: 'Помилка',
+            });
+        }
+        return () => {
+            dispatch(actionPromiseClear('goodDelete'));
+        };
+    }, [deletePromiseStatus]);
+
     useEffect(() => {
         setInputCategories(good?.categories || []);
         setInputImages(good?.images || []);
@@ -198,11 +222,27 @@ export const GoodForm = ({
                 />
             </Box>
 
-            <Box direction="row" sx={{ mt: 3 }} justifyContent="flex-end">
-                <Button variant="contained" disabled={!formik.isValid || formik.isSubmitting} type="submit" fullWidth>
+            <Stack direction="row" sx={{ mt: 3 }} justifyContent="flex-end" spacing={1}>
+                {!!good._id && (
+                    <Button variant="contained" onClick={() => setIsDeleteModalOpen(true)} color="error">
+                        Видалити
+                    </Button>
+                )}
+                <Button variant="contained" disabled={!formik.isValid || formik.isSubmitting} type="submit">
                     Зберегти
                 </Button>
-            </Box>
+            </Stack>
+            {!!good._id && (
+                <ConfirmModal
+                    open={isDeleteModalOpen}
+                    text="Видалити товар?"
+                    onClose={() => setIsDeleteModalOpen(false)}
+                    onNO={() => setIsDeleteModalOpen(false)}
+                    onYES={() => {
+                        onDelete(good._id);
+                    }}
+                />
+            )}
         </Box>
     );
 };
@@ -211,11 +251,13 @@ export const CGoodForm = connect(
     (state) => ({
         catList: state.promise.catAll?.payload || [],
         promiseStatus: state.promise.goodUpsert?.status || null,
+        deletePromiseStatus: state.promise.goodDelete?.status || null,
         good: state.promise?.adminGoodById?.payload || {},
         serverErrors: state.promise?.goodUpsert?.error || [],
     }),
     {
         onSave: (good) => actionGoodUpdate(good),
         onClose: () => actionPromiseClear('goodUpsert'),
+        onDelete: (_id) => actionGoodDelete({ _id }),
     }
 )(GoodForm);

+ 4 - 0
src/components/admin/AdminGoodsPage/AdminGoodItem.js

@@ -15,6 +15,10 @@ const AdminGoodItem = ({ good }) => (
                 <Box
                     component="img"
                     src={good.images?.length ? `${good.images ? good.images[0]?.url : ''}` : defaultGoodImage}
+                    onError={({ currentTarget }) => {
+                        currentTarget.onerror = null; // prevents looping
+                        currentTarget.src = defaultGoodImage;
+                    }}
                 />
             }
         </TableCell>

+ 22 - 0
src/components/common/ConfirmModal/index.js

@@ -0,0 +1,22 @@
+import { Box, Button, Stack, Typography } from '@mui/material';
+import { Modal } from '../Modal';
+
+export const ConfirmModal = ({ open, text, onYES, onNO, onClose }) => {
+    return (
+        <Box className="ConfirmModal">
+            <Modal open={open} onClose={() => onClose && onClose()} maxWidth={350}>
+                <Typography textAlign="center" variant="h5">
+                    {text}
+                </Typography>
+                <Stack direction="row" justifyContent="space-between">
+                    <Button variant="contained" onClick={() => onNO && onNO()} color="error">
+                        Ні
+                    </Button>
+                    <Button variant="contained" onClick={() => onYES && onYES()}>
+                        Так
+                    </Button>
+                </Stack>
+            </Modal>
+        </Box>
+    );
+};

+ 4 - 0
src/components/common/DrawerCart/DrawerCartItem.js

@@ -36,6 +36,10 @@ const DrawerCartItem = ({ order, onDeleteClick }) => {
                 component="img"
                 sx={{ width: 90 }}
                 src={images && images[0]?.url ? `${images ? images[0]?.url : ''}` : defaultGoodImage}
+                onError={({ currentTarget }) => {
+                    currentTarget.onerror = null; // prevents looping
+                    currentTarget.src = defaultGoodImage;
+                }}
             />
             <Box sx={{ display: 'flex', width: '100%' }}>
                 <CardContent className="content">

+ 15 - 0
src/components/common/Modal/index.js

@@ -0,0 +1,15 @@
+import { Box } from '@mui/system';
+import ReactDOM from 'react-dom';
+
+export const Modal = ({ children, open, onClose, maxWidth = 700 }) => {
+    return open
+        ? ReactDOM.createPortal(
+              <Box className="Modal" onClick={() => onClose && onClose()}>
+                  <Box className="modalContent" onClick={(e) => e.stopPropagation()} style={{ maxWidth }}>
+                      {children}
+                  </Box>
+              </Box>,
+              document.body
+          )
+        : null;
+};

+ 8 - 1
src/components/common/SearchBar/SearchGoodResultItem.js

@@ -16,7 +16,14 @@ const SearchGoodResultItem = ({ good, onClick, link = '' } = {}) => {
             spacing={1}
         >
             <Grid item xs={3}>
-                <Box component="img" src={images ? `${images[0]?.url}` : defaultGoodImage} />
+                <Box
+                    component="img"
+                    src={images ? `${images[0]?.url}` : defaultGoodImage}
+                    onError={({ currentTarget }) => {
+                        currentTarget.onerror = null; // prevents looping
+                        currentTarget.src = defaultGoodImage;
+                    }}
+                />
             </Grid>
             <Grid item xs={6}>
                 <Box sx={{ p: 1 }}>

BIN
src/helpers/.index.js.swp


+ 1 - 1
src/helpers/index.js

@@ -3,5 +3,5 @@ import { mock } from './mock';
 import { delay } from './delay';
 import { statusNumber, statusOptions } from './orderStatus';
 
-export const backendURL = 'http://188.72.209.29/api';
+export const backendURL = '';
 export { jwtDecode, mock, delay, statusNumber, statusOptions };

+ 36 - 0
src/index.scss

@@ -8,6 +8,42 @@
   text-decoration: none;
 }
 
+
+.Modal{
+  position: fixed;
+  z-index: 1;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+  background-color: rgba(0,0,0,0.1);
+
+
+  & .modalContent {
+    background-color: #fefefe;
+    margin: 15% auto;
+    padding: 20px;
+    border-radius: 7px;
+    width:50%;
+
+  }
+
+
+}
+
+
+.ConfirmModal{
+
+  & .modalContent{
+    max-width: 400px!important;
+  }
+}
+
+
+
+
+
 .AuthPage{
 
   display: flex;