announcement done
Some checks failed
NPM Installation / build (16.x, ubuntu-latest) (push) Has been cancelled
NPM Installation / build (16.x, windows-latest) (push) Has been cancelled
NPM Installation / build (17.x, ubuntu-latest) (push) Has been cancelled
NPM Installation / build (17.x, windows-latest) (push) Has been cancelled
NPM Installation / build (18.x, ubuntu-latest) (push) Has been cancelled
NPM Installation / build (18.x, windows-latest) (push) Has been cancelled
Some checks failed
NPM Installation / build (16.x, ubuntu-latest) (push) Has been cancelled
NPM Installation / build (16.x, windows-latest) (push) Has been cancelled
NPM Installation / build (17.x, ubuntu-latest) (push) Has been cancelled
NPM Installation / build (17.x, windows-latest) (push) Has been cancelled
NPM Installation / build (18.x, ubuntu-latest) (push) Has been cancelled
NPM Installation / build (18.x, windows-latest) (push) Has been cancelled
This commit is contained in:
parent
efb60cc3c1
commit
b96f7832e2
183
src/_nav.js
183
src/_nav.js
@ -16,6 +16,7 @@ import {
|
||||
cilShare,
|
||||
cilSpeedometer,
|
||||
cilStar,
|
||||
cilStorage,
|
||||
} from '@coreui/icons'
|
||||
import { CNavGroup, CNavItem, CNavTitle } from '@coreui/react'
|
||||
|
||||
@ -102,181 +103,17 @@ const _nav = [
|
||||
],
|
||||
},
|
||||
// {
|
||||
// component: CNavGroup,
|
||||
// name: 'Buttons',
|
||||
// to: '/buttons',
|
||||
// icon: <CIcon icon={cilCursor} customClassName="nav-icon" />,
|
||||
// items: [
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Buttons',
|
||||
// to: '/buttons/buttons',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Buttons groups',
|
||||
// to: '/buttons/button-groups',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Dropdowns',
|
||||
// to: '/buttons/dropdowns',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// component: CNavGroup,
|
||||
// name: 'Forms',
|
||||
// icon: <CIcon icon={cilNotes} customClassName="nav-icon" />,
|
||||
// items: [
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Form Control',
|
||||
// to: '/forms/form-control',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Select',
|
||||
// to: '/forms/select',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Checks & Radios',
|
||||
// to: '/forms/checks-radios',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Range',
|
||||
// to: '/forms/range',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Input Group',
|
||||
// to: '/forms/input-group',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Floating Labels',
|
||||
// to: '/forms/floating-labels',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Layout',
|
||||
// to: '/forms/layout',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Validation',
|
||||
// to: '/forms/validation',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Charts',
|
||||
// to: '/charts',
|
||||
// icon: <CIcon icon={cilChartPie} customClassName="nav-icon" />,
|
||||
// },
|
||||
// {
|
||||
// component: CNavGroup,
|
||||
// name: 'Icons',
|
||||
// icon: <CIcon icon={cilStar} customClassName="nav-icon" />,
|
||||
// items: [
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'CoreUI Free',
|
||||
// to: '/icons/coreui-icons',
|
||||
// badge: {
|
||||
// color: 'success',
|
||||
// text: 'NEW',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'CoreUI Flags',
|
||||
// to: '/icons/flags',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'CoreUI Brands',
|
||||
// to: '/icons/brands',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// component: CNavGroup,
|
||||
// name: 'Notifications',
|
||||
// icon: <CIcon icon={cilBell} customClassName="nav-icon" />,
|
||||
// items: [
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Alerts',
|
||||
// to: '/notifications/alerts',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Badges',
|
||||
// to: '/notifications/badges',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Modal',
|
||||
// to: '/notifications/modals',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Toasts',
|
||||
// to: '/notifications/toasts',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Widgets',
|
||||
// to: '/widgets',
|
||||
// icon: <CIcon icon={cilCalculator} customClassName="nav-icon" />,
|
||||
// badge: {
|
||||
// color: 'info',
|
||||
// text: 'NEW',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// component: CNavTitle,
|
||||
// name: 'Extras',
|
||||
// },
|
||||
// {
|
||||
// component: CNavGroup,
|
||||
// name: 'Pages',
|
||||
// icon: <CIcon icon={cilStar} customClassName="nav-icon" />,
|
||||
// items: [
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Login',
|
||||
// to: '/login',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Register',
|
||||
// to: '/register',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Error 404',
|
||||
// to: '/404',
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Error 500',
|
||||
// to: '/500',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// component: CNavItem,
|
||||
// name: 'Docs',
|
||||
// href: 'https://coreui.io/react/docs/templates/installation/',
|
||||
// icon: <CIcon icon={cilDescription} customClassName="nav-icon" />,
|
||||
// name: 'Stock',
|
||||
// to: '/stock',
|
||||
// icon: <CIcon icon={cilStorage} customClassName="nav-icon" />,
|
||||
// },
|
||||
{
|
||||
component: CNavItem,
|
||||
name: 'Announcements',
|
||||
to: '/announcemnets',
|
||||
icon: <CIcon icon={cilStorage} customClassName="nav-icon" />,
|
||||
},
|
||||
]
|
||||
|
||||
export default _nav
|
||||
|
@ -14,6 +14,8 @@ import ProcessingInvoices from './views/pages/rdOrders/processingInvoices'
|
||||
import ViewInvoices from './views/pages/rdOrders/invoiceView'
|
||||
import DispatchedInvoices from './views/pages/rdOrders/dispatchedInvoices'
|
||||
import DeliveredInvoices from './views/pages/rdOrders/deliveredInvoices'
|
||||
import StockTable from './views/pages/stock/stockTable'
|
||||
import Announcements from './views/pages/announcements/announcements'
|
||||
|
||||
const Dashboard = React.lazy(() => import('./views/dashboard/Dashboard'))
|
||||
const Shop = React.lazy(() => import('./views/shops/Shop'))
|
||||
@ -50,6 +52,8 @@ const routes = [
|
||||
{ path: '/change-password', name: 'Change password', element: ChangePassword },
|
||||
|
||||
{ path: '/cart', name: 'Cart', element: Cart },
|
||||
{ path: '/stock', name: 'Stock', element: StockTable },
|
||||
{ path: '/announcemnets', name: 'Announcement', element: Announcements },
|
||||
]
|
||||
|
||||
export default routes
|
||||
|
@ -42,6 +42,7 @@ const Dashboard = () => {
|
||||
cancelled: '#f44336', // Red
|
||||
processing: '#ff9800', // Orange
|
||||
delivered: '#9c27b0', // Purple
|
||||
pending: '#56F000 ',
|
||||
}
|
||||
const statusIcons = {
|
||||
new: <AddShoppingCartIcon sx={{ fontSize: 50, color: '#fff' }} />,
|
||||
|
151
src/views/pages/announcements/announcements.js
Normal file
151
src/views/pages/announcements/announcements.js
Normal file
@ -0,0 +1,151 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TablePagination,
|
||||
Paper,
|
||||
Button,
|
||||
Typography,
|
||||
Skeleton,
|
||||
Box,
|
||||
} from '@mui/material'
|
||||
import axios from 'axios'
|
||||
// import { Box } from '@material-ui/core'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { isAutheticated } from '../../../auth'
|
||||
import Axios from '../../../axios'
|
||||
|
||||
const Announcements = () => {
|
||||
const [announcements, setAnnouncements] = useState([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [page, setPage] = useState(0)
|
||||
const [rowsPerPage, setRowsPerPage] = useState(5)
|
||||
const [totalAnnouncements, setTotalAnnouncements] = useState(0)
|
||||
const token = isAutheticated()
|
||||
|
||||
const fetchAnnouncements = async (page, rowsPerPage) => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await Axios.get('/api/announcement/PDs', {
|
||||
params: {
|
||||
page: page + 1, // backend uses 1-based index
|
||||
rowsPerPage,
|
||||
},
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`, // if token is necessary for authorization
|
||||
},
|
||||
})
|
||||
console.log(response, 'this is the response ')
|
||||
const { announcements, totalAnnouncements } = response.data
|
||||
setAnnouncements(announcements)
|
||||
setTotalAnnouncements(totalAnnouncements)
|
||||
} catch (error) {
|
||||
console.error('Error fetching announcements', error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchAnnouncements(page, rowsPerPage)
|
||||
}, [page, rowsPerPage])
|
||||
|
||||
const handleChangePage = (event, newPage) => {
|
||||
setPage(newPage)
|
||||
}
|
||||
|
||||
const handleChangeRowsPerPage = (event) => {
|
||||
setRowsPerPage(parseInt(event.target.value, 10))
|
||||
setPage(0) // Reset page to 0 when changing rows per page
|
||||
}
|
||||
|
||||
const formatAMPM = (dateString) => {
|
||||
const date = new Date(dateString)
|
||||
let hours = date.getHours()
|
||||
let minutes = date.getMinutes()
|
||||
const ampm = hours >= 12 ? 'PM' : 'AM'
|
||||
hours = hours % 12 || 12
|
||||
minutes = minutes < 10 ? '0' + minutes : minutes
|
||||
return `${hours}:${minutes} ${ampm}`
|
||||
}
|
||||
const navigate = useNavigate()
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box display={'flex'} mb={2}>
|
||||
<Typography flex={1} textAlign={'center'} fontWeight={'bold'} variant="h4">
|
||||
Announcements
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead sx={{ fontWeight: 'bold' }}>
|
||||
<TableRow>
|
||||
<TableCell>ID</TableCell>
|
||||
<TableCell>Time</TableCell>
|
||||
{/* <TableCell>Sent to</TableCell> */}
|
||||
<TableCell>Message</TableCell>
|
||||
{/* <TableCell>Action</TableCell> */}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{loading ? (
|
||||
Array.from(new Array(rowsPerPage)).map((_, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell colSpan={5}>
|
||||
<Skeleton height={40} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : announcements.length > 0 ? (
|
||||
announcements.map((announcement) => (
|
||||
<TableRow key={announcement._id}>
|
||||
<TableCell>{announcement.uniqueId}</TableCell>
|
||||
<TableCell>
|
||||
{new Date(announcement.createdAt).toDateString()}
|
||||
<span>, {formatAMPM(announcement.createdAt)}</span>
|
||||
</TableCell>
|
||||
{/* <TableCell>{announcement.sentTo.join(', ')}</TableCell> */}
|
||||
<TableCell>{announcement.message}</TableCell>
|
||||
{/* <TableCell>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() =>
|
||||
alert(`Viewing announcement ${announcement.id}`)
|
||||
}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
</TableCell> */}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={5} align="center">
|
||||
<Typography variant="body1">Data not found</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[5, 10, 25]}
|
||||
component="div"
|
||||
count={totalAnnouncements}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default Announcements
|
@ -13,6 +13,8 @@ import {
|
||||
FormHelperText,
|
||||
} from '@mui/material'
|
||||
import React, { useState } from 'react'
|
||||
import Axios from '../../../axios'
|
||||
import { isAutheticated } from '../../../auth'
|
||||
|
||||
const AddressAndPayment = ({
|
||||
billTo,
|
||||
@ -22,9 +24,11 @@ const AddressAndPayment = ({
|
||||
paymentMode,
|
||||
setPaymentMode,
|
||||
handleTabChange,
|
||||
address,
|
||||
}) => {
|
||||
const [billToError, setBillToError] = useState(false)
|
||||
const [shipToError, setShipToError] = useState(false)
|
||||
|
||||
const [paymentModeError, setPaymentModeError] = useState(false)
|
||||
|
||||
const handleReviewOrderClick = (e) => {
|
||||
@ -59,6 +63,10 @@ const AddressAndPayment = ({
|
||||
handleTabChange(e, 2)
|
||||
}
|
||||
}
|
||||
const formatAddress = (address) => {
|
||||
const { street, city, state, postalCode } = address
|
||||
return `${street}, ${city}, ${state} - ${postalCode}`
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -79,15 +87,12 @@ const AddressAndPayment = ({
|
||||
label="Bill Address"
|
||||
onChange={(e) => setBillTo(e.target.value)}
|
||||
>
|
||||
<MenuItem value={'123, MG Road, Bengaluru, Karnataka - 560001'}>
|
||||
123, MG Road, Bengaluru, Karnataka - 560001
|
||||
</MenuItem>
|
||||
<MenuItem value={'456, Park Street, Kolkata, West Bengal - 700016'}>
|
||||
456, Park Street, Kolkata, West Bengal - 700016
|
||||
</MenuItem>
|
||||
<MenuItem value={'789, Connaught Place, New Delhi - 110001'}>
|
||||
789, Connaught Place, New Delhi - 110001
|
||||
{address &&
|
||||
address.map((address) => (
|
||||
<MenuItem key={address._id} value={formatAddress(address)}>
|
||||
{formatAddress(address)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{billToError && <FormHelperText>Bill Address is required</FormHelperText>}
|
||||
</FormControl>
|
||||
@ -103,16 +108,14 @@ const AddressAndPayment = ({
|
||||
label="Ship Address"
|
||||
onChange={(e) => setShipTo(e.target.value)}
|
||||
>
|
||||
<MenuItem value={'123, MG Road, Bengaluru, Karnataka - 560001'}>
|
||||
123, MG Road, Bengaluru, Karnataka - 560001
|
||||
</MenuItem>
|
||||
<MenuItem value={'456, Park Street, Kolkata, West Bengal - 700016'}>
|
||||
456, Park Street, Kolkata, West Bengal - 700016
|
||||
</MenuItem>
|
||||
<MenuItem value={'789, Connaught Place, New Delhi - 110001'}>
|
||||
789, Connaught Place, New Delhi - 110001
|
||||
{address &&
|
||||
address.map((address) => (
|
||||
<MenuItem key={address._id} value={formatAddress(address)}>
|
||||
{formatAddress(address)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
{shipToError && <FormHelperText>Ship Address is required</FormHelperText>}
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
@ -20,6 +20,8 @@ import {
|
||||
selectCartItems,
|
||||
selectCartSubtotal,
|
||||
} from '../../../redux-store/CartStore/ducs'
|
||||
import { isAutheticated } from '../../../auth'
|
||||
import Axios from '../../../axios'
|
||||
|
||||
const TabItem = ({ label, active, complete, onClick, reference, stepNumber }) => (
|
||||
<Box
|
||||
@ -107,9 +109,29 @@ const Cart = () => {
|
||||
const dispatch = useDispatch()
|
||||
const [paymentMode, setPaymentMode] = useState('')
|
||||
const cartItems = useSelector(selectCartItems)
|
||||
const totalItemCount = useSelector(selectCartItemCount)
|
||||
const cartSubtotal = useSelector(selectCartSubtotal)
|
||||
|
||||
const [address, setAddress] = useState([])
|
||||
const token = isAutheticated()
|
||||
const [value, setValue] = useState(0)
|
||||
|
||||
const getAddress = async () => {
|
||||
try {
|
||||
const res = await Axios.get('/api/shipping/address/user/address/', {
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
console.log(res)
|
||||
setAddress(res?.data?.UserShippingAddress)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
getAddress()
|
||||
}, [])
|
||||
const handleTabChange = (event, newValue) => {
|
||||
if (value === 3 && newValue !== 3) {
|
||||
setPaymentMode('')
|
||||
@ -216,6 +238,7 @@ const Cart = () => {
|
||||
paymentMode={paymentMode}
|
||||
setPaymentMode={setPaymentMode}
|
||||
handleTabChange={handleTabChange}
|
||||
address={address}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
@ -63,6 +63,7 @@ const OrderDetailsDialog = ({ open, onClose, order, onSubmit }) => {
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{order?.orderItem.map((item, index) => {
|
||||
if (item.remainingQuantity > 0) {
|
||||
const subtotal = item.price * item.remainingQuantity
|
||||
const gstAmount = ((item.GST * item.price) / 100) * item.remainingQuantity
|
||||
const totalWithGST = subtotal + gstAmount
|
||||
@ -100,6 +101,7 @@ const OrderDetailsDialog = ({ open, onClose, order, onSubmit }) => {
|
||||
<TableCell align="right">₹{totalWithGST}</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
}
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
@ -119,13 +119,13 @@ const ViewOrders = () => {
|
||||
}
|
||||
} else if (orderStatus === 'processing') {
|
||||
const processingOrderInvoice = order?.orderItem
|
||||
.filter((item) => item.remainingQuantity > 0) // Only include items with remainingQuantity > 0
|
||||
.filter((item) => item.remainingQuantity > 0)
|
||||
.map((item) => ({
|
||||
...item,
|
||||
productId: item.productId,
|
||||
processquantity: item.remainingQuantity, // Add processquantity only for items with remainingQuantity > 0
|
||||
processquantity: item.remainingQuantity,
|
||||
}))
|
||||
console.log(processingOrderInvoice)
|
||||
console.log(processingOrderInvoice, 'process invoices', order._id)
|
||||
|
||||
const cancellationRes = await Axios.post(
|
||||
`/api/pd-process-order`,
|
||||
|
267
src/views/pages/stock/stockTable.js
Normal file
267
src/views/pages/stock/stockTable.js
Normal file
@ -0,0 +1,267 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import {
|
||||
TableContainer,
|
||||
Table,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableBody,
|
||||
Paper,
|
||||
Typography,
|
||||
TablePagination,
|
||||
Skeleton,
|
||||
TextField,
|
||||
MenuItem,
|
||||
Select,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Grid,
|
||||
Button,
|
||||
} from '@mui/material'
|
||||
import axios from 'axios'
|
||||
import Axios from '../../../axios'
|
||||
|
||||
function StockTable({ apiEndpoint, totalProducts }) {
|
||||
const [stocks, setStocks] = useState([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [page, setPage] = useState(0)
|
||||
const [rowsPerPage, setRowsPerPage] = useState(5)
|
||||
const [category, setCategory] = useState('')
|
||||
const [brand, setBrand] = useState('')
|
||||
const [productName, setProductName] = useState('')
|
||||
const [isInitialStockMode, setIsInitialStockMode] = useState(false)
|
||||
const [initialStock, setInitialStock] = useState([])
|
||||
const [products, setProducts] = useState()
|
||||
|
||||
console.log(initialStock, 'initial stock ')
|
||||
|
||||
const fetchProducts = async () => {
|
||||
try {
|
||||
const response = await Axios.get('/api/product/getAll/user/')
|
||||
setProducts(response.data?.products || [])
|
||||
console.log(response, 'resp of products ')
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
const response = await Axios.get('/api/product/getAll/user/')
|
||||
setProducts(response.data?.products || [])
|
||||
}
|
||||
// Fetch Products from Backend API
|
||||
const fetchStocks = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await axios.get(apiEndpoint, {
|
||||
params: { category, brand, productName, page, limit: rowsPerPage },
|
||||
})
|
||||
setStocks(response.data.stocks)
|
||||
} catch (error) {
|
||||
console.error('Error fetching products:', error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
fetchProducts()
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
fetchStocks()
|
||||
}, [category, brand, productName, page, rowsPerPage])
|
||||
|
||||
// Pagination Handlers
|
||||
const handleChangePage = (event, newPage) => setPage(newPage)
|
||||
const handleChangeRowsPerPage = (event) => {
|
||||
setRowsPerPage(parseInt(event.target.value, 10))
|
||||
setPage(0)
|
||||
}
|
||||
|
||||
const handleStockChange = (productId, value) => {
|
||||
setInitialStock((prevStock) => {
|
||||
const stockExists = prevStock.find((item) => item.productId === productId)
|
||||
|
||||
if (stockExists) {
|
||||
// Update the existing stock entry
|
||||
return prevStock.map((item) =>
|
||||
item.productId === productId ? { ...item, stock: value } : item,
|
||||
)
|
||||
} else {
|
||||
// Add a new stock entry
|
||||
return [...prevStock, { productId, stock: value }]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleSubmitInitialStock = async () => {
|
||||
try {
|
||||
await axios.post(`${apiEndpoint}/initial-stock`, { stock: initialStock })
|
||||
setIsInitialStockMode(false)
|
||||
fetchProducts()
|
||||
} catch (error) {
|
||||
console.error('Error adding initial stock:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const formatDateTime = (dateString) => {
|
||||
const date = new Date(dateString)
|
||||
return `${date.toDateString()}, ${formatAMPM(date)}`
|
||||
}
|
||||
|
||||
const formatAMPM = (date) => {
|
||||
let hours = date.getHours()
|
||||
const minutes = date.getMinutes()
|
||||
const ampm = hours >= 12 ? 'PM' : 'AM'
|
||||
hours = hours % 12 || 12
|
||||
return `${hours}:${minutes < 10 ? '0' + minutes : minutes} ${ampm}`
|
||||
}
|
||||
|
||||
// Check if stock exists
|
||||
const stockExists = stocks.length > 0
|
||||
|
||||
return (
|
||||
<div style={{ background: '#fff', padding: '1rem' }}>
|
||||
{!stockExists && !isInitialStockMode ? (
|
||||
<Button variant="contained" onClick={() => setIsInitialStockMode(true)}>
|
||||
Add Initial Stock
|
||||
</Button>
|
||||
) : isInitialStockMode ? (
|
||||
<>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Add Initial Stock
|
||||
</Typography>
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Product Name</TableCell>
|
||||
<TableCell>SKU</TableCell>
|
||||
<TableCell>Stock</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{products.map((product) => (
|
||||
<TableRow key={product._id}>
|
||||
<TableCell>{product.name}</TableCell>
|
||||
<TableCell>{product.SKU}</TableCell>
|
||||
<TableCell>
|
||||
<TextField
|
||||
type="number"
|
||||
value={
|
||||
initialStock.find((item) => item.productId === product._id)?.stock || ''
|
||||
}
|
||||
onChange={(e) => handleStockChange(product._id, e.target.value)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSubmitInitialStock}
|
||||
sx={{ marginTop: 2 }}
|
||||
>
|
||||
Submit Stock
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{/* Filter Controls */}
|
||||
<Grid container spacing={2} sx={{ marginBottom: 2 }}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Category</InputLabel>
|
||||
<Select
|
||||
value={category}
|
||||
onChange={(e) => setCategory(e.target.value)}
|
||||
label="Category"
|
||||
>
|
||||
<MenuItem value="">All</MenuItem>
|
||||
<MenuItem value="Electronics">Electronics</MenuItem>
|
||||
<MenuItem value="Clothing">Clothing</MenuItem>
|
||||
<MenuItem value="Furniture">Furniture</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Brand</InputLabel>
|
||||
<Select value={brand} onChange={(e) => setBrand(e.target.value)} label="Brand">
|
||||
<MenuItem value="">All</MenuItem>
|
||||
<MenuItem value="Apple">Apple</MenuItem>
|
||||
<MenuItem value="Nike">Nike</MenuItem>
|
||||
<MenuItem value="Ikea">Ikea</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Product Name"
|
||||
value={productName}
|
||||
onChange={(e) => setProductName(e.target.value)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Products Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Product Name</TableCell>
|
||||
<TableCell>SKU</TableCell>
|
||||
<TableCell>Category</TableCell>
|
||||
<TableCell>Brand</TableCell>
|
||||
<TableCell>Added On</TableCell>
|
||||
<TableCell>Price</TableCell>
|
||||
<TableCell>Stock</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{loading ? (
|
||||
Array.from(new Array(rowsPerPage)).map((_, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell colSpan={7}>
|
||||
<Skeleton height={40} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : stocks.length > 0 ? (
|
||||
products.map((product) => (
|
||||
<TableRow key={product._id}>
|
||||
<TableCell>{product.name}</TableCell>
|
||||
<TableCell>{product.sku}</TableCell>
|
||||
<TableCell>{product.categoryName}</TableCell>
|
||||
<TableCell>{product.brandName}</TableCell>
|
||||
<TableCell>{formatDateTime(product.addedOn)}</TableCell>
|
||||
<TableCell>{product.price.toFixed(2)}</TableCell>
|
||||
<TableCell>{product.stock}</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={7} align="center">
|
||||
<Typography variant="body1">Data not found</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[5, 10, 25]}
|
||||
component="div"
|
||||
count={totalProducts}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/>
|
||||
</TableContainer>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StockTable
|
Loading…
Reference in New Issue
Block a user