update api done
This commit is contained in:
parent
490314ef24
commit
61da636a2d
@ -40,6 +40,7 @@
|
|||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"core-js": "^3.37.1",
|
"core-js": "^3.37.1",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
|
"jwt-decode": "^4.0.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
@ -2,15 +2,38 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { jwtDecode } from 'jwt-decode'
|
||||||
|
|
||||||
|
const isTokenExpired = (token) => {
|
||||||
|
try {
|
||||||
|
const decodedToken = jwtDecode(token)
|
||||||
|
console.log('Decoded Token:', decodedToken) // Debugging
|
||||||
|
const currentTime = Date.now() / 1000
|
||||||
|
console.log('Current Time:', currentTime) // Debugging
|
||||||
|
console.log('Token Expiration Time:', decodedToken.exp) // Debugging
|
||||||
|
return decodedToken.exp < currentTime
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error decoding token:', error) // Debugging
|
||||||
|
return true // If there's an error decoding the token, consider it expired
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const ProtectedRoute = ({ element: Element }) => {
|
const ProtectedRoute = ({ element: Element }) => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
console.log('req came here ')
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!localStorage.getItem('authToken')) {
|
const checkToken = () => {
|
||||||
|
const token = localStorage.getItem('authToken')
|
||||||
|
console.log('Token:', token) // Debugging
|
||||||
|
if (!token || isTokenExpired(token)) {
|
||||||
|
console.log('Token is expired or not present, redirecting to login')
|
||||||
navigate('/login')
|
navigate('/login')
|
||||||
|
} else {
|
||||||
|
console.log('Token is valid')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkToken()
|
||||||
}, [navigate])
|
}, [navigate])
|
||||||
|
|
||||||
return <Element />
|
return <Element />
|
||||||
|
@ -14,7 +14,7 @@ const routes = [
|
|||||||
{ path: '/shop', name: 'Shop', element: Shop },
|
{ path: '/shop', name: 'Shop', element: Shop },
|
||||||
{ path: '/order', name: 'Order', element: Order },
|
{ path: '/order', name: 'Order', element: Order },
|
||||||
// KYC
|
// KYC
|
||||||
{ path: '/kyc', name: 'Kyc', element: Kyc },
|
{ path: '/kyc', name: 'KYC', element: Kyc },
|
||||||
{ path: '/kyc/details/:id', name: 'Kyc details', element: KycDetails },
|
{ path: '/kyc/details/:id', name: 'Kyc details', element: KycDetails },
|
||||||
|
|
||||||
{ path: '/my-profile', name: 'Profile', element: MyProfile },
|
{ path: '/my-profile', name: 'Profile', element: MyProfile },
|
||||||
|
29
src/views/pages/Kyc/MessageList.js
Normal file
29
src/views/pages/Kyc/MessageList.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const MessageList = ({ messages }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{messages.map((msg, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
style={{
|
||||||
|
marginBottom: '10px',
|
||||||
|
padding: '10px',
|
||||||
|
borderRadius: '5px',
|
||||||
|
backgroundColor: msg.user === 'Principal Distributer' ? '#212631' : 'blue',
|
||||||
|
boxShadow: '0px 3px 6px rgba(0,0,0,0.1)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ fontWeight: 'bold', marginBottom: '5px', color: 'white' }}>{msg.user}</div>
|
||||||
|
<div style={{ fontWeight: 'bold', marginBottom: '5px', color: 'white' }}>
|
||||||
|
{msg.replyDate}
|
||||||
|
</div>
|
||||||
|
<div style={{ color: 'white' }}>{msg.message}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MessageList
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Table,
|
Table,
|
||||||
@ -10,34 +10,51 @@ import {
|
|||||||
Paper,
|
Paper,
|
||||||
TablePagination,
|
TablePagination,
|
||||||
Button,
|
Button,
|
||||||
IconButton,
|
|
||||||
Tooltip,
|
Tooltip,
|
||||||
|
Tabs,
|
||||||
|
Tab,
|
||||||
|
Modal,
|
||||||
|
TextField,
|
||||||
|
DialogActions,
|
||||||
|
Typography,
|
||||||
} from '@mui/material'
|
} from '@mui/material'
|
||||||
import { Visibility, ThumbUp, ThumbDown } from '@mui/icons-material'
|
|
||||||
import { format } from 'date-fns'
|
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import Axios from '../../../axios'
|
||||||
const generateRandomData = (numRows) => {
|
import { isAutheticated } from '../../../auth'
|
||||||
const statuses = ['New', 'Pending', 'Rejected', 'Approved']
|
import Swal from 'sweetalert2'
|
||||||
const data = []
|
|
||||||
|
|
||||||
for (let i = 0; i < numRows; i++) {
|
|
||||||
data.push({
|
|
||||||
id: i + 1,
|
|
||||||
tradeName: `Trade ${i + 1}`,
|
|
||||||
createdOn: new Date(),
|
|
||||||
status: statuses[Math.floor(Math.random() * statuses.length)],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
const Kyc = () => {
|
const Kyc = () => {
|
||||||
const [rows, setRows] = useState(generateRandomData(50))
|
const [rows, setRows] = useState([])
|
||||||
const [page, setPage] = useState(0)
|
const [page, setPage] = useState(0)
|
||||||
const [rowsPerPage, setRowsPerPage] = useState(5)
|
const [rowsPerPage, setRowsPerPage] = useState(10)
|
||||||
|
const [tabIndex, setTabIndex] = useState(0)
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [openModal, setOpenModal] = useState(false)
|
||||||
|
const [openModal2, setOpenModal2] = useState(false)
|
||||||
|
const [rejectionReason, setRejectionReason] = useState('')
|
||||||
|
const [selectedRowId, setSelectedRowId] = useState(null)
|
||||||
|
const [selectedRowId2, setSelectedRowId2] = useState(null)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const token = isAutheticated()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await Axios.get('/api/kyc/getAll/', {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
console.log(response)
|
||||||
|
setRows(response.data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching data: ', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData()
|
||||||
|
}, [])
|
||||||
|
|
||||||
const handleChangePage = (event, newPage) => {
|
const handleChangePage = (event, newPage) => {
|
||||||
setPage(newPage)
|
setPage(newPage)
|
||||||
@ -48,13 +65,124 @@ const Kyc = () => {
|
|||||||
setPage(0)
|
setPage(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// const handleViewClick = (id) => {
|
const handleViewClick = (id) => {
|
||||||
// navigate(`/kyc/details/${id}`)
|
navigate(`/kyc/details/${id}`)
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
const handleTabChange = (event, newValue) => {
|
||||||
|
setTabIndex(newValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterRowsByStatus = (status) => {
|
||||||
|
return rows.filter((row) => row.status === status)
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredRows = filterRowsByStatus(
|
||||||
|
tabIndex === 0 ? 'new' : tabIndex === 1 ? 'approved' : 'reject',
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleRejectClick = async (id) => {
|
||||||
|
setSelectedRowId(id)
|
||||||
|
setOpenModal(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleApproveClick = async (id) => {
|
||||||
|
setSelectedRowId2(id)
|
||||||
|
setOpenModal2(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleApproveConfirm = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true)
|
||||||
|
console.log(selectedRowId2)
|
||||||
|
await Axios.patch(
|
||||||
|
`/api/kyc/update/${selectedRowId2}`,
|
||||||
|
{
|
||||||
|
status: 'approved',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
setRows((prevRows) =>
|
||||||
|
prevRows.map((row) => (row._id === selectedRowId2 ? { ...row, status: 'approved' } : row)),
|
||||||
|
)
|
||||||
|
setLoading(true)
|
||||||
|
Swal.fire('Success', 'Approved', 'success')
|
||||||
|
handleModalClose2()
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false)
|
||||||
|
console.error('Error approving KYC: ', error)
|
||||||
|
Swal.fire('Error!', error.message, 'error')
|
||||||
|
handleModalClose2()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleModalClose = () => {
|
||||||
|
setOpenModal(false)
|
||||||
|
setRejectionReason('')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleModalClose2 = () => {
|
||||||
|
setOpenModal2(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRejectionReasonChange = (event) => {
|
||||||
|
setRejectionReason(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRejectConfirm = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true)
|
||||||
|
await Axios.patch(
|
||||||
|
`/api/kyc/update/${selectedRowId}`,
|
||||||
|
{
|
||||||
|
status: 'reject',
|
||||||
|
rejectionReason,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
setRows((prevRows) =>
|
||||||
|
prevRows.map((row) => (row._id === selectedRowId ? { ...row, status: 'reject' } : row)),
|
||||||
|
)
|
||||||
|
setLoading(true)
|
||||||
|
Swal.fire('Success', 'Rejected', 'success')
|
||||||
|
handleModalClose()
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false)
|
||||||
|
console.error('Error rejecting KYC: ', error)
|
||||||
|
Swal.fire('Error!', error.message, 'error')
|
||||||
|
handleModalClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatAMPM = (date) => {
|
||||||
|
var hours = new Date(date).getHours()
|
||||||
|
var minutes = new Date(date).getMinutes()
|
||||||
|
var ampm = hours >= 12 ? 'PM' : 'AM'
|
||||||
|
hours = hours % 12
|
||||||
|
hours = hours ? hours : 12 // the hour '0' should be '12'
|
||||||
|
minutes = minutes < 10 ? '0' + minutes : minutes
|
||||||
|
var strTime = hours + ':' + minutes + ' ' + ampm
|
||||||
|
return strTime
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ width: '100%' }}>
|
<Box sx={{ width: '100%' }}>
|
||||||
<Paper sx={{ width: '100%', mb: 2 }}>
|
<Paper sx={{ width: '100%', mb: 2 }}>
|
||||||
|
<Tabs value={tabIndex} onChange={handleTabChange}>
|
||||||
|
<Tab label="New" sx={{ textTransform: 'unset' }} />
|
||||||
|
<Tab label="Approved" sx={{ textTransform: 'unset' }} />
|
||||||
|
<Tab label="Rejected" sx={{ textTransform: 'unset' }} />
|
||||||
|
</Tabs>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
@ -67,42 +195,52 @@ const Kyc = () => {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row) => (
|
{filteredRows
|
||||||
<TableRow key={row.id}>
|
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||||
<TableCell>{row.id}</TableCell>
|
.map((row) => (
|
||||||
<TableCell>{row.tradeName}</TableCell>
|
<TableRow key={row._id}>
|
||||||
<TableCell>{format(row.createdOn, 'yyyy-MM-dd HH:mm:ss')}</TableCell>
|
<TableCell>{row._id}</TableCell>
|
||||||
|
<TableCell>{row.trade_name}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{new Date(`${row?.createdAt}`).toDateString()}
|
||||||
|
<span> , {`${formatAMPM(row?.createdAt)}`}</span>
|
||||||
|
</TableCell>
|
||||||
<TableCell>{row.status}</TableCell>
|
<TableCell>{row.status}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Tooltip title="View">
|
<Tooltip title="View">
|
||||||
{/* <IconButton color="primary">
|
|
||||||
<Visibility />
|
|
||||||
</IconButton> */}
|
|
||||||
<Button
|
<Button
|
||||||
sx={{ mr: '1rem' }}
|
sx={{ mr: '1rem', textTransform: 'unset' }}
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
// onClick={() => handleViewClick(row.id)}
|
onClick={() => handleViewClick(row._id)}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{tabIndex === 0 && (
|
||||||
|
<>
|
||||||
<Tooltip title="Approve">
|
<Tooltip title="Approve">
|
||||||
{/* <IconButton color="success">
|
<Button
|
||||||
<ThumbUp />
|
sx={{ mr: '1rem', textTransform: 'unset' }}
|
||||||
</IconButton> */}
|
color="success"
|
||||||
<Button sx={{ mr: '1rem' }} color="success" variant="contained">
|
variant="contained"
|
||||||
|
onClick={() => handleApproveClick(row._id)}
|
||||||
|
>
|
||||||
Approve
|
Approve
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Reject">
|
<Tooltip title="Reject">
|
||||||
{/* <IconButton color="error">
|
<Button
|
||||||
<ThumbDown />
|
sx={{ mr: '1rem', textTransform: 'unset' }}
|
||||||
</IconButton> */}
|
color="error"
|
||||||
<Button sx={{ mr: '1rem' }} color="error" variant="contained">
|
variant="contained"
|
||||||
|
onClick={() => handleRejectClick(row._id)}
|
||||||
|
>
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
@ -110,17 +248,90 @@ const Kyc = () => {
|
|||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
<TablePagination
|
<TablePagination
|
||||||
rowsPerPageOptions={[5, 10, 25]}
|
rowsPerPageOptions={[10, 15, 25]}
|
||||||
component="div"
|
component="div"
|
||||||
count={rows.length}
|
count={filteredRows.length}
|
||||||
rowsPerPage={rowsPerPage}
|
rowsPerPage={rowsPerPage}
|
||||||
page={page}
|
page={page}
|
||||||
onPageChange={handleChangePage}
|
onPageChange={handleChangePage}
|
||||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
<Modal
|
||||||
|
open={openModal}
|
||||||
|
onClose={handleModalClose}
|
||||||
|
aria-labelledby="modal-modal-title"
|
||||||
|
aria-describedby="modal-modal-description"
|
||||||
|
>
|
||||||
|
<Box sx={{ ...modalStyle, width: 400 }}>
|
||||||
|
<h2 id="modal-modal-title">Rejection Reason</h2>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
rows={4}
|
||||||
|
value={rejectionReason}
|
||||||
|
onChange={handleRejectionReasonChange}
|
||||||
|
variant="outlined"
|
||||||
|
label="Enter rejection reason"
|
||||||
|
/>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleModalClose} sx={{ textTransform: 'unset' }} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleRejectConfirm}
|
||||||
|
sx={{ textTransform: 'unset' }}
|
||||||
|
color="error"
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
open={openModal2}
|
||||||
|
onClose={handleModalClose2}
|
||||||
|
aria-labelledby="modal-modal-title"
|
||||||
|
aria-describedby="modal-modal-description"
|
||||||
|
>
|
||||||
|
<Box sx={{ ...modalStyle, width: 400 }}>
|
||||||
|
<h2 id="modal-modal-title">Approval Confirmation</h2>
|
||||||
|
<Typography id="modal-modal-description" sx={{ mt: 2 }}>
|
||||||
|
Are you sure you want to approve this KYC?
|
||||||
|
</Typography>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
onClick={handleModalClose2}
|
||||||
|
sx={{ textTransform: 'unset' }}
|
||||||
|
color="primary"
|
||||||
|
// variant="contained"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleApproveConfirm}
|
||||||
|
sx={{ textTransform: 'unset' }}
|
||||||
|
color="success"
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const modalStyle = {
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4,
|
||||||
|
}
|
||||||
|
|
||||||
export default Kyc
|
export default Kyc
|
||||||
|
@ -1,51 +1,180 @@
|
|||||||
import React from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { Box, Typography, Grid, Paper, Avatar } from '@mui/material'
|
import axios from 'axios'
|
||||||
import { useParams } from 'react-router-dom'
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Grid,
|
||||||
|
Paper,
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
TextField,
|
||||||
|
Modal,
|
||||||
|
DialogActions,
|
||||||
|
} from '@mui/material'
|
||||||
|
import { useNavigate, useParams } from 'react-router-dom'
|
||||||
import { format } from 'date-fns'
|
import { format } from 'date-fns'
|
||||||
|
import Axios from '../../../axios'
|
||||||
const generateRandomRetailerDetails = (id) => ({
|
import { isAutheticated } from '../../../auth'
|
||||||
id,
|
import MessageList from './MessageList'
|
||||||
tradeName: `Trade ${id}`,
|
import Swal from 'sweetalert2'
|
||||||
name: `Retailer ${id}`,
|
|
||||||
address: '123 Main St',
|
|
||||||
townCity: 'Townsville',
|
|
||||||
district: 'District A',
|
|
||||||
state: 'State B',
|
|
||||||
pincode: '123456',
|
|
||||||
mobileNumber: '123-456-7890',
|
|
||||||
mappedDistributor: `Distributor ${id}`,
|
|
||||||
documents: {
|
|
||||||
panNumber: 'ABCDE1234F',
|
|
||||||
panCard:
|
|
||||||
'https://www.shutterstock.com/shutterstock/photos/2329691987/display_1500/stock-vector-blank-pan-card-vector-image-income-tax-card-personal-account-number-image-translation-income-2329691987.jpg',
|
|
||||||
aadharNumber: '1234-5678-9101',
|
|
||||||
aadharCard: 'https://via.placeholder.com/100',
|
|
||||||
gstNumber: '22AAAAA0000A1Z5',
|
|
||||||
gstRegistration: 'https://via.placeholder.com/100',
|
|
||||||
pesticideLicense: 'https://via.placeholder.com/100',
|
|
||||||
fertilizerLicense: 'https://via.placeholder.com/100',
|
|
||||||
entranceBoardSelfie: 'https://via.placeholder.com/100',
|
|
||||||
},
|
|
||||||
salesCoordinator: {
|
|
||||||
designation: 'Sales Coordinator',
|
|
||||||
name: `Coordinator ${id}`,
|
|
||||||
employeeId: `EMP${id}`,
|
|
||||||
uploadedOn: new Date(),
|
|
||||||
resubmittedOn: new Date(),
|
|
||||||
},
|
|
||||||
notes: ['Note 1', 'Note 2', 'Note 3'],
|
|
||||||
})
|
|
||||||
|
|
||||||
const KycDetails = () => {
|
const KycDetails = () => {
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
console.log(id)
|
const [openRejectModal, setOpenRejectModal] = useState(false)
|
||||||
const retailerDetails = generateRandomRetailerDetails(id)
|
const [openApproveModal, setOpenApproveModal] = useState(false)
|
||||||
|
const [rejectionReason, setRejectionReason] = useState('')
|
||||||
|
const [selectedRowId, setSelectedRowId] = useState(null)
|
||||||
|
const [retailerDetails, setRetailerDetails] = useState(null)
|
||||||
|
const token = isAutheticated()
|
||||||
|
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await Axios.get(`/api/kyc/get-single-kyc/${id}`, {
|
||||||
|
headers: {
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'multipart/formdata',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
console.log(response.data)
|
||||||
|
setRetailerDetails(response.data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching data: ', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData()
|
||||||
|
}, [id])
|
||||||
|
|
||||||
|
const [msg, setMsg] = useState('')
|
||||||
|
const handelSend = async () => {
|
||||||
|
try {
|
||||||
|
const resp = await Axios.patch(
|
||||||
|
`/api/kyc/update/${id}`,
|
||||||
|
{
|
||||||
|
rejectionReason: msg,
|
||||||
|
|
||||||
|
user: 'Principal Distributer', // Replace with actual user type
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
setRetailerDetails(resp.data.kyc)
|
||||||
|
setMsg('')
|
||||||
|
Swal.fire('Success', 'Message sent', 'success')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error sending message: ', error)
|
||||||
|
Swal.fire('Error!', error.message, 'error')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleModalClose = () => {
|
||||||
|
setOpenRejectModal(false)
|
||||||
|
setOpenApproveModal(false)
|
||||||
|
setRejectionReason('')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRejectionReasonChange = (event) => {
|
||||||
|
setRejectionReason(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRejectConfirm = async () => {
|
||||||
|
try {
|
||||||
|
const res = await Axios.patch(
|
||||||
|
`/api/kyc/update/${id}`,
|
||||||
|
{
|
||||||
|
status: 'reject',
|
||||||
|
rejectionReason,
|
||||||
|
|
||||||
|
user: 'Principal Distributer', // Replace with actual user type
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
setRetailerDetails(res.data.kyc)
|
||||||
|
Swal.fire('Success', 'Rejected', 'success')
|
||||||
|
handleModalClose()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error rejecting KYC: ', error)
|
||||||
|
Swal.fire('Error!', error.message, 'error')
|
||||||
|
handleModalClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleApproveConfirm = async () => {
|
||||||
|
try {
|
||||||
|
const res = await Axios.patch(
|
||||||
|
`/api/kyc/update/${id}`,
|
||||||
|
{
|
||||||
|
status: 'approved',
|
||||||
|
user: 'Principal Distributer', // Replace with actual user type
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
setRetailerDetails(res.data.kyc)
|
||||||
|
Swal.fire('Success', 'Approved', 'success')
|
||||||
|
handleModalClose()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error approving KYC: ', error)
|
||||||
|
Swal.fire('Error!', error.message, 'error')
|
||||||
|
handleModalClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatAMPM = (date) => {
|
||||||
|
var hours = new Date(date).getHours()
|
||||||
|
var minutes = new Date(date).getMinutes()
|
||||||
|
var ampm = hours >= 12 ? 'PM' : 'AM'
|
||||||
|
hours = hours % 12
|
||||||
|
hours = hours ? hours : 12 // the hour '0' should be '12'
|
||||||
|
minutes = minutes < 10 ? '0' + minutes : minutes
|
||||||
|
var strTime = hours + ':' + minutes + ' ' + ampm
|
||||||
|
return strTime
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRejectClick = () => {
|
||||||
|
setOpenRejectModal(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleApproveClick = () => {
|
||||||
|
setOpenApproveModal(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!retailerDetails) {
|
||||||
|
return <Typography>Loading...</Typography>
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ p: 3 }}>
|
<Box sx={{ p: 3 }}>
|
||||||
<Typography variant="h4" gutterBottom>
|
<Box sx={{ display: 'flex', mb: '1rem' }}>
|
||||||
|
<Typography variant="h4" flex={1} gutterBottom>
|
||||||
Retailer Details
|
Retailer Details
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<Button
|
||||||
|
onClick={() => navigate('/kyc')}
|
||||||
|
color="primary"
|
||||||
|
sx={{ padding: '0.5rem 1rem' }}
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Back
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Paper sx={{ p: 2, mb: 3 }}>
|
<Paper sx={{ p: 2, mb: 3 }}>
|
||||||
<Typography variant="h5" gutterBottom>
|
<Typography variant="h5" gutterBottom>
|
||||||
@ -54,7 +183,7 @@ const KycDetails = () => {
|
|||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Trade Name:</strong> {retailerDetails.tradeName}
|
<strong>Trade Name:</strong> {retailerDetails.trade_name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Name:</strong> {retailerDetails.name}
|
<strong>Name:</strong> {retailerDetails.name}
|
||||||
@ -63,7 +192,7 @@ const KycDetails = () => {
|
|||||||
<strong>Address:</strong> {retailerDetails.address}
|
<strong>Address:</strong> {retailerDetails.address}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Town/City:</strong> {retailerDetails.townCity}
|
<strong>Town/City:</strong> {retailerDetails.city}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
@ -77,10 +206,11 @@ const KycDetails = () => {
|
|||||||
<strong>Pincode:</strong> {retailerDetails.pincode}
|
<strong>Pincode:</strong> {retailerDetails.pincode}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Mobile Number:</strong> {retailerDetails.mobileNumber}
|
<strong>Mobile Number:</strong> {retailerDetails.mobile_number}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Mapped Principal Distributor:</strong> {retailerDetails.mappedDistributor}
|
<strong>Mapped Principal Distributor:</strong>{' '}
|
||||||
|
{retailerDetails.principal_distributer.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -93,27 +223,27 @@ const KycDetails = () => {
|
|||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>PAN Number:</strong> {retailerDetails.documents.panNumber}
|
<strong>PAN Number:</strong> {retailerDetails.pan_number}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant="square"
|
variant="square"
|
||||||
src={retailerDetails.documents.panCard}
|
src={retailerDetails.pan_img.url}
|
||||||
sx={{ width: 100, height: 100, mb: 2 }}
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
/>
|
/>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Aadhar Number:</strong> {retailerDetails.documents.aadharNumber}
|
<strong>Aadhar Number:</strong> {retailerDetails.aadhar_number}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant="square"
|
variant="square"
|
||||||
src={retailerDetails.documents.aadharCard}
|
src={retailerDetails.aadhar_img.url}
|
||||||
sx={{ width: 100, height: 100, mb: 2 }}
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
/>
|
/>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>GST Number:</strong> {retailerDetails.documents.gstNumber}
|
<strong>GST Number:</strong> {retailerDetails.gst_number}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant="square"
|
variant="square"
|
||||||
src={retailerDetails.documents.gstRegistration}
|
src={retailerDetails.gst_img.url}
|
||||||
sx={{ width: 100, height: 100, mb: 2 }}
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -123,23 +253,27 @@ const KycDetails = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant="square"
|
variant="square"
|
||||||
src={retailerDetails.documents.pesticideLicense}
|
src={retailerDetails.pesticide_license_img.url}
|
||||||
sx={{ width: 100, height: 100, mb: 2 }}
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
/>
|
/>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Fertilizer License (optional):</strong>
|
<strong>Fertilizer License (optional):</strong>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{retailerDetails.fertilizer_license_img ? (
|
||||||
<Avatar
|
<Avatar
|
||||||
variant="square"
|
variant="square"
|
||||||
src={retailerDetails.documents.fertilizerLicense}
|
src={retailerDetails.fertilizer_license_img.url}
|
||||||
sx={{ width: 100, height: 100, mb: 2 }}
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<Typography>Img not available</Typography>
|
||||||
|
)}
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Selfie of Entrance Board:</strong>
|
<strong>Selfie of Entrance Board:</strong>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant="square"
|
variant="square"
|
||||||
src={retailerDetails.documents.entranceBoardSelfie}
|
src={retailerDetails.selfie_entrance_img.url}
|
||||||
sx={{ width: 100, height: 100, mb: 2 }}
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -148,43 +282,158 @@ const KycDetails = () => {
|
|||||||
|
|
||||||
<Paper sx={{ p: 2, mb: 3 }}>
|
<Paper sx={{ p: 2, mb: 3 }}>
|
||||||
<Typography variant="h6" gutterBottom>
|
<Typography variant="h6" gutterBottom>
|
||||||
Block 3: Sales Coordinators/Territory Manager Details
|
Sales Coordinators/Territory Manager Details
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Designation:</strong> {retailerDetails.salesCoordinator.designation}
|
<strong>Designation:</strong>{' '}
|
||||||
|
{retailerDetails.userType === 'SalesCoOrdinator'
|
||||||
|
? 'Sales Coordinator'
|
||||||
|
: 'Territory Manager'}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Name:</strong> {retailerDetails.salesCoordinator.name}
|
<strong>Name:</strong> {retailerDetails.addedBy.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Employee ID:</strong> {retailerDetails.salesCoordinator.employeeId}
|
<strong>Employee ID:</strong> {retailerDetails.addedBy.uniqueId}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Uploaded on:</strong>{' '}
|
<strong>Uploaded on:</strong>{' '}
|
||||||
{format(retailerDetails.salesCoordinator.uploadedOn, 'yyyy-MM-dd HH:mm:ss')}
|
{new Date(`${retailerDetails?.createdAt}`).toDateString()}
|
||||||
|
<span> , {`${formatAMPM(retailerDetails?.createdAt)}`}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
<strong>Resubmitted on:</strong>{' '}
|
<strong>Resubmitted on:</strong>{' '}
|
||||||
{format(retailerDetails.salesCoordinator.resubmittedOn, 'yyyy-MM-dd HH:mm:ss')}
|
{new Date(`${retailerDetails?.createdAt}`).toDateString()}
|
||||||
|
<span> , {`${formatAMPM(retailerDetails?.createdAt)}`}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
|
{retailerDetails.notes.length > 0 && retailerDetails.status === 'reject' && (
|
||||||
<Paper sx={{ p: 2, mb: 3 }}>
|
<Paper sx={{ p: 2, mb: 3 }}>
|
||||||
<Typography variant="h6" gutterBottom>
|
<Typography variant="h6" gutterBottom>
|
||||||
Block 4: Notes
|
Notes:
|
||||||
</Typography>
|
</Typography>
|
||||||
{retailerDetails.notes.map((note, index) => (
|
|
||||||
<Typography key={index}>{note}</Typography>
|
<MessageList messages={retailerDetails.notes} />
|
||||||
))}
|
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
rows={4}
|
||||||
|
value={msg}
|
||||||
|
onChange={(e) => setMsg(e.target.value)}
|
||||||
|
variant="outlined"
|
||||||
|
label="send message"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{ textTransform: 'unset', mt: '2rem' }}
|
||||||
|
onClick={() => handelSend()}
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</Button>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
)}
|
||||||
|
{retailerDetails.status === 'new' && (
|
||||||
|
<>
|
||||||
|
<Modal
|
||||||
|
open={openRejectModal}
|
||||||
|
onClose={handleModalClose}
|
||||||
|
aria-labelledby="modal-modal-title"
|
||||||
|
aria-describedby="modal-modal-description"
|
||||||
|
>
|
||||||
|
<Box sx={{ ...modalStyle, width: 400 }}>
|
||||||
|
<h2 id="modal-modal-title">Rejection Reason</h2>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
rows={4}
|
||||||
|
value={rejectionReason}
|
||||||
|
onChange={handleRejectionReasonChange}
|
||||||
|
variant="outlined"
|
||||||
|
label="Enter rejection reason"
|
||||||
|
/>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleModalClose} sx={{ textTransform: 'unset' }} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleRejectConfirm}
|
||||||
|
sx={{ textTransform: 'unset' }}
|
||||||
|
color="error"
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
open={openApproveModal}
|
||||||
|
onClose={handleModalClose}
|
||||||
|
aria-labelledby="modal-modal-title"
|
||||||
|
aria-describedby="modal-modal-description"
|
||||||
|
>
|
||||||
|
<Box sx={{ ...modalStyle, width: 400 }}>
|
||||||
|
<h2 id="modal-modal-title">Approval Confirmation</h2>
|
||||||
|
<Typography id="modal-modal-description" sx={{ mt: 2 }}>
|
||||||
|
Are you sure you want to approve this KYC?
|
||||||
|
</Typography>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleModalClose} sx={{ textTransform: 'unset' }} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleApproveConfirm}
|
||||||
|
sx={{ textTransform: 'unset' }}
|
||||||
|
color="success"
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Paper sx={{ p: 2, mb: 3 }}>
|
||||||
|
<Button
|
||||||
|
sx={{ mr: '1rem', textTransform: 'unset' }}
|
||||||
|
color="success"
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleApproveClick}
|
||||||
|
>
|
||||||
|
Approve
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
sx={{ mr: '1rem', textTransform: 'unset' }}
|
||||||
|
color="error"
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleRejectClick}
|
||||||
|
>
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</Paper>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const modalStyle = {
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4,
|
||||||
|
}
|
||||||
|
|
||||||
export default KycDetails
|
export default KycDetails
|
||||||
|
@ -95,27 +95,25 @@ const Login = () => {
|
|||||||
if (!(auth.email && auth.password)) {
|
if (!(auth.email && auth.password)) {
|
||||||
return Swal.fire('Error!', 'All fields are required', 'error')
|
return Swal.fire('Error!', 'All fields are required', 'error')
|
||||||
}
|
}
|
||||||
setLoading({ loading: true })
|
setLoading(true)
|
||||||
try {
|
try {
|
||||||
const res = await Axios.post('/api/v1/user/login/', auth)
|
const res = await Axios.post('/api/v1/user/login/', auth)
|
||||||
console.log(res)
|
console.log(res)
|
||||||
if (res.data.success == true && res.data.user.role === 'principal-Distributor') {
|
if (res.data.success === true && res.data.user.role === 'principal-Distributor') {
|
||||||
localStorage.setItem('authToken', res.data.token)
|
localStorage.setItem('authToken', res.data.token)
|
||||||
navigate('/dashboard')
|
navigate('/dashboard')
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
Swal.fire('success', 'logged in successfuly ', 'success')
|
Swal.fire('success', 'logged in successfully ', 'success')
|
||||||
|
} else if (res.data.success === true && res.data.user.role !== 'principal-Distributor') {
|
||||||
// console.log(response.data)
|
|
||||||
} else if (res.data.success == true && res.data.user.role !== 'principal-Distributor') {
|
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
Swal.fire('error', 'Please login through the PD Credentials ', 'error')
|
Swal.fire('error', 'Please login through the PD Credentials ', 'error')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
|
|
||||||
Swal.fire('Error!', 'Invalid Credentials', 'error')
|
Swal.fire('Error!', 'Invalid Credentials', 'error')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
|
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
|
||||||
<CContainer>
|
<CContainer>
|
||||||
|
Loading…
Reference in New Issue
Block a user