diff --git a/package.json b/package.json
index 8024cb9..17d997b 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"classnames": "^2.5.1",
"core-js": "^3.37.1",
"date-fns": "^3.6.0",
+ "jwt-decode": "^4.0.0",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/src/protectedRoute.js b/src/protectedRoute.js
index 1382107..87cf6dc 100644
--- a/src/protectedRoute.js
+++ b/src/protectedRoute.js
@@ -2,15 +2,38 @@
/* eslint-disable react/prop-types */
import { useEffect } from 'react'
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 navigate = useNavigate()
- console.log('req came here ')
useEffect(() => {
- if (!localStorage.getItem('authToken')) {
- navigate('/login')
+ 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')
+ } else {
+ console.log('Token is valid')
+ }
}
+
+ checkToken()
}, [navigate])
return
diff --git a/src/routes.js b/src/routes.js
index 4f2d010..6976e7f 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -14,7 +14,7 @@ const routes = [
{ path: '/shop', name: 'Shop', element: Shop },
{ path: '/order', name: 'Order', element: Order },
// KYC
- { path: '/kyc', name: 'Kyc', element: Kyc },
+ { path: '/kyc', name: 'KYC', element: Kyc },
{ path: '/kyc/details/:id', name: 'Kyc details', element: KycDetails },
{ path: '/my-profile', name: 'Profile', element: MyProfile },
diff --git a/src/views/pages/Kyc/MessageList.js b/src/views/pages/Kyc/MessageList.js
new file mode 100644
index 0000000..26b4a7d
--- /dev/null
+++ b/src/views/pages/Kyc/MessageList.js
@@ -0,0 +1,29 @@
+/* eslint-disable react/prop-types */
+import React from 'react'
+
+const MessageList = ({ messages }) => {
+ return (
+ <>
+ {messages.map((msg, index) => (
+
+
{msg.user}
+
+ {msg.replyDate}
+
+
{msg.message}
+
+ ))}
+ >
+ )
+}
+
+export default MessageList
diff --git a/src/views/pages/Kyc/kyc.js b/src/views/pages/Kyc/kyc.js
index 0623936..eab8ecc 100644
--- a/src/views/pages/Kyc/kyc.js
+++ b/src/views/pages/Kyc/kyc.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react'
+import React, { useState, useEffect } from 'react'
import {
Box,
Table,
@@ -10,34 +10,51 @@ import {
Paper,
TablePagination,
Button,
- IconButton,
Tooltip,
+ Tabs,
+ Tab,
+ Modal,
+ TextField,
+ DialogActions,
+ Typography,
} from '@mui/material'
-import { Visibility, ThumbUp, ThumbDown } from '@mui/icons-material'
-import { format } from 'date-fns'
import { useNavigate } from 'react-router-dom'
-
-const generateRandomData = (numRows) => {
- const statuses = ['New', 'Pending', 'Rejected', 'Approved']
- 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
-}
+import Axios from '../../../axios'
+import { isAutheticated } from '../../../auth'
+import Swal from 'sweetalert2'
const Kyc = () => {
- const [rows, setRows] = useState(generateRandomData(50))
+ const [rows, setRows] = useState([])
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 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) => {
setPage(newPage)
@@ -48,13 +65,124 @@ const Kyc = () => {
setPage(0)
}
- // const handleViewClick = (id) => {
- // navigate(`/kyc/details/${id}`)
- // }
+ const handleViewClick = (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 (
+
+
+
+
+
@@ -67,60 +195,143 @@ const Kyc = () => {
- {rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row) => (
-
- {row.id}
- {row.tradeName}
- {format(row.createdOn, 'yyyy-MM-dd HH:mm:ss')}
- {row.status}
-
-
- {/*
-
- */}
-
-
-
- {/*
-
- */}
-
-
-
- {/*
-
- */}
-
-
-
-
- ))}
+ {filteredRows
+ .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
+ .map((row) => (
+
+ {row._id}
+ {row.trade_name}
+
+ {new Date(`${row?.createdAt}`).toDateString()}
+ , {`${formatAMPM(row?.createdAt)}`}
+
+ {row.status}
+
+
+
+
+ {tabIndex === 0 && (
+ <>
+
+
+
+
+
+
+ >
+ )}
+
+
+ ))}
+
+
+ Rejection Reason
+
+
+
+
+
+
+
+
+
+ Approval Confirmation
+
+ Are you sure you want to approve this KYC?
+
+
+
+
+
+
+
)
}
+const modalStyle = {
+ position: 'absolute',
+ top: '50%',
+ left: '50%',
+ transform: 'translate(-50%, -50%)',
+ bgcolor: 'background.paper',
+ boxShadow: 24,
+ p: 4,
+}
+
export default Kyc
diff --git a/src/views/pages/Kyc/kycDetails.js b/src/views/pages/Kyc/kycDetails.js
index 8da92e0..c28c04a 100644
--- a/src/views/pages/Kyc/kycDetails.js
+++ b/src/views/pages/Kyc/kycDetails.js
@@ -1,51 +1,180 @@
-import React from 'react'
-import { Box, Typography, Grid, Paper, Avatar } from '@mui/material'
-import { useParams } from 'react-router-dom'
+import React, { useState, useEffect } from 'react'
+import axios from 'axios'
+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'
-
-const generateRandomRetailerDetails = (id) => ({
- id,
- tradeName: `Trade ${id}`,
- 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'],
-})
+import Axios from '../../../axios'
+import { isAutheticated } from '../../../auth'
+import MessageList from './MessageList'
+import Swal from 'sweetalert2'
const KycDetails = () => {
const { id } = useParams()
- console.log(id)
- const retailerDetails = generateRandomRetailerDetails(id)
+ const [openRejectModal, setOpenRejectModal] = useState(false)
+ 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 Loading...
+ }
return (
-
- Retailer Details
-
+
+
+ Retailer Details
+
+
+
@@ -54,7 +183,7 @@ const KycDetails = () => {
- Trade Name: {retailerDetails.tradeName}
+ Trade Name: {retailerDetails.trade_name}
Name: {retailerDetails.name}
@@ -63,7 +192,7 @@ const KycDetails = () => {
Address: {retailerDetails.address}
- Town/City: {retailerDetails.townCity}
+ Town/City: {retailerDetails.city}
@@ -77,10 +206,11 @@ const KycDetails = () => {
Pincode: {retailerDetails.pincode}
- Mobile Number: {retailerDetails.mobileNumber}
+ Mobile Number: {retailerDetails.mobile_number}
- Mapped Principal Distributor: {retailerDetails.mappedDistributor}
+ Mapped Principal Distributor:{' '}
+ {retailerDetails.principal_distributer.name}
@@ -93,27 +223,27 @@ const KycDetails = () => {
- PAN Number: {retailerDetails.documents.panNumber}
+ PAN Number: {retailerDetails.pan_number}
- Aadhar Number: {retailerDetails.documents.aadharNumber}
+ Aadhar Number: {retailerDetails.aadhar_number}
- GST Number: {retailerDetails.documents.gstNumber}
+ GST Number: {retailerDetails.gst_number}
@@ -123,23 +253,27 @@ const KycDetails = () => {
Fertilizer License (optional):
-
+ {retailerDetails.fertilizer_license_img ? (
+
+ ) : (
+ Img not available
+ )}
Selfie of Entrance Board:
@@ -148,43 +282,158 @@ const KycDetails = () => {
- Block 3: Sales Coordinators/Territory Manager Details
+ Sales Coordinators/Territory Manager Details
- Designation: {retailerDetails.salesCoordinator.designation}
+ Designation:{' '}
+ {retailerDetails.userType === 'SalesCoOrdinator'
+ ? 'Sales Coordinator'
+ : 'Territory Manager'}
- Name: {retailerDetails.salesCoordinator.name}
+ Name: {retailerDetails.addedBy.name}
- Employee ID: {retailerDetails.salesCoordinator.employeeId}
+ Employee ID: {retailerDetails.addedBy.uniqueId}
Uploaded on:{' '}
- {format(retailerDetails.salesCoordinator.uploadedOn, 'yyyy-MM-dd HH:mm:ss')}
+ {new Date(`${retailerDetails?.createdAt}`).toDateString()}
+ , {`${formatAMPM(retailerDetails?.createdAt)}`}
Resubmitted on:{' '}
- {format(retailerDetails.salesCoordinator.resubmittedOn, 'yyyy-MM-dd HH:mm:ss')}
+ {new Date(`${retailerDetails?.createdAt}`).toDateString()}
+ , {`${formatAMPM(retailerDetails?.createdAt)}`}
-
-
- Block 4: Notes
-
- {retailerDetails.notes.map((note, index) => (
- {note}
- ))}
-
+ {retailerDetails.notes.length > 0 && retailerDetails.status === 'reject' && (
+
+
+ Notes:
+
+
+
+
+ setMsg(e.target.value)}
+ variant="outlined"
+ label="send message"
+ />
+
+
+ )}
+ {retailerDetails.status === 'new' && (
+ <>
+
+
+ Rejection Reason
+
+
+
+
+
+
+
+
+
+
+ Approval Confirmation
+
+ Are you sure you want to approve this KYC?
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
)
}
+const modalStyle = {
+ position: 'absolute',
+ top: '50%',
+ left: '50%',
+ transform: 'translate(-50%, -50%)',
+ bgcolor: 'background.paper',
+ boxShadow: 24,
+ p: 4,
+}
+
export default KycDetails
diff --git a/src/views/pages/login/Login.js b/src/views/pages/login/Login.js
index 6031786..f9d0ad3 100644
--- a/src/views/pages/login/Login.js
+++ b/src/views/pages/login/Login.js
@@ -95,27 +95,25 @@ const Login = () => {
if (!(auth.email && auth.password)) {
return Swal.fire('Error!', 'All fields are required', 'error')
}
- setLoading({ loading: true })
+ setLoading(true)
try {
const res = await Axios.post('/api/v1/user/login/', auth)
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)
navigate('/dashboard')
setLoading(false)
- Swal.fire('success', 'logged in successfuly ', 'success')
-
- // console.log(response.data)
- } else if (res.data.success == true && res.data.user.role !== 'principal-Distributor') {
+ Swal.fire('success', 'logged in successfully ', 'success')
+ } else if (res.data.success === true && res.data.user.role !== 'principal-Distributor') {
setLoading(false)
Swal.fire('error', 'Please login through the PD Credentials ', 'error')
}
} catch (error) {
setLoading(false)
-
Swal.fire('Error!', 'Invalid Credentials', 'error')
}
}
+
return (