Pārlūkot izejas kodu

pages for admin and pagination

viktoriia.kapran 1 gadu atpakaļ
vecāks
revīzija
f01a3d9495

+ 12 - 0
js21 react/my-react-app/src/App.js

@@ -19,6 +19,8 @@ import UsersPage from './pages/admin/UsersPage';
 import CategoriesPage from './pages/admin/CategoriesPage';
 import CreateCategoryPage from './pages/admin/CreateCategoryPage';
 import EditCategoryPage from './pages/admin/EditCategoryPage';
+import GoodsPage from './pages/admin/GoodsPage';
+import OrdersPage from './pages/admin/OrdersPage';
 
 
 function App() {
@@ -44,6 +46,11 @@ function App() {
                 <UsersPage />
               </RequireAdmin>
             } />
+            <Route path='/admin/orders' element={
+              <RequireAdmin>
+                <OrdersPage />
+              </RequireAdmin>
+            } />
             <Route path='/admin/categories' element={
               <RequireAdmin>
                 <CategoriesPage />
@@ -59,6 +66,11 @@ function App() {
                 <EditCategoryPage />
               </RequireAdmin>
             } />
+            <Route path='/admin/goods' element={
+              <RequireAdmin>
+                <GoodsPage />
+              </RequireAdmin>
+            } />
             <Route path='/register' element={<RegisterPage />} />
             <Route path='/login' element={<LoginPage />} />
             <Route path='/:category/:categoryId' element={<CategoryPage />} />

+ 62 - 12
js21 react/my-react-app/src/api/api.js

@@ -21,7 +21,7 @@ export const api = createApi({
     url: API_URL,
     prepareHeaders
   }),
-  tagTypes: ['Category', 'Order'],
+  tagTypes: ['Category', 'Order', 'Good'],
   endpoints: (builder) => ({
     getCategories: builder.query({
       query: () => ({
@@ -113,7 +113,7 @@ export const api = createApi({
       providesTags: (result, error, id) => ([{ type: 'User', id }])
     }),
     getOwnerOrder: builder.query({
-      query: () => ({
+      query: ({ limit, skip }) => ({
         document: gql`
                   query orders($q: String) {
                     OrderFind(query: $q) {
@@ -129,10 +129,19 @@ export const api = createApi({
                     }
                   }
                   `,
-        variables: { q: JSON.stringify([{}]) }
+        variables: { q: JSON.stringify([{}, { limit: [limit], skip: [skip] }]) }
       }),
       providesTags: ['Order'],
     }),
+    getOrderCount: builder.query({
+      query: () => ({
+        document: gql`
+                  query getOrderCount($q: String) {
+                    OrderCount(query: $q)
+                  }`,
+        variables: { q: JSON.stringify([{}]) }
+      })
+    }),
     getOrderGood: builder.query({
       query: () => ({
         document: gql`
@@ -161,22 +170,32 @@ export const api = createApi({
                   query GetGoods($q: String) {
                     GoodFind(query: $q) {
                       _id, name, description, price, categories {
-                        _id
+                        _id, name
                       }
                     }
                   }`,
         variables: { q: JSON.stringify([{}]) }
+      }),
+      providesTags: ['Good'],
+    }),
+    getUserCount: builder.query({
+      query: () => ({
+        document: gql`
+                  query GetUserCount($q: String) {
+                    UserCount(query: $q)
+                  }`,
+        variables: { q: JSON.stringify([{}]) }
       })
     }),
     getUsers: builder.query({
-      query: () => ({
+      query: ({ skip, limit }) => ({
         document: gql`
                   query GetUsers($q: String) {
                     UserFind(query: $q) {
                       _id, login, createdAt
                     }
                   }`,
-        variables: { q: JSON.stringify([{}]) }
+        variables: { q: JSON.stringify([{}, { skip: [skip], limit: [limit] }]) }
       })
     }),
     login: builder.mutation({
@@ -242,20 +261,50 @@ export const api = createApi({
       }),
       invalidatesTags: ['Category'],
     }),
+    createGood: builder.mutation({
+      query: (good) => ({
+        document: gql`
+                  mutation createGood($good: GoodInput) {
+                    GoodUpsert(good: $good) {
+                      _id
+                    }
+                  }`,
+        variables: { good }
+      }),
+      invalidatesTags: ['Good']
+    }),
+    deleteGood: builder.mutation({
+      query: (good) => ({
+        document: gql`
+                  mutation deleteGood($good: GoodInput) {
+                    GoodDelete(good: $good) {
+                      _id, name, images {
+                        url, _id
+                      }, price, description
+                    }
+                  }`,
+        variables: { good }
+      }),
+      invalidatesTags: ['Good']
+    }),
   }),
 });
 
+export const createGood = good =>
+  async dispatch => {
+    await dispatch(api.endpoints.createGood.initiate(good));
+  }
+
+
+
 export const createCategory = category =>
   async dispatch => {
-    console.log(category);
-    const payload = await dispatch(api.endpoints.createCategory.initiate(category));
-    console.log('category created', payload);
+    await dispatch(api.endpoints.createCategory.initiate(category));
   }
 
 export const deleteCategory = category =>
   async dispatch => {
-    const payload = await dispatch(api.endpoints.deleteCategory.initiate(category));
-    console.log('deleted', payload);
+    await dispatch(api.endpoints.deleteCategory.initiate(category));
   }
 
 export const actionOrder = orderGoods =>
@@ -371,4 +420,5 @@ export const cartSlice = createSlice({
 });
 export const { addGood, deleteGood, decreaseGoodCount, setGoodCount, clearCart } = cartSlice.actions;
 export const { useGetCategoriesQuery, useGetCategoryByIdQuery, useGetGoodByIdQuery, useLoginMutation, useGetOwnerOrderQuery,
-  useRegisterMutation, useGetUserByIdQuery, useCreateCategoryMutation, useGetGoodsQuery, useGetUsersQuery, useGetOrderGoodQuery } = api;
+  useRegisterMutation, useGetUserByIdQuery, useCreateCategoryMutation, useGetGoodsQuery, useGetUsersQuery, useGetOrderGoodQuery,
+  useGetUserCountQuery, useGetOrderCountQuery } = api;

+ 1 - 1
js21 react/my-react-app/src/components/CategoriesMenu/CategoryMenu.js

@@ -9,7 +9,7 @@ import List from '@mui/material/List';
  const CategoryMenu = () => {
   const { data, error, isFetching } = useGetCategoriesQuery();
   const admin = useSelector(state => state.auth?.payload?.sub?.acl?.includes('admin'));
-  const adminMenu = ['Categories', 'Users'];
+  const adminMenu = ['Categories', 'Users', 'Goods', 'Orders'];
 
   return (
     <aside className='aside'>

+ 1 - 1
js21 react/my-react-app/src/components/hoc/RequireAdmin.js

@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import React from 'react';
 import { useSelector } from 'react-redux';
 import { Navigate, useLocation } from 'react-router-dom';
 

+ 1 - 1
js21 react/my-react-app/src/pages/GoodPage/GoodPage.js

@@ -1,5 +1,5 @@
 
-import React, { useEffect, useState } from 'react';
+import React, { useState } from 'react';
 import { useParams } from 'react-router-dom';
 import { useDispatch } from 'react-redux';
 import { CategoriesSection } from '../../components/CategoriesSection/CategoriesSection';

+ 1 - 2
js21 react/my-react-app/src/pages/UserPage.js

@@ -8,11 +8,10 @@ import { useParams } from 'react-router-dom';
 
 export default function UserPage() {
   const { categoryId } = useParams();
-  const { data, error, isFetching, refetch } = useGetOwnerOrderQuery(categoryId);
+  const { data, error, isFetching} = useGetOwnerOrderQuery(categoryId);
   const [sortedData, setSortedData] = useState();
   useEffect(() => {
     if (data) {
-      refetch();
       const dataForSort = [...data?.OrderFind];
       setSortedData(dataForSort?.sort((a, b) => b.createdAt - a.createdAt));
     }

+ 97 - 0
js21 react/my-react-app/src/pages/admin/GoodsPage.js

@@ -0,0 +1,97 @@
+import { DeleteOutlineOutlined, Edit } from '@mui/icons-material';
+import { Button, Dialog, DialogActions, DialogContent, DialogContentText, IconButton, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow } from '@mui/material';
+import React, { useState } from 'react';
+import { useDispatch } from 'react-redux';
+import { Link } from 'react-router-dom';
+import { useGetGoodsQuery } from '../../api/api';
+import LinkButton from '../../components/LinkButton';
+import Loader from '../../components/Loader';
+
+function GoodsPage() {
+  const { data, isFetching } = useGetGoodsQuery();
+  const [open, setOpen] = useState(false);
+  const [page, setPage] = useState(0);
+  const [rowsPerPage, setRowsPerPage] = useState(10);
+  const [selectedId, setSelectedId] = useState('');
+  const dispatch = useDispatch();
+
+  const handleChangePage = (event, newPage) => {
+    setPage(newPage);
+  };
+
+  const handleChangeRowsPerPage = (event) => {
+    setRowsPerPage(parseInt(event.target.value, 10));
+    setPage(0);
+  };
+
+  const openModalWindow = (goodId) => {
+    setSelectedId(goodId);
+    setOpen(true);
+  };
+
+  const closeModalWindow = () => {
+    setSelectedId('');
+    setOpen(false);
+  };
+  return (
+    <>
+      {isFetching ? <Loader /> :
+        <>
+          <LinkButton to={'/admin/good'} text={'Create good'} />
+          <Paper sx={{ m: 1 }}>
+            <TableContainer>
+              <Table>
+                <TableHead>
+                  <TableRow>
+                    <TableCell>ID</TableCell>
+                    <TableCell>Good</TableCell>
+                    <TableCell>Category</TableCell>
+                    <TableCell align='right'></TableCell>
+                    <TableCell align='right'></TableCell>
+                  </TableRow>
+                </TableHead>
+                <TableBody>
+                  {data.GoodFind?.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)?.map(good =>
+                    <TableRow key={good?._id}>
+                      <TableCell>{good?._id}</TableCell>
+                      <TableCell>{good?.name}</TableCell>
+                      <TableCell>{good?.categories?.map(category => category?.name)}</TableCell>
+                      <TableCell align='right'>
+                        <IconButton component={Link} to={`/admin/good/${good?._id}`}><Edit /></IconButton>
+                      </TableCell>
+                      <TableCell align='right'>
+                        <IconButton onClick={() => openModalWindow(good?._id)}><DeleteOutlineOutlined /></IconButton>
+                      </TableCell>
+                    </TableRow>
+                  )}
+                  <Dialog
+                    open={open}
+                    onClose={closeModalWindow}
+                  >
+                    <DialogContent>
+                      <DialogContentText>Do you confirm good deletion?</DialogContentText>
+                    </DialogContent>
+                    <DialogActions>
+                      <Button onClick={''}>Yes</Button>
+                      <Button onClick={closeModalWindow}>No</Button>
+                    </DialogActions>
+                  </Dialog>
+                </TableBody>
+              </Table>
+            </TableContainer>
+            <TablePagination
+              rowsPerPageOptions={[10, 20, 30]}
+              component="div"
+              count={data?.GoodFind?.length}
+              rowsPerPage={rowsPerPage}
+              page={page}
+              onPageChange={handleChangePage}
+              onRowsPerPageChange={handleChangeRowsPerPage} />
+          </Paper>
+        </>
+      }
+    </>
+  )
+}
+
+export default GoodsPage;

+ 117 - 0
js21 react/my-react-app/src/pages/admin/OrdersPage.js

@@ -0,0 +1,117 @@
+import { Collapse, IconButton, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow } from '@mui/material';
+import React, { useEffect, useState } from 'react';
+import { useGetOrderCountQuery, useGetOwnerOrderQuery } from '../../api/api';
+import Loader from '../../components/Loader';
+import { getDateString } from '../../functions/getDataString';
+import { KeyboardArrowDown, KeyboardArrowUp } from '@mui/icons-material';
+import { Box } from '@mui/system';
+
+function OrdersPage() {
+  const [page, setPage] = useState(0);
+  const [rowsPerPage, setRowsPerPage] = useState(50);
+  const { data: orderCount } = useGetOrderCountQuery();
+  const { data, isFetching, refetch } = useGetOwnerOrderQuery({ skip: page * rowsPerPage, limit: rowsPerPage });
+
+
+  useEffect(() => {
+    refetch();
+  }, [page || rowsPerPage]);
+
+  const handleChangePage = (event, newPage) => {
+    setPage(newPage);
+  };
+
+  const handleChangeRowsPerPage = (event) => {
+    setRowsPerPage(parseInt(event.target.value));
+    setPage(0);
+  };
+
+  const Row = ({id, login, total, createdAt, orderGoods}) => {
+    const [open, setOpen] = useState(false);
+    return (
+      <>
+        <TableRow>
+          <TableCell>
+            <IconButton
+              size="small"
+              onClick={() => setOpen(!open)}
+            >
+              {open ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
+            </IconButton>
+          </TableCell>
+          <TableCell>{id}</TableCell>
+          <TableCell>{login}</TableCell>
+          <TableCell>{total}</TableCell>
+          <TableCell>{getDateString(createdAt)}</TableCell>
+        </TableRow>
+        <TableRow>
+          <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
+            <Collapse in={open} timeout="auto" unmountOnExit>
+              <Box sx={{ margin: 1 }}>
+                <Table size="small">
+                  <TableHead>
+                    <TableCell >Good</TableCell>
+                    <TableCell >Price</TableCell>
+                    <TableCell >Count</TableCell>
+                  </TableHead>
+                  <TableBody>
+                    {orderGoods?.map(good => 
+                      <TableRow key={good?.good?._id}>
+                        <TableCell >{good.good?.name}</TableCell>
+                        <TableCell >{good?.price}</TableCell>
+                        <TableCell >{good?.count}</TableCell>
+                      </TableRow>)}
+                  </TableBody>
+                </Table>
+              </Box>
+            </Collapse>
+          </TableCell>
+        </TableRow>
+      </>
+    )
+  }
+
+
+  return (
+    <>
+      {isFetching ? <Loader /> :
+        <Paper>
+          <TableContainer>
+            <Table>
+              <TableHead>
+                <TableRow>
+                  <TableCell />
+                  <TableCell>ID</TableCell>
+                  <TableCell>Owner</TableCell>
+                  <TableCell>Total</TableCell>
+                  <TableCell>Created at</TableCell>
+                </TableRow>
+              </TableHead>
+              <TableBody>
+                {data?.OrderFind?.map(order =>
+                  <Row 
+                  key={order._id}
+                  id={order?._id}
+                  login={order?.owner?.login}
+                  total={order?.total}
+                  createdAt={order?.createdAt}
+                  orderGoods={order?.orderGoods}/>
+                )}
+              </TableBody>
+            </Table>
+          </TableContainer>
+          <TablePagination
+            rowsPerPageOptions={[50, 100, 200]}
+            component="div"
+            count={orderCount?.OrderCount}
+            rowsPerPage={rowsPerPage}
+            page={page}
+            onPageChange={handleChangePage}
+            onRowsPerPageChange={handleChangeRowsPerPage} />
+        </Paper>
+      }
+    </>
+  )
+}
+
+export default OrdersPage;

+ 11 - 14
js21 react/my-react-app/src/pages/admin/UsersPage.js

@@ -1,27 +1,25 @@
 import { Paper, Table, TableBody, TableCell, TableContainer, TableHead, TablePagination, TableRow } from '@mui/material';
 import React, { useEffect, useState } from 'react';
-import { useGetUsersQuery } from '../../api/api';
+import { useGetUserCountQuery, useGetUsersQuery } from '../../api/api';
 import Loader from '../../components/Loader';
 import { getDateString } from '../../functions/getDataString';
 
 function UsersPage() {
-  const { data, isFetching } = useGetUsersQuery();
-  const [sortedData, setSortedData] = useState();
   const [page, setPage] = useState(0);
-  const [rowsPerPage, setRowsPerPage] = useState(10);
+  const [rowsPerPage, setRowsPerPage] = useState(50);
+  const { data: userCount } = useGetUserCountQuery();
+  const { data, isFetching, refetch } = useGetUsersQuery({skip: page * rowsPerPage, limit: rowsPerPage});
+  
   useEffect(() => {
-    if (data) {
-      const dataForSort = [...data?.UserFind];
-      setSortedData(dataForSort?.sort((a, b) => b.createdAt - a.createdAt));
-    }
-  }, [data]);
+    refetch();
+  }, [page || rowsPerPage]);
 
   const handleChangePage = (event, newPage) => {
     setPage(newPage);
   };
 
   const handleChangeRowsPerPage = (event) => {
-    setRowsPerPage(parseInt(event.target.value, 10));
+    setRowsPerPage(parseInt(event.target.value));
     setPage(0);
   };
   return (
@@ -38,7 +36,7 @@ function UsersPage() {
                 </TableRow>
               </TableHead>
               <TableBody>
-                {sortedData?.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)?.map(user =>
+                {data?.UserFind?.map(user =>
                   <TableRow key={user._id}>
                     <TableCell>{user._id}</TableCell>
                     <TableCell>{user.login}</TableCell>
@@ -49,9 +47,9 @@ function UsersPage() {
             </Table>
           </TableContainer>
           <TablePagination
-            rowsPerPageOptions={[10, 20, 30]}
+            rowsPerPageOptions={[50, 100, 200]}
             component="div"
-            count={sortedData?.length}
+            count={userCount?.UserCount}
             rowsPerPage={rowsPerPage}
             page={page}
             onPageChange={handleChangePage}
@@ -59,7 +57,6 @@ function UsersPage() {
         </Paper>
       }
     </>
-
   )
 }