Jelajahi Sumber

+ Change order form, convert all actions to GraphQL

ilya_shyian 1 tahun lalu
induk
melakukan
d916cf4289

+ 6 - 6
src/actions/actionCatAll.js

@@ -1,8 +1,8 @@
-import { actionPromise } from '../reducers';
-import { backendURL, gql } from '../helpers';
+import { actionPromise } from "../reducers";
+import { backendURL, gql } from "../helpers";
 
 export const actionCatAll =
-    ({ limit = 20, skip = 0, promiseName = 'catAll', orderBy = '' } = {}) =>
+    ({ limit = 20, skip = 0, promiseName = "catAll", orderBy = "_id" } = {}) =>
     async (dispatch, getState) => {
         dispatch(
             actionPromise(
@@ -23,9 +23,9 @@ export const actionCatAll =
                         query: JSON.stringify([
                             {},
                             {
-                                // sort: { name: 1 },
-                                limit: [!!limit ? limit : 100],
-                                skip: [skip],
+                                limit: !!limit ? limit : 100,
+                                skip: skip,
+                                orderBy,
                             },
                         ]),
                     }

+ 5 - 5
src/actions/actionCatById.js

@@ -1,12 +1,12 @@
-import { backendURL, mock, query, gql } from '../helpers';
+import { backendURL, mock, query, gql } from "../helpers";
 
-import { actionPromise } from '../reducers';
+import { actionPromise } from "../reducers";
 
-export const actionCatById = ({ _id, promiseName = 'catById', orderBy = '', limit = 20, skip = 0 }) =>
+export const actionCatById = ({ _id, promiseName = "catById", orderBy = "", limit = 20, skip = 0 }) =>
     actionPromise(
         promiseName,
         gql(
-            `query CatAll($q:String){
+            `query CatById($q:String){
                 CategoryFindOne(query: $q){
                     _id name
                     parent{
@@ -20,6 +20,6 @@ export const actionCatById = ({ _id, promiseName = 'catById', orderBy = '', limi
                     }
                 }
             }`,
-            { q: JSON.stringify([{ _id }]) }
+            { q: JSON.stringify([{ _id }, { limit: !!limit ? limit : 5, skip, goods_order: orderBy }]) }
         )
     );

+ 20 - 18
src/actions/actionCategoryDelete.js

@@ -1,23 +1,25 @@
-import { backendURL, getQuery, mock, query } from '../helpers';
+import { backendURL, getQuery, gql, mock, query } from "../helpers";
 
-import { actionPromise } from '../reducers';
+import { actionPromise } from "../reducers";
 
-export const actionCategoryDelete = ({ _id, promiseName = 'categoryDelete' } = {}) =>
+export const actionCategoryDelete = ({ category, promiseName = "categoryDelete" } = {}) =>
     actionPromise(
         promiseName,
-        fetch(`${backendURL}/category/${_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;
-            })
+        gql(
+            `mutation CatDelete($category:CategoryInput!){
+                CategoryDelete(category:$category){
+                    _id name
+                    parent{
+                        _id, name
+                    }
+                    subcategories{
+                        _id name
+                    }
+                    goods{
+                        _id name price amount
+                    }
+                }
+            }`,
+            { category }
+        )
     );

+ 20 - 23
src/actions/actionCategoryUpsert.js

@@ -1,30 +1,27 @@
-import { backendURL } from '../helpers';
-import { actionPromise } from '../reducers';
+import { backendURL, gql } from "../helpers";
+import { actionPromise } from "../reducers";
 
 export const actionCategoryUpsert = (category) => async (dispatch) => {
-    const formData = new FormData();
-    category._id && formData.append('_id', category._id);
-    category.name && formData.append('name', category.name);
-    category.goods && formData.append('goods', JSON.stringify(category.goods));
-    category.parent !== undefined && formData.append('parent', JSON.stringify(category.parent));
-    category.subcategories && formData.append('subcategories', JSON.stringify(category.subcategories));
     dispatch(
         actionPromise(
-            'categoryUpsert',
-            fetch(`${backendURL}/category/`, {
-                method: 'POST',
-                headers: {
-                    accept: 'application/json',
-                    ...(localStorage.authToken ? { Authorization: 'Bearer ' + localStorage.authToken } : {}),
-                },
-                body: formData,
-            })
-                .then((res) => res.json())
-                .then((data) => {
-                    if (data.errors) {
-                        throw new Error(JSON.stringify(data.errors));
-                    } else return data.data;
-                })
+            "categoryUpsert",
+            gql(
+                `mutation CatUpsert($category:CategoryInput!){
+                    CategoryUpsert(category:$category){
+                        _id name
+                        parent{
+                            _id, name
+                        }
+                        subcategories{
+                            _id name
+                        }
+                        goods{
+                            _id name price amount
+                        }
+                    }
+                }`,
+                { category }
+            )
         )
     );
 };

+ 20 - 18
src/actions/actionCatsFind.js

@@ -1,31 +1,33 @@
-import { backendURL } from '../helpers';
-import { actionPromise } from '../reducers';
+import { backendURL, gql } from "../helpers";
+import { actionPromise } from "../reducers";
 
 export const actionCatsFind =
-    ({ text = '', limit = 7, skip = 0, promiseName = 'catsFind', orderBy = '' }) =>
+    ({ text = "", limit = 7, skip = 0, promiseName = "catsFind", orderBy = "_id" }) =>
     async (dispatch, getState) => {
         dispatch(
             actionPromise(
                 promiseName,
-                fetch(
-                    `${backendURL}/categories/?limit=${limit}&skip=${skip}&text=${text}${
-                        orderBy && `&orderBy=` + orderBy
+                gql(
+                    `query CatsFind($query:String){
+                        CategoryFind(query: $query){
+                            _id name 
+                            parent{
+                                _id name
+                            }
+
+                        }
                     }`,
                     {
-                        method: 'GET',
-                        headers: {
-                            accept: 'application/json',
-                            'Content-Type': 'application/json',
-                            ...(localStorage.authToken ? { Authorization: 'Bearer ' + localStorage.authToken } : {}),
-                        },
+                        query: JSON.stringify([
+                            { name__contains: text },
+                            {
+                                limit: !!limit ? limit : 5,
+                                skip,
+                                orderBy,
+                            },
+                        ]),
                     }
                 )
-                    .then((res) => res.json())
-                    .then((data) => {
-                        if (data.errors) {
-                            throw new Error(JSON.stringify(data.errors));
-                        } else return data.data;
-                    })
             )
         );
     };

+ 11 - 18
src/actions/actionGoodDelete.js

@@ -1,23 +1,16 @@
-import { backendURL, getQuery, mock, query } from '../helpers';
+import { backendURL, getQuery, gql, mock, query } from "../helpers";
 
-import { actionPromise } from '../reducers';
+import { actionPromise } from "../reducers";
 
-export const actionGoodDelete = ({ _id, promiseName = 'goodDelete' } = {}) =>
+export const actionGoodDelete = ({ good, 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;
-            })
+        gql(
+            `mutation GoodDelete($good:GoodInput!){
+                GoodDelete(good:$good){
+                    _id name
+                }
+            }`,
+            { good }
+        )
     );

+ 4 - 3
src/actions/actionGoodsAll.js

@@ -1,8 +1,8 @@
-import { backendURL, getQuery, gql } from '../helpers';
-import { actionPromise } from '../reducers';
+import { backendURL, getQuery, gql } from "../helpers";
+import { actionPromise } from "../reducers";
 
 export const actionGoodsAll =
-    ({ limit = 20, skip = 0, promiseName = 'goodsAll', orderBy = '' } = {}) =>
+    ({ limit = 20, skip = 0, promiseName = "goodsAll", orderBy = "_id" } = {}) =>
     async (dispatch, getState) => {
         dispatch(
             actionPromise(
@@ -25,6 +25,7 @@ export const actionGoodsAll =
                             {
                                 limit: !!limit ? limit : 100,
                                 skip: skip,
+                                orderBy,
                             },
                         ]),
                     }

+ 23 - 17
src/actions/actionGoodsFind.js

@@ -1,29 +1,35 @@
-import { backendURL } from '../helpers';
-import { actionPromise } from '../reducers';
+import { backendURL, gql } from "../helpers";
+import { actionPromise } from "../reducers";
 
 export const actionGoodsFind =
-    ({ text = '', limit = 7, skip = 0, promiseName = 'goodsFind', orderBy = '' }) =>
+    ({ text = "", limit = 7, skip = 0, promiseName = "goodsFind", orderBy = "_id" }) =>
     async (dispatch, getState) => {
         dispatch(
             actionPromise(
                 promiseName,
-                fetch(
-                    `${backendURL}/goods/?limit=${limit}&skip=${skip}&text=${text}${orderBy && `&orderBy=` + orderBy}`,
+                gql(
+                    `query GoodsFind($query:String){
+                        GoodFind(query: $query){
+                            _id name price images{
+                                _id url
+                            }
+                            categories{
+                                _id name
+                            }
+                            amount
+                        }
+                    }`,
                     {
-                        method: 'GET',
-                        headers: {
-                            accept: 'application/json',
-                            'Content-Type': 'application/json',
-                            ...(localStorage.authToken ? { Authorization: 'Bearer ' + localStorage.authToken } : {}),
-                        },
+                        query: JSON.stringify([
+                            { name__contains: text },
+                            {
+                                limit: !!limit ? limit : 5,
+                                skip,
+                                orderBy,
+                            },
+                        ]),
                     }
                 )
-                    .then((res) => res.json())
-                    .then((data) => {
-                        if (data.errors) {
-                            throw new Error(JSON.stringify(data.errors));
-                        } else return data.data;
-                    })
             )
         );
     };

+ 5 - 4
src/actions/actionGoodsPopular.js

@@ -1,11 +1,11 @@
-import { backendURL, mock, query, gql } from '../helpers';
+import { backendURL, mock, query, gql } from "../helpers";
 
-import { actionPromise } from '../reducers';
+import { actionPromise } from "../reducers";
 
 export const actionGoodsPopular = () => async (dispatch, getState) => {
     dispatch(
         actionPromise(
-            'goodsPopular',
+            "goodsPopular",
             gql(
                 `query GoodsPopular($query:String){
                     GoodFind(query: $query){
@@ -19,7 +19,8 @@ export const actionGoodsPopular = () => async (dispatch, getState) => {
                     query: JSON.stringify([
                         {},
                         {
-                            sort: 'popular',
+                            limit: 15,
+                            orderBy: "popular",
                         },
                     ]),
                 }

+ 21 - 17
src/actions/actionOrderById.js

@@ -1,23 +1,27 @@
-import { backendURL, mock, query } from '../helpers';
+import { backendURL, gql, mock, query } from "../helpers";
 
-import { actionPromise } from '../reducers';
+import { actionPromise } from "../reducers";
 
-export const actionOrderById = ({ _id, promiseName = 'orderById' }) =>
+export const actionOrderById = ({ _id, promiseName = "orderById" }) =>
     actionPromise(
         promiseName,
-        fetch(`${backendURL}/orders/${_id}/`, {
-            method: 'GET',
-            headers: {
-                'Content-Type': 'application/json',
-                Accept: 'application/json',
+        gql(
+            `query OrderById($q:String){
+                OrderFindOne(query: $q){
+                _id status
+                owner{
+                    _id username
+                }
+                orderGoods{
+                    _id
+                    good{
+                        _id name
+                    }
+                    count
 
-                ...(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;
-            })
+                }
+            }
+        }`,
+            { q: JSON.stringify([{ _id }]) }
+        )
     );

+ 12 - 18
src/actions/actionOrderDelete.js

@@ -1,23 +1,17 @@
-import { backendURL, getQuery, mock, query } from '../helpers';
+import { backendURL, getQuery, gql, mock, query } from "../helpers";
 
-import { actionPromise } from '../reducers';
+import { actionPromise } from "../reducers";
 
-export const actionOrderDelete = ({ _id, promiseName = 'orderDelete' } = {}) =>
+export const actionOrderDelete = ({ order, promiseName = "orderDelete" } = {}) =>
     actionPromise(
         promiseName,
-        fetch(`${backendURL}/order/${_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;
-            })
+        gql(
+            `mutation OrderDelete($order:OrderInput!){
+            OrderDelete(order:$order){
+              _id price
+            }
+          }
+      `,
+            { order }
+        )
     );

+ 3 - 3
src/actions/actionOrderUpdate.js

@@ -2,7 +2,7 @@ import { actionCartClear, actionPromiseClear } from "../reducers";
 import { actionOrdersAll } from "./actionOrdersAll";
 import { actionOrderUpsert } from "./actionOrderUpsert";
 
-export const actionOrderUpdate = (orderGoods) => async (dispatch, getState) => {
-  await dispatch(actionOrderUpsert(orderGoods));
-  await dispatch(actionOrdersAll());
+export const actionOrderUpdate = (order) => async (dispatch, getState) => {
+    await dispatch(actionOrderUpsert(order));
+    await dispatch(actionOrdersAll());
 };

+ 22 - 27
src/actions/actionOrderUpsert.js

@@ -1,37 +1,32 @@
 import { backendURL, gql } from "../helpers";
 import { actionCartClear, actionPromise } from "../reducers";
 
-export const actionOrderUpsert = (orderGoods) => async (dispatch, getState) => {
-  if (!orderGoods.length) {
-    return;
-  }
-  await dispatch(
-    actionPromise(
-      "orderUpsert",
-      gql(
-        `mutation newOrder($order:OrderInput!){
+export const actionOrderUpsert = (order) => async (dispatch, getState) => {
+    if (!order?.orderGoods?.length) {
+        return;
+    }
+    await dispatch(
+        actionPromise(
+            "orderUpsert",
+            gql(
+                `mutation newOrder($order:OrderInput!){
         OrderUpsert(order:$order){
           _id price
         }
       }
       `,
-        {
-          order: {
-            orderGoods: orderGoods.map((orderGood) => ({
-              count: orderGood.count,
-              good: { _id: orderGood.good._id },
-            })),
-          },
-        }
-      )
-    )
-  );
-  let {
-    promise: { orderUpsert },
-  } = getState();
+                {
+                    order,
+                }
+            )
+        )
+    );
+    let {
+        promise: { orderUpsert },
+    } = getState();
 
-  if (orderUpsert.status === "FULFILLED") {
-    dispatch(actionCartClear());
-    // dispatch(actionOrders(token));
-  }
+    if (orderUpsert.status === "FULFILLED") {
+        dispatch(actionCartClear());
+        // dispatch(actionOrders(token));
+    }
 };

+ 11 - 8
src/actions/actionOrders.js

@@ -1,13 +1,16 @@
 import { actionPromise } from "../reducers";
 import { gql } from "../helpers";
-export const actionOrders = () => (dispatch) =>
-  dispatch(
-    actionPromise(
-      "orders",
-      gql(`
+export const actionOrders =
+    ({ promiseName = "orders" } = {}) =>
+    (dispatch) =>
+        dispatch(
+            actionPromise(
+                promiseName,
+                gql(`
             query orders{
                 OrderFind(query:"[{}]"){
-                    _id price createdAt status orderGoods{
+                    _id price createdAt status 
+                    orderGoods{
                         _id count price good{
                             name _id price images{
                                 url _id
@@ -17,5 +20,5 @@ export const actionOrders = () => (dispatch) =>
                 }
             }
           `)
-    )
-  );
+            )
+        );

+ 7 - 4
src/actions/actionOrdersAll.js

@@ -1,8 +1,8 @@
-import { actionPromise } from '../reducers';
-import { backendURL, gql } from '../helpers';
+import { actionPromise } from "../reducers";
+import { backendURL, gql } from "../helpers";
 
 export const actionOrdersAll =
-    ({ limit = 0, skip = 0, promiseName = 'adminOrdersAll', orderBy = '', status = 0 } = {}) =>
+    ({ limit = 0, skip = 0, promiseName = "adminOrdersAll", orderBy = "_id", status = 0 } = {}) =>
     async (dispatch, getState) => {
         dispatch(
             actionPromise(
@@ -23,10 +23,13 @@ export const actionOrdersAll =
                     }`,
                     {
                         query: JSON.stringify([
-                            {},
+                            {
+                                status,
+                            },
                             {
                                 limit: !!limit ? limit : 100,
                                 skip: skip,
+                                orderBy,
                             },
                         ]),
                     }

+ 19 - 17
src/actions/actionOrdersFind.js

@@ -1,29 +1,31 @@
-import { backendURL } from '../helpers';
-import { actionPromise } from '../reducers';
+import { backendURL, gql } from "../helpers";
+import { actionPromise } from "../reducers";
 
 export const actionOrdersFind =
-    ({ text = '', limit = 7, skip = 0, promiseName = 'ordersFind', orderBy = '' }) =>
+    ({ text = "", limit = 7, skip = 0, promiseName = "ordersFind" }) =>
     async (dispatch, getState) => {
         dispatch(
             actionPromise(
                 promiseName,
-                fetch(
-                    `${backendURL}/orders/?limit=${limit}&skip=${skip}&text=${text}${orderBy && `&orderBy=` + orderBy}`,
+                gql(
+                    `query OrdersFind($query:String){
+                        OrderFind(query: $query){
+                            _id status price 
+                            owner{
+                                _id username
+                            }
+                        }
+                    }`,
                     {
-                        method: 'GET',
-                        headers: {
-                            accept: 'application/json',
-                            'Content-Type': 'application/json',
-                            ...(localStorage.authToken ? { Authorization: 'Bearer ' + localStorage.authToken } : {}),
-                        },
+                        query: JSON.stringify([
+                            { name__contains: text },
+                            {
+                                limit: !!limit ? limit : 5,
+                                skip,
+                            },
+                        ]),
                     }
                 )
-                    .then((res) => res.json())
-                    .then((data) => {
-                        if (data.errors) {
-                            throw new Error(JSON.stringify(data.errors));
-                        } else return data.data;
-                    })
             )
         );
     };

+ 22 - 22
src/actions/actionRegister.js

@@ -3,26 +3,26 @@ import { actionPromise } from "../reducers";
 import { actionLogin } from "./actionLogin";
 
 export const actionRegister = (username, password) => async (dispatch, getState) => {
-  await dispatch(
-    actionPromise(
-      "register",
-      gql(
-        `mutation register($username:String,$password:String){
-                               UserUpsert(user:{username:$username,password:$password}){
-                                   _id username
-                               }
-                           }`,
-        {
-          username,
-          password,
-        }
-      )
-    )
-  );
-  const {
-    promise: { register },
-  } = getState();
-  if (register.status === "FULFILLED") {
-    dispatch(actionLogin(username, password));
-  }
+    await dispatch(
+        actionPromise(
+            "register",
+            gql(
+                `mutation register($username:String,$password:String){
+              UserUpsert(user:{username:$username,password:$password}){
+                  _id username
+              }
+          }`,
+                {
+                    username,
+                    password,
+                }
+            )
+        )
+    );
+    const {
+        promise: { register },
+    } = getState();
+    if (register.status === "FULFILLED") {
+        dispatch(actionLogin(username, password));
+    }
 };

+ 29 - 0
src/actions/actionUsersAll.js

@@ -0,0 +1,29 @@
+import { actionPromise } from "../reducers";
+import { backendURL, gql } from "../helpers";
+
+export const actionUsersAll =
+    ({ limit = 0, skip = 0, promiseName = "adminUsersAll", orderBy = "_id" } = {}) =>
+    async (dispatch, getState) => {
+        dispatch(
+            actionPromise(
+                promiseName,
+                gql(
+                    `query OUsersAll($query:String){
+                        UserFind(query: $query){
+                            _id username 
+                        }
+                    }`,
+                    {
+                        query: JSON.stringify([
+                            {},
+                            {
+                                limit: !!limit ? limit : 100,
+                                skip: skip,
+                                orderBy,
+                            },
+                        ]),
+                    }
+                )
+            )
+        );
+    };

+ 78 - 78
src/components/CartPage/index.js

@@ -10,92 +10,92 @@ import { UIContext } from "../UIContext";
 import { CartItem } from "./CartItem";
 
 export const CartPage = ({ onConfirm, promiseStatus, serverErrors }) => {
-  const cart = useSelector((state) => state.cart || {});
-  const { setAlert } = useContext(UIContext);
-  const sum = Object.entries(cart).reduce((prev, [_id, order]) => prev + order.count * order.good.price, 0);
-  const dispatch = useDispatch();
-  const navigate = useNavigate();
+    const cart = useSelector((state) => state.cart || {});
+    const { setAlert } = useContext(UIContext);
+    const sum = Object.entries(cart).reduce((prev, [_id, order]) => prev + order.count * order.good.price, 0);
+    const dispatch = useDispatch();
+    const navigate = useNavigate();
 
-  const formik = useFormik({
-    initialValues: {},
-    onSubmit: () => {
-      onConfirm && Object.keys(cart).length && onConfirm(Object.values(cart));
-    },
-  });
+    const formik = useFormik({
+        initialValues: {},
+        onSubmit: () => {
+            onConfirm && Object.keys(cart).length && onConfirm({ orderGoods: Object.values(cart) });
+        },
+    });
 
-  useEffect(() => {
-    if (!Object.entries(cart).length) {
-      navigate("/");
-    }
-  }, []);
+    useEffect(() => {
+        if (!Object.entries(cart).length) {
+            navigate("/");
+        }
+    }, []);
 
-  useEffect(() => {
-    !Object.keys(cart).length && navigate("/");
-  }, [cart]);
+    useEffect(() => {
+        !Object.keys(cart).length && navigate("/");
+    }, [cart]);
 
-  useEffect(() => {
-    if (promiseStatus === "FULFILLED") {
-      formik.setSubmitting(false);
-      setAlert({
-        show: true,
-        severity: "success",
-        message: "Готово",
-      });
-    }
-    if (promiseStatus === "REJECTED") {
-      const errorMessage = serverErrors.reduce((prev, curr) => prev + "\n" + curr.message, "");
-      formik.setSubmitting(false);
-      setAlert({
-        show: true,
-        severity: "error",
-        message: errorMessage,
-      });
-    }
-  }, [promiseStatus]);
+    useEffect(() => {
+        if (promiseStatus === "FULFILLED") {
+            formik.setSubmitting(false);
+            setAlert({
+                show: true,
+                severity: "success",
+                message: "Готово",
+            });
+        }
+        if (promiseStatus === "REJECTED") {
+            const errorMessage = serverErrors.reduce((prev, curr) => prev + "\n" + curr.message, "");
+            formik.setSubmitting(false);
+            setAlert({
+                show: true,
+                severity: "error",
+                message: errorMessage,
+            });
+        }
+    }, [promiseStatus]);
 
-  return (
-    <Box className="CartPage" component="form" onSubmit={formik.handleSubmit}>
-      <Stack spacing={2}>
-        <Typography>Оформлення замовлення</Typography>
-        <Table className="table">
-          <TableBody>
-            {Object.entries(cart).map(([_id, order]) => (
-              <CartItem order={order} onDeleteClick={(good) => dispatch(actionCartDelete(good))} key={_id} />
-            ))}
+    return (
+        <Box className="CartPage" component="form" onSubmit={formik.handleSubmit}>
+            <Stack spacing={2}>
+                <Typography>Оформлення замовлення</Typography>
+                <Table className="table">
+                    <TableBody>
+                        {Object.entries(cart).map(([_id, order]) => (
+                            <CartItem order={order} onDeleteClick={(good) => dispatch(actionCartDelete(good))} key={_id} />
+                        ))}
 
-            <TableRow>
-              <TableCell colSpan={3}>
-                <Typography variant="body1" bold>
-                  Всього:
-                </Typography>
-              </TableCell>
-              <TableCell>
-                <Typography textAlign="center">{sum} ₴</Typography>
-              </TableCell>
-              <TableCell></TableCell>
-            </TableRow>
-            <TableRow>
-              <TableCell colSpan={4}></TableCell>
+                        <TableRow>
+                            <TableCell colSpan={3}>
+                                <Typography variant="body1" bold>
+                                    Всього:
+                                </Typography>
+                            </TableCell>
+                            <TableCell>
+                                <Typography textAlign="center">{sum} ₴</Typography>
+                            </TableCell>
+                            <TableCell></TableCell>
+                        </TableRow>
+                        <TableRow>
+                            <TableCell colSpan={4}></TableCell>
 
-              <TableCell>
-                <Button variant="contained" disabled={formik.isSubmitting} type="submit">
-                  Підтвердити
-                </Button>
-              </TableCell>
-            </TableRow>
-          </TableBody>
-        </Table>
-      </Stack>
-    </Box>
-  );
+                            <TableCell>
+                                <Button variant="contained" disabled={formik.isSubmitting} type="submit">
+                                    Підтвердити
+                                </Button>
+                            </TableCell>
+                        </TableRow>
+                    </TableBody>
+                </Table>
+            </Stack>
+        </Box>
+    );
 };
 
 export const CCartPage = connect(
-  (state) => ({
-    promiseStatus: state.promise.orderUpsert?.status || null,
-    serverErrors: state.promise.orderUpsert?.error || null,
-  }),
-  {
-    onConfirm: (orderGoods) => actionOrderUpdate(orderGoods),
-  }
+    (state) => ({
+        promiseStatus: state.promise.orderUpsert?.status || null,
+        serverErrors: state.promise.orderUpsert?.error || null,
+    }),
+    {
+        onConfirm: (order) => actionOrderUpdate(order),
+    }
 )(CartPage);

+ 5 - 3
src/components/DashboardPage/DashboardOrder/index.js

@@ -1,13 +1,15 @@
 import { Box, Divider, Paper, Stack, Typography } from "@mui/material";
+import { statusNumber } from "../../../helpers";
 import { DashboardOrderGood } from "./DashboardOrderGood";
 
 export const DashboardOrder = ({ order }) => {
-    const { price = null, createdAt, orderGoods = [] } = order || {};
+    const { price = null, createdAt, orderGoods = [], status } = order || {};
     return (
         <Paper className="DashboardOrder">
-            <Stack direction="vertical" justifyContent="space-between">
-                <Typography textAlign="left">Дата: {new Date(+createdAt).toDateString()}</Typography>
+            <Stack direction="vertical" justifyContent="space-between" className="title">
+                <Typography textAlign="left">Дата: {new Date(+createdAt * 1000).toLocaleDateString()}</Typography>
                 <Typography textAlign="left">Сума: {price || " - "}</Typography>
+                <Typography textAlign="left">Статус: {"" + status?.length ? statusNumber[+order.status] : "-"}</Typography>
             </Stack>
             <Divider sx={{ my: 2 }} />
             <Stack spacing={2}>

+ 3 - 1
src/components/DashboardPage/index.js

@@ -1,5 +1,7 @@
 import { Stack } from "@mui/material";
-import { connect } from "react-redux";
+import { useEffect } from "react";
+import { connect, useDispatch } from "react-redux";
+import { actionOrders } from "../../actions/actionOrders";
 import { Error } from "../common/Error";
 import { DashboardOrder } from "./DashboardOrder";
 

+ 9 - 1
src/components/LayoutPage/index.js

@@ -5,6 +5,7 @@ import { Navigate, Route, Routes, useLocation, useParams } from "react-router-do
 import { actionCatById } from "../../actions/actionCatById";
 import { actionGoodById } from "../../actions/actionGoodById";
 import { actionGoodsFind } from "../../actions/actionGoodsFind";
+import { actionOrders } from "../../actions/actionOrders";
 import { AdminLayoutPage } from "../admin/AdminLayoutPage";
 import { CCartPage } from "../CartPage";
 import { Error404 } from "../common/Error404";
@@ -37,6 +38,13 @@ const GoodPageContainer = () => {
     return <GoodPage />;
 };
 
+const DashboardPageContainer = () => {
+    const dispatch = useDispatch();
+
+    dispatch(actionOrders());
+    return <CDashboardPage />;
+};
+
 const CGoodsList = connect((state) => ({ goods: state.promise?.pageGoodsFind?.payload || [] }))(GoodList);
 
 const GoodsListContainer = () => {
@@ -91,7 +99,7 @@ export const LayoutPage = () => {
                                 exact
                                 element={
                                     <CProtectedRoute roles={["user"]} fallback="/auth">
-                                        <CDashboardPage />
+                                        <DashboardPageContainer />
                                     </CProtectedRoute>
                                 }
                             />

+ 32 - 32
src/components/admin/AdminCategoryPage/CategoryForm.js

@@ -1,16 +1,16 @@
-import { connect, useDispatch } from 'react-redux';
-import React, { useState, useEffect, useContext } from 'react';
-import Select from 'react-select';
-import { actionCategoryUpdate } from '../../../actions/actionCategoryUpdate';
-import { actionPromise, actionPromiseClear, store } from '../../../reducers';
-import { Alert, Box, Button, InputLabel, Snackbar, Stack, TextField, Typography } from '@mui/material';
-import { UIContext } from '../../UIContext';
-import { useFormik } from 'formik';
-import * as Yup from 'yup';
-import { Error } from '../../common/Error';
-import { ConfirmModal } from '../../common/ConfirmModal';
-import { useNavigate } from 'react-router-dom';
-import { actionCategoryDelete } from '../../../actions/actionCategoryDelete';
+import { connect, useDispatch } from "react-redux";
+import React, { useState, useEffect, useContext } from "react";
+import Select from "react-select";
+import { actionCategoryUpdate } from "../../../actions/actionCategoryUpdate";
+import { actionPromise, actionPromiseClear, store } from "../../../reducers";
+import { Alert, Box, Button, InputLabel, Snackbar, Stack, TextField, Typography } from "@mui/material";
+import { UIContext } from "../../UIContext";
+import { useFormik } from "formik";
+import * as Yup from "yup";
+import { Error } from "../../common/Error";
+import { ConfirmModal } from "../../common/ConfirmModal";
+import { useNavigate } from "react-router-dom";
+import { actionCategoryDelete } from "../../../actions/actionCategoryDelete";
 
 const categorySchema = Yup.object().shape({
     name: Yup.string().required("Обов'язкове"),
@@ -39,7 +39,7 @@ const CategoryForm = ({
     const dispatch = useDispatch();
     const formik = useFormik({
         initialValues: {
-            name: category?.name || '',
+            name: category?.name || "",
         },
         validationSchema: categorySchema,
         validateOnChange: true,
@@ -57,45 +57,45 @@ const CategoryForm = ({
     });
 
     useEffect(() => {
-        formik.setFieldValue('name', category.name || '');
+        formik.setFieldValue("name", category.name || "");
         setInputParent(category?.parent || null);
         setInputGoods(category?.goods || []);
         setInputSubcategories(category?.subcategories || []);
     }, [category]);
 
     useEffect(() => {
-        if (promiseStatus === 'FULFILLED') {
+        if (promiseStatus === "FULFILLED") {
             formik.setSubmitting(false);
             setAlert({
                 show: true,
-                severity: 'success',
-                message: 'Готово',
+                severity: "success",
+                message: "Готово",
             });
         }
-        if (promiseStatus === 'REJECTED') {
-            const errorMessage = serverErrors.reduce((prev, curr) => prev + '\n' + curr.message, '');
+        if (promiseStatus === "REJECTED") {
+            const errorMessage = serverErrors.reduce((prev, curr) => prev + "\n" + curr.message, "");
             formik.setSubmitting(false);
             setAlert({
                 show: true,
-                severity: 'error',
+                severity: "error",
                 message: errorMessage,
             });
         }
     }, [promiseStatus]);
 
     useEffect(() => {
-        if (deletePromiseStatus === 'FULFILLED') {
-            navigate('/admin/categories/');
+        if (deletePromiseStatus === "FULFILLED") {
+            navigate("/admin/categories/");
         }
-        if (deletePromiseStatus === 'REJECTED') {
+        if (deletePromiseStatus === "REJECTED") {
             setAlert({
                 show: true,
-                severity: 'error',
-                message: 'Помилка',
+                severity: "error",
+                message: "Помилка",
             });
         }
         return () => {
-            dispatch(actionPromiseClear('categoryDelete'));
+            dispatch(actionPromiseClear("categoryDelete"));
         };
     }, [deletePromiseStatus]);
 
@@ -106,7 +106,7 @@ const CategoryForm = ({
                 _id !== category?._id &&
                 !inputSubcategories?.find((subCat) => _id === subCat._id)
         );
-        parentList = [...[{ _id: null, name: 'null' }], ...parentList];
+        parentList = [...[{ _id: null, name: "null" }], ...parentList];
 
         setParentList(parentList);
     }, [inputSubcategories]);
@@ -146,7 +146,7 @@ const CategoryForm = ({
             <Box sx={{ mt: 3 }}>
                 <InputLabel className="form-label">Батьківська категорія</InputLabel>
                 <Select
-                    value={{ value: inputParent?._id || null, label: inputParent?.name || 'null' }}
+                    value={{ value: inputParent?._id || null, label: inputParent?.name || "null" }}
                     onChange={(e) => setInputParent({ _id: e.value, name: e.label })}
                     options={parentList.map(({ _id, name }) => ({ value: _id, label: name }))}
                 />
@@ -190,7 +190,7 @@ const CategoryForm = ({
                     onClose={() => setIsDeleteModalOpen(false)}
                     onNO={() => setIsDeleteModalOpen(false)}
                     onYES={() => {
-                        onDelete(category._id);
+                        onDelete(category);
                     }}
                 />
             )}
@@ -208,7 +208,7 @@ export const CCategoryForm = connect(
     }),
     {
         onSave: (cat) => actionCategoryUpdate(cat),
-        onClose: () => actionPromiseClear('categoryUpsert'),
-        onDelete: (_id) => actionCategoryDelete({ _id }),
+        onClose: () => actionPromiseClear("categoryUpsert"),
+        onDelete: (category) => actionCategoryDelete({ category }),
     }
 )(CategoryForm);

+ 38 - 38
src/components/admin/AdminGoodPage/GoodForm.js

@@ -1,11 +1,11 @@
-import { connect, useDispatch } from 'react-redux';
-import React, { useState, useEffect, useContext } from 'react';
-import { actionPromise, actionPromiseClear } from '../../../reducers';
-import Select from 'react-select';
-import { actionGoodUpdate } from '../../../actions/actionGoodUpdate';
-import { EntityEditor } from '../../common/EntityEditor';
-import { actionUploadFiles } from '../../../actions/actionUploadFiles';
-import { UIContext } from '../../UIContext';
+import { connect, useDispatch } from "react-redux";
+import React, { useState, useEffect, useContext } from "react";
+import { actionPromise, actionPromiseClear } from "../../../reducers";
+import Select from "react-select";
+import { actionGoodUpdate } from "../../../actions/actionGoodUpdate";
+import { EntityEditor } from "../../common/EntityEditor";
+import { actionUploadFiles } from "../../../actions/actionUploadFiles";
+import { UIContext } from "../../UIContext";
 import {
     Alert,
     Box,
@@ -20,19 +20,19 @@ import {
     TextareaAutosize,
     TextField,
     Typography,
-} from '@mui/material';
-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';
+} from "@mui/material";
+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("Обов'язкове"),
     description: Yup.string().required("Обов'язкове"),
-    price: Yup.number().min(0, 'більше або равно 0').required("Обов'язкове"),
-    amount: Yup.number().min(0, 'більше або равно 0').required("Обов'язкове"),
+    price: Yup.number().min(0, "більше або равно 0").required("Обов'язкове"),
+    amount: Yup.number().min(0, "більше або равно 0").required("Обов'язкове"),
 });
 
 const CGoodEditor = connect(
@@ -64,8 +64,8 @@ export const GoodForm = ({
     const dispatch = useDispatch();
     const formik = useFormik({
         initialValues: {
-            name: '',
-            description: '',
+            name: "",
+            description: "",
             price: 0,
             amount: 0,
         },
@@ -86,48 +86,48 @@ export const GoodForm = ({
     });
 
     useEffect(() => {
-        if (promiseStatus === 'FULFILLED') {
+        if (promiseStatus === "FULFILLED") {
             formik.setSubmitting(false);
             setAlert({
                 show: true,
-                severity: 'success',
-                message: 'Готово',
+                severity: "success",
+                message: "Готово",
             });
         }
-        if (promiseStatus === 'REJECTED') {
-            const errorMessage = serverErrors.reduce((prev, curr) => prev + '\n' + curr.message, '');
+        if (promiseStatus === "REJECTED") {
+            const errorMessage = serverErrors.reduce((prev, curr) => prev + "\n" + curr.message, "");
             formik.setSubmitting(false);
             setAlert({
                 show: true,
-                severity: 'error',
+                severity: "error",
                 message: errorMessage,
             });
         }
     }, [promiseStatus]);
 
     useEffect(() => {
-        if (deletePromiseStatus === 'FULFILLED') {
-            navigate('/admin/goods/');
+        if (deletePromiseStatus === "FULFILLED") {
+            navigate("/admin/goods/");
         }
-        if (deletePromiseStatus === 'REJECTED') {
+        if (deletePromiseStatus === "REJECTED") {
             setAlert({
                 show: true,
-                severity: 'error',
-                message: 'Помилка',
+                severity: "error",
+                message: "Помилка",
             });
         }
         return () => {
-            dispatch(actionPromiseClear('goodDelete'));
+            dispatch(actionPromiseClear("goodDelete"));
         };
     }, [deletePromiseStatus]);
 
     useEffect(() => {
         setInputCategories(good?.categories || []);
         setInputImages(good?.images || []);
-        formik.setFieldValue('name', good.name || '');
-        formik.setFieldValue('description', good.description || '');
-        formik.setFieldValue('amount', good.amount || 0);
-        formik.setFieldValue('price', good.price || 0);
+        formik.setFieldValue("name", good.name || "");
+        formik.setFieldValue("description", good.description || "");
+        formik.setFieldValue("amount", good.amount || 0);
+        formik.setFieldValue("price", good.price || 0);
     }, [good.categories, good.name, good.description, good.amount, good.price]);
 
     useEffect(() => {
@@ -239,7 +239,7 @@ export const GoodForm = ({
                     onClose={() => setIsDeleteModalOpen(false)}
                     onNO={() => setIsDeleteModalOpen(false)}
                     onYES={() => {
-                        onDelete(good._id);
+                        onDelete(good);
                     }}
                 />
             )}
@@ -257,7 +257,7 @@ export const CGoodForm = connect(
     }),
     {
         onSave: (good) => actionGoodUpdate(good),
-        onClose: () => actionPromiseClear('goodUpsert'),
-        onDelete: (_id) => actionGoodDelete({ _id }),
+        onClose: () => actionPromiseClear("goodUpsert"),
+        onDelete: (good) => actionGoodDelete({ good }),
     }
 )(GoodForm);

+ 50 - 52
src/components/admin/AdminLayoutPage/index.js

@@ -1,22 +1,23 @@
-import { Box, Container } from '@mui/material';
-import { useEffect } from 'react';
-import { connect, useDispatch, useSelector } from 'react-redux';
-import { Navigate, Route, Routes, useParams, useSearchParams } from 'react-router-dom';
-import { actionGoodById } from '../../../actions/actionGoodById';
-import { actionCatById } from '../../../actions/actionCatById';
-import { actionPromiseClear, store, actionFeedCats } from '../../../reducers';
-import { actionFeedAdd, actionFeedClear, actionFeedGoods, actionFeedOrders } from '../../../reducers/feedReducer';
-import { CProtectedRoute } from '../../common/ProtectedRoute';
-import { CAdminGoodPage } from '../AdminGoodPage';
-import { AdminGoodsPage } from '../AdminGoodsPage';
-import { AdminCategoriesPage } from '../AdminCategoriesPage';
-import { CAdminCategoryPage } from '../AdminCategoryPage';
-import { AdminOrdersPage } from '../AdminOrdersPage';
-import { CAdminOrderPage } from '../AdminOrderPage';
-import { actionOrderById } from '../../../actions/actionOrderById';
-import { actionCatAll } from '../../../actions/actionCatAll';
-import { actionGoodsAll } from '../../../actions/actionGoodsAll';
-import { CAdminCategoryTree } from '../AdminCategoryTree';
+import { Box, Container } from "@mui/material";
+import { useEffect } from "react";
+import { connect, useDispatch, useSelector } from "react-redux";
+import { Navigate, Route, Routes, useParams, useSearchParams } from "react-router-dom";
+import { actionGoodById } from "../../../actions/actionGoodById";
+import { actionCatById } from "../../../actions/actionCatById";
+import { actionPromiseClear, store, actionFeedCats } from "../../../reducers";
+import { actionFeedAdd, actionFeedClear, actionFeedGoods, actionFeedOrders } from "../../../reducers/feedReducer";
+import { CProtectedRoute } from "../../common/ProtectedRoute";
+import { CAdminGoodPage } from "../AdminGoodPage";
+import { AdminGoodsPage } from "../AdminGoodsPage";
+import { AdminCategoriesPage } from "../AdminCategoriesPage";
+import { CAdminCategoryPage } from "../AdminCategoryPage";
+import { AdminOrdersPage } from "../AdminOrdersPage";
+import { CAdminOrderPage } from "../AdminOrderPage";
+import { actionOrderById } from "../../../actions/actionOrderById";
+import { actionCatAll } from "../../../actions/actionCatAll";
+import { actionGoodsAll } from "../../../actions/actionGoodsAll";
+import { CAdminCategoryTree } from "../AdminCategoryTree";
+import { actionUsersAll } from "../../../actions/actionUsersAll";
 
 const AdminCategoryPageContainer = ({}) => {
     const dispatch = useDispatch();
@@ -24,9 +25,9 @@ const AdminCategoryPageContainer = ({}) => {
     dispatch(actionGoodsAll());
     useEffect(() => {
         if (params._id) {
-            dispatch(actionCatById({ _id: params._id, promiseName: 'adminCatById' }));
+            dispatch(actionCatById({ _id: params._id, promiseName: "adminCatById" }));
         } else {
-            dispatch(actionPromiseClear('adminCatById'));
+            dispatch(actionPromiseClear("adminCatById"));
         }
     }, [params._id]);
     return <CAdminCategoryPage />;
@@ -35,12 +36,12 @@ const AdminCategoryPageContainer = ({}) => {
 const AdminCategoriesPageContainer = ({ cats }) => {
     const dispatch = useDispatch();
     const [searchParams] = useSearchParams();
-    const orderBy = searchParams.get('orderBy') || '_id';
+    const orderBy = searchParams.get("orderBy") || "_id";
 
     useEffect(() => {
         dispatch(actionFeedClear());
-        dispatch(actionPromiseClear('feedCatAll'));
-        dispatch(actionPromiseClear('categoryUpsert'));
+        dispatch(actionPromiseClear("feedCatAll"));
+        dispatch(actionPromiseClear("categoryUpsert"));
         dispatch(actionFeedCats({ skip: 0, orderBy }));
     }, [orderBy]);
 
@@ -52,15 +53,15 @@ const AdminCategoriesPageContainer = ({ cats }) => {
                     feed,
                     promise: { feedCatAll },
                 } = store.getState();
-                if (feedCatAll.status !== 'PENDING') {
+                if (feedCatAll.status !== "PENDING") {
                     dispatch(actionFeedCats(feed.payload?.length || 0, orderBy));
                 }
             }
         };
         return () => {
             dispatch(actionFeedClear());
-            dispatch(actionPromiseClear('feedCatAll'));
-            dispatch(actionPromiseClear('categoryUpsert'));
+            dispatch(actionPromiseClear("feedCatAll"));
+            dispatch(actionPromiseClear("categoryUpsert"));
             window.onscroll = null;
         };
     }, []);
@@ -78,9 +79,9 @@ const AdminGoodPageContainer = () => {
     dispatch(actionCatAll());
     useEffect(() => {
         if (params._id) {
-            dispatch(actionGoodById({ _id: params._id, promiseName: 'adminGoodById' }));
+            dispatch(actionGoodById({ _id: params._id, promiseName: "adminGoodById" }));
         } else {
-            dispatch(actionPromiseClear('adminGoodById'));
+            dispatch(actionPromiseClear("adminGoodById"));
         }
     }, [params._id]);
     return <CAdminGoodPage />;
@@ -89,12 +90,12 @@ const AdminGoodPageContainer = () => {
 const AdminGoodsPageContainer = ({ goods }) => {
     const dispatch = useDispatch();
     const [searchParams] = useSearchParams();
-    const orderBy = searchParams.get('orderBy') || '_id';
+    const orderBy = searchParams.get("orderBy") || "_id";
 
     useEffect(() => {
         dispatch(actionFeedClear());
-        dispatch(actionPromiseClear('feedGoodsAll'));
-        dispatch(actionPromiseClear('goodUpsert'));
+        dispatch(actionPromiseClear("feedGoodsAll"));
+        dispatch(actionPromiseClear("goodUpsert"));
         dispatch(actionFeedGoods({ skip: 0, orderBy }));
     }, [orderBy]);
 
@@ -107,15 +108,15 @@ const AdminGoodsPageContainer = ({ goods }) => {
                     promise: { feedGoodsAll },
                 } = store.getState();
 
-                if (feedGoodsAll.status !== 'PENDING') {
+                if (feedGoodsAll.status !== "PENDING") {
                     dispatch(actionFeedGoods({ skip: feed.payload?.length || 0, orderBy }));
                 }
             }
         };
         return () => {
             dispatch(actionFeedClear());
-            dispatch(actionPromiseClear('feedGoodsAll'));
-            dispatch(actionPromiseClear('goodUpsert'));
+            dispatch(actionPromiseClear("feedGoodsAll"));
+            dispatch(actionPromiseClear("goodUpsert"));
             window.onscroll = null;
         };
     }, []);
@@ -129,13 +130,13 @@ const AdminGoodsPageContainer = ({ goods }) => {
 const AdminOrdersPageContainer = ({ orders }) => {
     const dispatch = useDispatch();
     const [searchParams] = useSearchParams();
-    const orderBy = searchParams.get('orderBy') || '_id';
-    const status = searchParams.get('status') || 0;
+    const orderBy = searchParams.get("orderBy") || "_id";
+    const status = searchParams.get("status") || 0;
 
     useEffect(() => {
         dispatch(actionFeedClear());
-        dispatch(actionPromiseClear('feedOrdersAll'));
-        dispatch(actionPromiseClear('orderUpsert'));
+        dispatch(actionPromiseClear("feedOrdersAll"));
+        dispatch(actionPromiseClear("orderUpsert"));
         dispatch(actionFeedOrders({ skip: 0, orderBy, status }));
     }, [orderBy, status]);
 
@@ -148,15 +149,15 @@ const AdminOrdersPageContainer = ({ orders }) => {
                     promise: { feedOrdersAll },
                 } = store.getState();
 
-                if (feedOrdersAll.status !== 'PENDING') {
+                if (feedOrdersAll.status !== "PENDING") {
                     dispatch(actionFeedOrders({ skip: feed.payload?.length || 0, orderBy, status }));
                 }
             }
         };
         return () => {
             dispatch(actionFeedClear());
-            dispatch(actionPromiseClear('feedOrdersAll'));
-            dispatch(actionPromiseClear('orderUpsert'));
+            dispatch(actionPromiseClear("feedOrdersAll"));
+            dispatch(actionPromiseClear("orderUpsert"));
             window.onscroll = null;
         };
     }, []);
@@ -170,25 +171,22 @@ const AdminOrdersPageContainer = ({ orders }) => {
 const AdminOrderPageContainer = () => {
     const params = useParams();
     const dispatch = useDispatch();
-    dispatch(actionPromiseClear('adminOrderById'));
+    dispatch(actionPromiseClear("adminOrderById"));
+    dispatch(actionUsersAll());
     dispatch(actionGoodsAll());
     useEffect(() => {
         if (params._id) {
-            dispatch(actionOrderById({ _id: params._id, promiseName: 'adminOrderById' }));
+            dispatch(actionOrderById({ _id: params._id, promiseName: "adminOrderById" }));
         } else {
-            dispatch(actionOrderById('adminOrderById'));
+            dispatch(actionOrderById("adminOrderById"));
         }
     }, [params._id]);
     return <CAdminOrderPage />;
 };
 
-const CAdminGoodsPageContainer = connect((state) => ({ goods: state.promise?.feedGoodsAll?.payload || [] }))(
-    AdminGoodsPageContainer
-);
+const CAdminGoodsPageContainer = connect((state) => ({ goods: state.promise?.feedGoodsAll?.payload || [] }))(AdminGoodsPageContainer);
 
-const CAdminOrdersPageContainer = connect((state) => ({ orders: state.promise?.feedOrdersAll?.payload || [] }))(
-    AdminOrdersPageContainer
-);
+const CAdminOrdersPageContainer = connect((state) => ({ orders: state.promise?.feedOrdersAll?.payload || [] }))(AdminOrdersPageContainer);
 
 const CAdminCategoriesPageContainer = connect((state) => ({ cats: state.promise?.feedCatAll?.payload || [] }))(
     AdminCategoriesPageContainer
@@ -198,7 +196,7 @@ const AdminLayoutPage = () => {
     return (
         <Box className="AdminLayoutPage">
             <Routes>
-                <Route path="/" element={<Navigate to={'/admin/goods/'} />} />
+                <Route path="/" element={<Navigate to={"/admin/goods/"} />} />
                 <Route path="/tree/" element={<CAdminCategoryTree />} />
                 <Route path="/goods/" element={<CAdminGoodsPageContainer />} />
                 <Route path="/good/" element={<AdminGoodPageContainer />} />

+ 49 - 164
src/components/admin/AdminOrderPage/OrderForm.js

@@ -1,11 +1,11 @@
-import { connect, useDispatch, useSelector } from 'react-redux';
-import React, { useState, useEffect, useContext } from 'react';
-import { actionPromise, actionPromiseClear } from '../../../reducers';
-import Select from 'react-select';
-import { actionOrderUpdate } from '../../../actions/actionOrderUpdate';
-import { EntityEditor } from '../../common/EntityEditor';
-import { actionUploadFiles } from '../../../actions/actionUploadFiles';
-import { UIContext } from '../../UIContext';
+import { connect, useDispatch, useSelector } from "react-redux";
+import React, { useState, useEffect, useContext } from "react";
+import { actionPromise, actionPromiseClear } from "../../../reducers";
+import Select from "react-select";
+import { actionOrderUpdate } from "../../../actions/actionOrderUpdate";
+import { EntityEditor } from "../../common/EntityEditor";
+import { actionUploadFiles } from "../../../actions/actionUploadFiles";
+import { UIContext } from "../../UIContext";
 import {
     Box,
     Button,
@@ -19,46 +19,34 @@ import {
     TextareaAutosize,
     TextField,
     Typography,
-} from '@mui/material';
-import { FormikProvider, useFormik } from 'formik';
-import * as Yup from 'yup';
-import { Error } from '../../common/Error';
-import { statusNumber, statusOptions } from '../../../helpers';
-import { OrderGoodsEditor } from './OrderGoodsEditor';
-import { useNavigate } from 'react-router-dom';
-import { actionOrderDelete } from '../../../actions/actionOrderDelete';
-import { ConfirmModal } from '../../common/ConfirmModal';
+} from "@mui/material";
+import { FormikProvider, useFormik } from "formik";
+import * as Yup from "yup";
+import { Error } from "../../common/Error";
+import { statusNumber, statusOptions } from "../../../helpers";
+import { OrderGoodsEditor } from "./OrderGoodsEditor";
+import { useNavigate } from "react-router-dom";
+import { actionOrderDelete } from "../../../actions/actionOrderDelete";
+import { ConfirmModal } from "../../common/ConfirmModal";
 
 const deliveryOptions = [
-    { label: 'Нова пошта', value: 'nova-poshta' },
-    { label: 'Justin', value: 'justin' },
+    { label: "Нова пошта", value: "nova-poshta" },
+    { label: "Justin", value: "justin" },
 ];
 
-const orderSchema = Yup.object().shape({
-    email: Yup.string().required("Обов'язкове"),
-    phoneNumber: Yup.string().required("Обов'язкове"),
-    name: Yup.string(),
-    address: Yup.string().required("Обов'язкове"),
-    surname: Yup.string(),
-    delivery: Yup.string()
-        .required("обов'язкове")
-        .oneOf(
-            deliveryOptions.map((option) => option.value),
-            'не знайдено'
-        ),
-});
-
 export const OrderForm = ({
     serverErrors = [],
     onSaveClick,
     onSave,
     onClose,
     onDelete,
+    userList,
     promiseStatus,
     deletePromiseStatus,
     order = {},
 } = {}) => {
     const [inputStatus, setInputStatus] = useState(null);
+    const [inputUser, setInputUser] = useState({});
     const { setAlert } = useContext(UIContext);
     const goodList = useSelector((state) => state.promise?.goodsAll?.payload || []);
     const [inputOrderGoods, setInputOrderGoods] = useState([]);
@@ -67,26 +55,12 @@ export const OrderForm = ({
     const dispatch = useDispatch();
 
     const formik = useFormik({
-        initialValues: {
-            email: '',
-            name: '',
-            surname: '',
-            phoneNumber: '',
-            delivery: '',
-            address: '',
-        },
-        validationSchema: orderSchema,
-        validateOnChange: true,
+        initialValues: {},
         onSubmit: () => {
             let orderToSave = {};
             order?._id && (orderToSave._id = order._id);
-            orderToSave.name = formik.values.name;
-            orderToSave.email = formik.values.email;
             orderToSave.status = inputStatus;
-            orderToSave.surname = formik.values.surname;
-            orderToSave.phoneNumber = formik.values.phoneNumber;
-            orderToSave.address = formik.values.address;
-            orderToSave.delivery = formik.values.delivery;
+            inputUser && (orderToSave.owner = inputUser);
             orderToSave.orderGoods = inputOrderGoods;
             onSaveClick && onSaveClick();
             onSave(orderToSave);
@@ -95,13 +69,8 @@ export const OrderForm = ({
 
     useEffect(() => {
         setInputStatus(order?.status || null);
+        setInputUser(order?.owner || null);
         setInputOrderGoods(order.orderGoods || []);
-        formik.setFieldValue('email', order.email || '');
-        formik.setFieldValue('name', order.name || '');
-        formik.setFieldValue('address', order.address || '');
-        formik.setFieldValue('surname', order.surname || '');
-        formik.setFieldValue('phoneNumber', order.phoneNumber || '');
-        formik.setFieldValue('delivery', order.delivery || '');
     }, [order]);
 
     useEffect(() => {
@@ -109,38 +78,38 @@ export const OrderForm = ({
     }, [formik.values]);
 
     useEffect(() => {
-        if (promiseStatus === 'FULFILLED') {
+        if (promiseStatus === "FULFILLED") {
             formik.setSubmitting(false);
             setAlert({
                 show: true,
-                severity: 'success',
-                message: 'Готово',
+                severity: "success",
+                message: "Готово",
             });
         }
-        if (promiseStatus === 'REJECTED') {
-            const errorMessage = serverErrors.reduce((prev, curr) => prev + '\n' + curr.message, '');
+        if (promiseStatus === "REJECTED") {
+            const errorMessage = serverErrors.reduce((prev, curr) => prev + "\n" + curr.message, "");
             formik.setSubmitting(false);
             setAlert({
                 show: true,
-                severity: 'error',
+                severity: "error",
                 message: errorMessage,
             });
         }
     }, [promiseStatus]);
 
     useEffect(() => {
-        if (deletePromiseStatus === 'FULFILLED') {
-            navigate('/admin/orders/');
+        if (deletePromiseStatus === "FULFILLED") {
+            navigate("/admin/orders/");
         }
-        if (deletePromiseStatus === 'REJECTED') {
+        if (deletePromiseStatus === "REJECTED") {
             setAlert({
                 show: true,
-                severity: 'error',
-                message: 'Помилка',
+                severity: "error",
+                message: "Помилка",
             });
         }
         return () => {
-            dispatch(actionPromiseClear('orderDelete'));
+            dispatch(actionPromiseClear("orderDelete"));
         };
     }, [deletePromiseStatus]);
 
@@ -154,35 +123,6 @@ export const OrderForm = ({
         <Box className="OrderForm" component="form" onSubmit={formik.handleSubmit}>
             <Grid container spacing={5}>
                 <Grid item xs={6}>
-                    <TextField
-                        id="email"
-                        name="email"
-                        variant="outlined"
-                        label="Email"
-                        size="small"
-                        error={formik.touched.email && Boolean(formik.errors.email)}
-                        value={formik.values.email}
-                        onBlur={formik.handleBlur}
-                        onChange={formik.handleChange}
-                        helperText={formik.touched.email && formik.errors.email}
-                        fullWidth
-                        sx={{ mt: 2 }}
-                    />
-                    <TextField
-                        id="name"
-                        name="name"
-                        variant="outlined"
-                        label="Ім'я"
-                        size="small"
-                        error={formik.touched.name && Boolean(formik.errors.name)}
-                        value={formik.values.name}
-                        onBlur={formik.handleBlur}
-                        onChange={formik.handleChange}
-                        helperText={formik.touched.name && formik.errors.name}
-                        fullWidth
-                        sx={{ mt: 2 }}
-                    />
-
                     <Box sx={{ mt: 3 }}>
                         <InputLabel className="form-label">Статус</InputLabel>
                         <Select
@@ -211,76 +151,20 @@ export const OrderForm = ({
                                 Видалити
                             </Button>
                         )}
-                        <Button variant="contained" disabled={!formik.isValid || formik.isSubmitting} type="submit">
+                        <Button variant="contained" disabled={formik.isSubmitting} type="submit">
                             Зберегти
                         </Button>
                     </Stack>
                 </Grid>
                 <Grid item xs={6}>
-                    <TextField
-                        variant="outlined"
-                        id="phoneNumber"
-                        name="phoneNumber"
-                        label="Номер"
-                        size="small"
-                        error={formik.touched.phoneNumber && Boolean(formik.errors.phoneNumber)}
-                        value={formik.values.phoneNumber}
-                        onBlur={formik.handleBlur}
-                        onChange={formik.handleChange}
-                        helperText={formik.touched.phoneNumber && formik.errors.phoneNumber}
-                        multiline
-                        fullWidth
-                        sx={{ mt: 2 }}
-                    />
-                    <TextField
-                        id="surname"
-                        name="surname"
-                        variant="outlined"
-                        label="Прізвище"
-                        size="small"
-                        error={formik.touched.surname && Boolean(formik.errors.surname)}
-                        value={formik.values.surname}
-                        onBlur={formik.handleBlur}
-                        onChange={formik.handleChange}
-                        helperText={formik.touched.surname && formik.errors.surname}
-                        fullWidth
-                        sx={{ mt: 2 }}
-                    />
-                    <TextField
-                        id="address"
-                        name="address"
-                        variant="outlined"
-                        label="Адреса"
-                        size="small"
-                        error={formik.touched.address && Boolean(formik.errors.address)}
-                        value={formik.values.address}
-                        onBlur={formik.handleBlur}
-                        onChange={formik.handleChange}
-                        helperText={formik.touched.address && formik.errors.address}
-                        fullWidth
-                        sx={{ mt: 2 }}
-                    />
-                    <TextField
-                        id="delivery"
-                        name="delivery"
-                        variant="outlined"
-                        label="Тип доставкі"
-                        size="small"
-                        select
-                        error={formik.touched.delivery && Boolean(formik.errors.delivery)}
-                        value={formik.values.delivery}
-                        onBlur={formik.handleBlur}
-                        onChange={formik.handleChange}
-                        helperText={formik.touched.delivery && formik.errors.delivery}
-                        fullWidth
-                        sx={{ mt: 2 }}
-                    >
-                        {deliveryOptions.map((option) => (
-                            <MenuItem key={option.value} value={option.value} t>
-                                {option.label}
-                            </MenuItem>
-                        ))}
-                    </TextField>
+                    <Box sx={{ mt: 3 }}>
+                        <InputLabel className="form-label">Користувач</InputLabel>
+                        <Select
+                            value={{ value: inputUser?._id || null, label: inputUser?.username || "null" }}
+                            onChange={(e) => setInputUser({ _id: e.value, username: e.label })}
+                            options={userList.map(({ _id, username }) => ({ value: _id, label: username }))}
+                        />
+                    </Box>
                 </Grid>
             </Grid>
 
@@ -291,7 +175,7 @@ export const OrderForm = ({
                     onClose={() => setIsDeleteModalOpen(false)}
                     onNO={() => setIsDeleteModalOpen(false)}
                     onYES={() => {
-                        onDelete(order._id);
+                        onDelete(order);
                     }}
                 />
             )}
@@ -304,11 +188,12 @@ export const COrderForm = connect(
         promiseStatus: state.promise.orderUpsert?.status || null,
         serverErrors: state.promise.orderUpsert?.error || null,
         order: state.promise?.adminOrderById?.payload || {},
+        userList: state.promise.adminUsersAll.payload || [],
         deletePromiseStatus: state.promise.orderDelete?.status || null,
     }),
     {
         onSave: (order) => actionOrderUpdate(order),
-        onClose: () => actionPromiseClear('orderUpsert'),
-        onDelete: (_id) => actionOrderDelete({ _id }),
+        onClose: () => actionPromiseClear("orderUpsert"),
+        onDelete: (order) => actionOrderDelete({ order }),
     }
 )(OrderForm);

+ 7 - 8
src/components/admin/AdminOrdersPage/AdminOrderItem.js

@@ -1,13 +1,12 @@
-import { Link } from 'react-router-dom';
+import { Link } from "react-router-dom";
 
-import { Box, Button, TableCell, TableRow, Typography } from '@mui/material';
-import { statusNumber } from '../../../helpers';
+import { Box, Button, TableCell, TableRow, Typography } from "@mui/material";
+import { statusNumber } from "../../../helpers";
 
 const AdminOrderItem = ({ order }) => (
     <TableRow className="AdminOrderItem">
         <TableCell scope="row">{order._id}</TableCell>
-        <TableCell>{order.email ? order.email : '-'}</TableCell>
-        <TableCell>{order.phoneNumber ? order.phoneNumber : '-'}</TableCell>
+        <TableCell>{order?.owner?.username ? order.owner.username : "-"}</TableCell>
         <TableCell>
             {order.orderGoods
                 ? (order.orderGoods || []).map((orderGood) => (
@@ -15,10 +14,10 @@ const AdminOrderItem = ({ order }) => (
                           {orderGood.good.name} - {orderGood.count}
                       </Typography>
                   ))
-                : '-'}
+                : "-"}
         </TableCell>
-        <TableCell>{order.price ? order.price : '-'}</TableCell>
-        <TableCell>{'' + order?.status?.length ? statusNumber[+order.status] : '-'}</TableCell>
+        <TableCell>{order.price ? order.price : "-"}</TableCell>
+        <TableCell>{"" + order?.status?.length ? statusNumber[+order.status] : "-"}</TableCell>
         <TableCell className="edit">
             <Button component={Link} className="Link" to={`/admin/order/${order._id}/`} variant="contained">
                 Редагувати

+ 15 - 16
src/components/admin/AdminOrdersPage/AdminOrderListHeader.js

@@ -1,8 +1,8 @@
-import { connect } from 'react-redux';
+import { connect } from "react-redux";
 
-import { AddButton } from '../../common/AddButton';
-import { TableCell, TableRow, TableSortLabel } from '@mui/material';
-import { useNavigate } from 'react-router-dom';
+import { AddButton } from "../../common/AddButton";
+import { TableCell, TableRow, TableSortLabel } from "@mui/material";
+import { useNavigate } from "react-router-dom";
 
 const AdminOrderListHeader = ({ onSortChange, sort }) => {
     const navigate = useNavigate();
@@ -10,30 +10,29 @@ const AdminOrderListHeader = ({ onSortChange, sort }) => {
         <TableRow className="AdminOrderListHeader">
             <TableCell scope="col">
                 <TableSortLabel
-                    active={sort === '_id' || sort === '-_id'}
-                    direction={sort === '_id' ? 'asc' : 'desc'}
-                    onClick={() => onSortChange(sort === '_id' ? '-_id' : '_id')}
+                    active={sort === "_id" || sort === "-_id"}
+                    direction={sort === "_id" ? "asc" : "desc"}
+                    onClick={() => onSortChange(sort === "_id" ? "-_id" : "_id")}
                 >
                     #
                 </TableSortLabel>
             </TableCell>
-            <TableCell scope="col">Email</TableCell>
-            <TableCell scope="col">Номер</TableCell>
+            <TableCell scope="col">Користувач</TableCell>
             <TableCell scope="col">Товари</TableCell>
             <TableCell scope="col">
                 <TableSortLabel
-                    active={sort === 'price' || sort === '-price'}
-                    direction={sort === 'price' ? 'asc' : 'desc'}
-                    onClick={() => onSortChange(sort === 'price' ? '-price' : 'price')}
+                    active={sort === "price" || sort === "-price"}
+                    direction={sort === "price" ? "asc" : "desc"}
+                    onClick={() => onSortChange(sort === "price" ? "-price" : "price")}
                 >
                     Ціна
                 </TableSortLabel>
             </TableCell>
             <TableCell scope="col">
                 <TableSortLabel
-                    active={sort === 'status' || sort === '-status'}
-                    direction={sort === 'status' ? 'asc' : 'desc'}
-                    onClick={() => onSortChange(sort === 'status' ? '-status' : 'status')}
+                    active={sort === "status" || sort === "-status"}
+                    direction={sort === "status" ? "asc" : "desc"}
+                    onClick={() => onSortChange(sort === "status" ? "-status" : "status")}
                 >
                     Статус
                 </TableSortLabel>
@@ -41,7 +40,7 @@ const AdminOrderListHeader = ({ onSortChange, sort }) => {
             <TableCell scope="col">
                 <AddButton
                     onClick={() => {
-                        navigate('/admin/order/');
+                        navigate("/admin/order/");
                     }}
                 />
             </TableCell>

+ 1 - 0
src/index.scss

@@ -222,6 +222,7 @@
       padding: 20px;
       & .DashboardOrder{
         padding:20px;
+
         & .DashboardOrderGood{
           & img{
            width:100%;

+ 25 - 25
src/reducers/feedReducer.js

@@ -1,62 +1,62 @@
-import { actionPromise } from '.';
-import { actionCatAll } from '../actions/actionCatAll';
-import { actionGoodsFind } from '../actions/actionGoodsFind';
-import { actionCatsFind } from '../actions/actionCatsFind';
-import { actionGoodsAll } from '../actions/actionGoodsAll';
-import { gql } from '../helpers';
-import { actionOrdersAll } from '../actions/actionOrdersAll';
-import { actionOrdersFind } from '../actions/actionOrdersFind';
+import { actionPromise } from ".";
+import { actionCatAll } from "../actions/actionCatAll";
+import { actionGoodsFind } from "../actions/actionGoodsFind";
+import { actionCatsFind } from "../actions/actionCatsFind";
+import { actionGoodsAll } from "../actions/actionGoodsAll";
+import { gql } from "../helpers";
+import { actionOrdersAll } from "../actions/actionOrdersAll";
+import { actionOrdersFind } from "../actions/actionOrdersFind";
 
 function feedReducer(state = { payload: [] }, { type, payload = [] }) {
-    if (type === 'FEED_ADD') {
+    if (type === "FEED_ADD") {
         return {
             ...state,
-            payload: [...new Map([...state['payload'], ...payload].map((item) => [item['_id'], item])).values()],
+            payload: [...new Map([...state["payload"], ...payload].map((item) => [item["_id"], item])).values()],
         };
     }
 
-    if (type === 'FEED_CLEAR') {
+    if (type === "FEED_CLEAR") {
         return { payload: [] };
     }
     return state || { payload: [] };
 }
 
-const actionFeedAdd = (payload) => ({ type: 'FEED_ADD', payload });
-const actionFeedClear = () => ({ type: 'FEED_CLEAR' });
+const actionFeedAdd = (payload) => ({ type: "FEED_ADD", payload });
+const actionFeedClear = () => ({ type: "FEED_CLEAR" });
 const actionFeedGoods =
-    ({ skip = 0, orderBy = '_id' }) =>
+    ({ skip = 0, orderBy = "_id" }) =>
     async (dispatch, getState) => {
-        await dispatch(actionGoodsAll({ skip, limit: 20, promiseName: 'feedGoodsAll', orderBy }));
+        await dispatch(actionGoodsAll({ skip, limit: 15, promiseName: "feedGoodsAll", orderBy }));
     };
 
 const actionFeedGoodsFind =
-    ({ skip = 0, text = '' }) =>
+    ({ skip = 0, text = "" }) =>
     async (dispatch, getState) => {
-        await dispatch(actionGoodsFind({ skip, limit: 20, promiseName: 'feedGoodsFind', text }));
+        await dispatch(actionGoodsFind({ skip, limit: 15, promiseName: "feedGoodsFind", text }));
     };
 
 const actionFeedCatsFind =
-    ({ skip = 0, text = '' }) =>
+    ({ skip = 0, text = "" }) =>
     async (dispatch, getState) => {
-        await dispatch(actionCatsFind({ skip, promiseName: 'feedCatsFind', text, limit: 7 }));
+        await dispatch(actionCatsFind({ skip, promiseName: "feedCatsFind", text, limit: 7 }));
     };
 
 const actionFeedCats =
-    ({ skip = 0, orderBy = '_id' }) =>
+    ({ skip = 0, orderBy = "_id" }) =>
     async (dispatch, getState) => {
-        await dispatch(actionCatAll({ promiseName: 'feedCatAll', skip, limit: 20, orderBy }));
+        await dispatch(actionCatAll({ promiseName: "feedCatAll", skip, limit: 15, orderBy }));
     };
 
 const actionFeedOrders =
-    ({ skip = 0, orderBy = '_id', status = 0 }) =>
+    ({ skip = 0, orderBy = "_id", status = 0 }) =>
     async (dispatch, getState) => {
-        await dispatch(actionOrdersAll({ skip, limit: 20, promiseName: 'feedOrdersAll', orderBy, status }));
+        await dispatch(actionOrdersAll({ skip, limit: 15, promiseName: "feedOrdersAll", orderBy, status }));
     };
 
 const actionFeedOrdersFind =
-    ({ skip = 0, text = '' }) =>
+    ({ skip = 0, text = "" }) =>
     async (dispatch, getState) => {
-        await dispatch(actionOrdersFind({ skip, limit: 20, promiseName: 'feedOrdersFind', text }));
+        await dispatch(actionOrdersFind({ skip, limit: 15, promiseName: "feedOrdersFind", text }));
     };
 
 export {