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

This commit is contained in:
ROSHAN GARG 2024-10-18 12:04:00 +05:30
parent efb60cc3c1
commit b96f7832e2
9 changed files with 520 additions and 232 deletions

View File

@ -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

View File

@ -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

View File

@ -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' }} />,

View 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

View File

@ -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>

View File

@ -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>
)}

View File

@ -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>

View File

@ -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`,

View 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