PD auth and protected routes done
This commit is contained in:
parent
823fbd7d19
commit
d5754487ad
@ -26,14 +26,20 @@
|
|||||||
"@coreui/react": "^5.1.0",
|
"@coreui/react": "^5.1.0",
|
||||||
"@coreui/react-chartjs": "^3.0.0",
|
"@coreui/react-chartjs": "^3.0.0",
|
||||||
"@coreui/utils": "^2.0.2",
|
"@coreui/utils": "^2.0.2",
|
||||||
|
"@emotion/react": "^11.13.0",
|
||||||
|
"@emotion/styled": "^11.13.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
|
"@mui/icons-material": "^5.16.4",
|
||||||
|
"@mui/material": "^5.16.4",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@themesberg/react-bootstrap": "^1.4.1",
|
"@themesberg/react-bootstrap": "^1.4.1",
|
||||||
|
"axios": "^1.7.2",
|
||||||
"chart.js": "^4.4.3",
|
"chart.js": "^4.4.3",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"core-js": "^3.37.1",
|
"core-js": "^3.37.1",
|
||||||
|
"date-fns": "^3.6.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",
|
||||||
@ -41,7 +47,7 @@
|
|||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"redux": "5.0.1",
|
"redux": "5.0.1",
|
||||||
"simplebar-react": "^3.2.5",
|
"simplebar-react": "^3.2.5",
|
||||||
"sweetalert2": "^11.12.2"
|
"sweetalert2": "^11.12.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-react": "^4.3.1",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
|
14
src/App.js
14
src/App.js
@ -4,6 +4,7 @@ import { useSelector } from 'react-redux'
|
|||||||
|
|
||||||
import { CSpinner, useColorModes } from '@coreui/react'
|
import { CSpinner, useColorModes } from '@coreui/react'
|
||||||
import './scss/style.scss'
|
import './scss/style.scss'
|
||||||
|
import ProtectedRoute from './protectedRoute'
|
||||||
|
|
||||||
// Containers
|
// Containers
|
||||||
const DefaultLayout = React.lazy(() => import('./layout/DefaultLayout'))
|
const DefaultLayout = React.lazy(() => import('./layout/DefaultLayout'))
|
||||||
@ -13,8 +14,7 @@ const Login = React.lazy(() => import('./views/pages/login/Login'))
|
|||||||
const Register = React.lazy(() => import('./views/pages/register/Register'))
|
const Register = React.lazy(() => import('./views/pages/register/Register'))
|
||||||
const Page404 = React.lazy(() => import('./views/pages/page404/Page404'))
|
const Page404 = React.lazy(() => import('./views/pages/page404/Page404'))
|
||||||
const Page500 = React.lazy(() => import('./views/pages/page500/Page500'))
|
const Page500 = React.lazy(() => import('./views/pages/page500/Page500'))
|
||||||
const MyProfile = React.lazy(() => import('./views/pages/profile/MyProfile'))
|
const ForgetPassword = React.lazy(() => import('./views/pages/forgetPassword'))
|
||||||
const ChangePassword = React.lazy(() => import('./views/pages/profile/ChangePassword'))
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const { isColorModeSet, setColorMode } = useColorModes('coreui-free-react-admin-template-theme')
|
const { isColorModeSet, setColorMode } = useColorModes('coreui-free-react-admin-template-theme')
|
||||||
@ -46,12 +46,18 @@ const App = () => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route exact path="/my-profile" name="My profile" element={<MyProfile />} />
|
{/* <Route exact path="/change-password" name="My profile" element={<ChangePassword />} /> */}
|
||||||
<Route exact path="/change-password" name="My profile" element={<ChangePassword />} />
|
|
||||||
<Route exact path="/login" name="Login Page" element={<Login />} />
|
<Route exact path="/login" name="Login Page" element={<Login />} />
|
||||||
<Route exact path="/register" name="Register Page" element={<Register />} />
|
<Route exact path="/register" name="Register Page" element={<Register />} />
|
||||||
<Route exact path="/404" name="Page 404" element={<Page404 />} />
|
<Route exact path="/404" name="Page 404" element={<Page404 />} />
|
||||||
<Route exact path="/500" name="Page 500" element={<Page500 />} />
|
<Route exact path="/500" name="Page 500" element={<Page500 />} />
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/forget-password"
|
||||||
|
name="Forget password "
|
||||||
|
element={<ForgetPassword />}
|
||||||
|
/>
|
||||||
|
<Route path="/*" element={<ProtectedRoute element={DefaultLayout} />} />
|
||||||
<Route path="*" name="Home" element={<DefaultLayout />} />
|
<Route path="*" name="Home" element={<DefaultLayout />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
17
src/_nav.js
17
src/_nav.js
@ -23,10 +23,6 @@ const _nav = [
|
|||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
to: '/dashboard',
|
to: '/dashboard',
|
||||||
icon: <CIcon icon={cilSpeedometer} customClassName="nav-icon" />,
|
icon: <CIcon icon={cilSpeedometer} customClassName="nav-icon" />,
|
||||||
badge: {
|
|
||||||
color: 'info',
|
|
||||||
text: 'NEW',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
component: CNavItem,
|
component: CNavItem,
|
||||||
@ -34,12 +30,19 @@ const _nav = [
|
|||||||
to: '/shop',
|
to: '/shop',
|
||||||
icon: <CIcon icon={cilShare} customClassName="nav-icon" />,
|
icon: <CIcon icon={cilShare} customClassName="nav-icon" />,
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// component: CNavItem,
|
||||||
|
// name: 'Orders',
|
||||||
|
// to: '/order',
|
||||||
|
// icon: <CIcon icon={cilBorderAll} customClassName="nav-icon" />,
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
component: CNavItem,
|
component: CNavItem,
|
||||||
name: 'Orders',
|
name: 'KYC',
|
||||||
to: '/order',
|
to: '/kyc',
|
||||||
icon: <CIcon icon={cilBorderAll} customClassName="nav-icon" />,
|
icon: <CIcon icon={cilDescription} customClassName="nav-icon" />,
|
||||||
},
|
},
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// component: CNavTitle,
|
// component: CNavTitle,
|
||||||
// name: 'Theme',
|
// name: 'Theme',
|
||||||
|
26
src/assets/data/cardjson.json
Normal file
26
src/assets/data/cardjson.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Item 1",
|
||||||
|
"image": "https://images.pexels.com/photos/341523/pexels-photo-341523.jpeg?auto=compress&cs=tinysrgb&w=600",
|
||||||
|
"price": 10.99,
|
||||||
|
"categoryName": "phone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Item 2",
|
||||||
|
"image": "https://images.pexels.com/photos/90946/pexels-photo-90946.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
|
||||||
|
"price": 20.99,
|
||||||
|
"categoryName": "phone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Item 3",
|
||||||
|
"image": "https://images.pexels.com/photos/341523/pexels-photo-341523.jpeg?auto=compress&cs=tinysrgb&w=600",
|
||||||
|
"price": 30.99,
|
||||||
|
"categoryName": "camera"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Item 4",
|
||||||
|
"image": "https://images.pexels.com/photos/90946/pexels-photo-90946.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
|
||||||
|
"price": 40.99,
|
||||||
|
"categoryName": "camera"
|
||||||
|
}
|
||||||
|
]
|
10
src/auth.js
Normal file
10
src/auth.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export const isAutheticated = () => {
|
||||||
|
if (typeof window == 'undefined') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (localStorage.getItem('authToken')) {
|
||||||
|
return localStorage.getItem('authToken')
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
const Axios = axios.create({
|
const Axios = axios.create({
|
||||||
// baseURL: "http://localhost:5000/",
|
// baseURL: 'http://localhost:5000/',
|
||||||
// baseURL: 'https://leadesh-whatsapp.onrender.com',
|
// baseURL: 'https://leadesh-whatsapp.onrender.com',
|
||||||
// baseURL: "https://api.leadesh.com/",
|
// baseURL: "https://api.leadesh.com/",
|
||||||
baseURL: 'https://leadesh-api-github.onrender.com/', // latest is this one
|
baseURL: 'https://cheminova-api-2.onrender.com', // latest is this one
|
||||||
})
|
})
|
||||||
|
|
||||||
export default Axios
|
export default Axios
|
||||||
|
@ -4,7 +4,7 @@ import { CFooter } from '@coreui/react'
|
|||||||
const AppFooter = () => {
|
const AppFooter = () => {
|
||||||
return (
|
return (
|
||||||
<CFooter className="px-4">
|
<CFooter className="px-4">
|
||||||
<div>
|
{/* <div>
|
||||||
<a href="https://coreui.io" target="_blank" rel="noopener noreferrer">
|
<a href="https://coreui.io" target="_blank" rel="noopener noreferrer">
|
||||||
CoreUI
|
CoreUI
|
||||||
</a>
|
</a>
|
||||||
@ -15,7 +15,7 @@ const AppFooter = () => {
|
|||||||
<a href="https://coreui.io/react" target="_blank" rel="noopener noreferrer">
|
<a href="https://coreui.io/react" target="_blank" rel="noopener noreferrer">
|
||||||
CoreUI React Admin & Dashboard Template
|
CoreUI React Admin & Dashboard Template
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div> */}
|
||||||
</CFooter>
|
</CFooter>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
CAvatar,
|
CAvatar,
|
||||||
CBadge,
|
CBadge,
|
||||||
@ -26,55 +26,50 @@ import avatar8 from './../../assets/images/avatars/8.jpg'
|
|||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faUserCircle } from '@fortawesome/free-solid-svg-icons'
|
import { faUserCircle } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
import Swal from 'sweetalert2'
|
||||||
|
import Axios from '../../axios'
|
||||||
|
import { isAutheticated } from '../../auth'
|
||||||
|
|
||||||
const AppHeaderDropdown = () => {
|
const AppHeaderDropdown = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const signout = async () => {
|
||||||
|
localStorage.removeItem('authToken')
|
||||||
|
Swal.fire('success!', 'Logged Out', 'success')
|
||||||
|
navigate('/login')
|
||||||
|
}
|
||||||
|
const [user, setUser] = useState(null)
|
||||||
|
const token = isAutheticated()
|
||||||
|
const getData = async () => {
|
||||||
|
let res = await Axios.get(`/api/v1/user/details`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (res.data.success) {
|
||||||
|
setUser({ ...res.data.user })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
getData()
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CDropdown variant="nav-item">
|
<CDropdown variant="nav-item">
|
||||||
<CDropdownToggle placement="bottom-end" className="py-0 pe-0" caret={false}>
|
<CDropdownToggle placement="bottom-end" className="py-0 pe-0" caret={false}>
|
||||||
<div className="media d-flex align-items-center">
|
<div className="media d-flex align-items-center">
|
||||||
{/* <Image src={"Profile3"} className="user-avatar md-avatar rounded-circle" /> */}
|
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
style={{ fontSize: '2rem' }}
|
style={{ fontSize: '2rem' }}
|
||||||
className="user-avatar md-avatar rounded-circle "
|
className="user-avatar md-avatar rounded-circle "
|
||||||
icon={faUserCircle}
|
icon={faUserCircle}
|
||||||
/>
|
/>
|
||||||
<div className="media-body ms-2 text-dark align-items-center d-none d-lg-block">
|
<div className="media-body ms-2 text-dark align-items-center d-none d-lg-block">
|
||||||
<span className="mb-0 font-small fw-bold"> Garg</span>
|
<span className="mb-0 font-small fw-bold"> {user?.name}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CDropdownToggle>
|
</CDropdownToggle>
|
||||||
<CDropdownMenu className="pt-0" placement="bottom-end">
|
<CDropdownMenu className="pt-0" placement="bottom-end">
|
||||||
<CDropdownHeader className="bg-body-secondary fw-semibold mb-2">Account</CDropdownHeader>
|
<CDropdownHeader className="bg-body-secondary fw-semibold mb-2">Account</CDropdownHeader>
|
||||||
{/* <CDropdownItem href="#">
|
|
||||||
<CIcon icon={cilBell} className="me-2" />
|
|
||||||
Update
|
|
||||||
<CBadge color="info" className="ms-2">
|
|
||||||
42
|
|
||||||
</CBadge>
|
|
||||||
</CDropdownItem>
|
|
||||||
<CDropdownItem href="#">
|
|
||||||
<CIcon icon={cilEnvelopeOpen} className="me-2" />
|
|
||||||
Messages
|
|
||||||
<CBadge color="success" className="ms-2">
|
|
||||||
42
|
|
||||||
</CBadge>
|
|
||||||
</CDropdownItem>
|
|
||||||
<CDropdownItem href="#">
|
|
||||||
<CIcon icon={cilTask} className="me-2" />
|
|
||||||
Tasks
|
|
||||||
<CBadge color="danger" className="ms-2">
|
|
||||||
42
|
|
||||||
</CBadge>
|
|
||||||
</CDropdownItem>
|
|
||||||
<CDropdownItem href="#">
|
|
||||||
<CIcon icon={cilCommentSquare} className="me-2" />
|
|
||||||
Comments
|
|
||||||
<CBadge color="warning" className="ms-2">
|
|
||||||
42
|
|
||||||
</CBadge>
|
|
||||||
</CDropdownItem>
|
|
||||||
<CDropdownHeader className="bg-body-secondary fw-semibold my-2">Settings</CDropdownHeader> */}
|
|
||||||
<CDropdownItem onClick={() => navigate('/my-profile')}>
|
<CDropdownItem onClick={() => navigate('/my-profile')}>
|
||||||
<CIcon icon={cilUser} className="me-2" />
|
<CIcon icon={cilUser} className="me-2" />
|
||||||
Profile
|
Profile
|
||||||
@ -83,22 +78,9 @@ const AppHeaderDropdown = () => {
|
|||||||
<CIcon icon={cilSettings} className="me-2" />
|
<CIcon icon={cilSettings} className="me-2" />
|
||||||
Change Password
|
Change Password
|
||||||
</CDropdownItem>
|
</CDropdownItem>
|
||||||
{/* <CDropdownItem href="#">
|
|
||||||
<CIcon icon={cilCreditCard} className="me-2" />
|
|
||||||
Payments
|
|
||||||
<CBadge color="secondary" className="ms-2">
|
|
||||||
42
|
|
||||||
</CBadge>
|
|
||||||
</CDropdownItem>
|
|
||||||
<CDropdownItem href="#">
|
|
||||||
<CIcon icon={cilFile} className="me-2" />
|
|
||||||
Projects
|
|
||||||
<CBadge color="primary" className="ms-2">
|
|
||||||
42
|
|
||||||
</CBadge>
|
|
||||||
</CDropdownItem> */}
|
|
||||||
<CDropdownDivider />
|
<CDropdownDivider />
|
||||||
<CDropdownItem href="#">
|
<CDropdownItem onClick={signout}>
|
||||||
<CIcon icon={cilLockLocked} className="me-2" />
|
<CIcon icon={cilLockLocked} className="me-2" />
|
||||||
Logout
|
Logout
|
||||||
</CDropdownItem>
|
</CDropdownItem>
|
||||||
|
19
src/protectedRoute.js
Normal file
19
src/protectedRoute.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/* eslint-disable react/react-in-jsx-scope */
|
||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
|
const ProtectedRoute = ({ element: Element }) => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
console.log('req came here ')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!localStorage.getItem('authToken')) {
|
||||||
|
navigate('/login')
|
||||||
|
}
|
||||||
|
}, [navigate])
|
||||||
|
|
||||||
|
return <Element />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProtectedRoute
|
@ -3,12 +3,22 @@ import React from 'react'
|
|||||||
const Dashboard = React.lazy(() => import('./views/dashboard/Dashboard'))
|
const Dashboard = React.lazy(() => import('./views/dashboard/Dashboard'))
|
||||||
const Shop = React.lazy(() => import('./views/shops/Shop'))
|
const Shop = React.lazy(() => import('./views/shops/Shop'))
|
||||||
const Order = React.lazy(() => import('./views/orders/Order'))
|
const Order = React.lazy(() => import('./views/orders/Order'))
|
||||||
|
const MyProfile = React.lazy(() => import('./views/pages/profile/MyProfile'))
|
||||||
|
const ChangePassword = React.lazy(() => import('./views/pages/profile/ChangePassword'))
|
||||||
|
const Kyc = React.lazy(() => import('./views/pages/Kyc/kyc'))
|
||||||
|
const KycDetails = React.lazy(() => import('./views/pages/Kyc/kycDetails'))
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: '/', exact: true, name: 'Home' },
|
{ path: '/', exact: true, name: 'Home' },
|
||||||
{ path: '/dashboard', name: 'Dashboard', element: Dashboard },
|
{ path: '/dashboard', name: 'Dashboard', element: Dashboard },
|
||||||
{ 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
|
||||||
|
{ path: '/kyc', name: 'Kyc', element: Kyc },
|
||||||
|
{ path: '/kyc/details/:id', name: 'Kyc details', element: KycDetails },
|
||||||
|
|
||||||
|
{ path: '/my-profile', name: 'Profile', element: MyProfile },
|
||||||
|
{ path: '/change-password', name: 'Change password', element: ChangePassword },
|
||||||
]
|
]
|
||||||
|
|
||||||
export default routes
|
export default routes
|
||||||
|
126
src/views/pages/Kyc/kyc.js
Normal file
126
src/views/pages/Kyc/kyc.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import React, { useState } from 'react'
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Paper,
|
||||||
|
TablePagination,
|
||||||
|
Button,
|
||||||
|
IconButton,
|
||||||
|
Tooltip,
|
||||||
|
} 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
|
||||||
|
}
|
||||||
|
|
||||||
|
const Kyc = () => {
|
||||||
|
const [rows, setRows] = useState(generateRandomData(50))
|
||||||
|
const [page, setPage] = useState(0)
|
||||||
|
const [rowsPerPage, setRowsPerPage] = useState(5)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const handleChangePage = (event, newPage) => {
|
||||||
|
setPage(newPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChangeRowsPerPage = (event) => {
|
||||||
|
setRowsPerPage(parseInt(event.target.value, 10))
|
||||||
|
setPage(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleViewClick = (id) => {
|
||||||
|
navigate(`/kyc/details/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ width: '100%' }}>
|
||||||
|
<Paper sx={{ width: '100%', mb: 2 }}>
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>ID</TableCell>
|
||||||
|
<TableCell>Trade Name</TableCell>
|
||||||
|
<TableCell>Created On</TableCell>
|
||||||
|
<TableCell>Status</TableCell>
|
||||||
|
<TableCell>Action</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row) => (
|
||||||
|
<TableRow key={row.id}>
|
||||||
|
<TableCell>{row.id}</TableCell>
|
||||||
|
<TableCell>{row.tradeName}</TableCell>
|
||||||
|
<TableCell>{format(row.createdOn, 'yyyy-MM-dd HH:mm:ss')}</TableCell>
|
||||||
|
<TableCell>{row.status}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Tooltip title="View">
|
||||||
|
{/* <IconButton color="primary">
|
||||||
|
<Visibility />
|
||||||
|
</IconButton> */}
|
||||||
|
<Button
|
||||||
|
sx={{ mr: '1rem' }}
|
||||||
|
color="primary"
|
||||||
|
variant="contained"
|
||||||
|
onClick={() => handleViewClick(row.id)}
|
||||||
|
>
|
||||||
|
View
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="Approve">
|
||||||
|
{/* <IconButton color="success">
|
||||||
|
<ThumbUp />
|
||||||
|
</IconButton> */}
|
||||||
|
<Button sx={{ mr: '1rem' }} color="success" variant="contained">
|
||||||
|
Approve
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="Reject">
|
||||||
|
{/* <IconButton color="error">
|
||||||
|
<ThumbDown />
|
||||||
|
</IconButton> */}
|
||||||
|
<Button sx={{ mr: '1rem' }} color="error" variant="contained">
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
<TablePagination
|
||||||
|
rowsPerPageOptions={[5, 10, 25]}
|
||||||
|
component="div"
|
||||||
|
count={rows.length}
|
||||||
|
rowsPerPage={rowsPerPage}
|
||||||
|
page={page}
|
||||||
|
onPageChange={handleChangePage}
|
||||||
|
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Kyc
|
190
src/views/pages/Kyc/kycDetails.js
Normal file
190
src/views/pages/Kyc/kycDetails.js
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Box, Typography, Grid, Paper, Avatar } from '@mui/material'
|
||||||
|
import { 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'],
|
||||||
|
})
|
||||||
|
|
||||||
|
const KycDetails = () => {
|
||||||
|
const { id } = useParams()
|
||||||
|
console.log(id)
|
||||||
|
const retailerDetails = generateRandomRetailerDetails(id)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ p: 3 }}>
|
||||||
|
<Typography variant="h4" gutterBottom>
|
||||||
|
Retailer Details
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Paper sx={{ p: 2, mb: 3 }}>
|
||||||
|
<Typography variant="h5" gutterBottom>
|
||||||
|
Retailer Details
|
||||||
|
</Typography>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Typography>
|
||||||
|
<strong>Trade Name:</strong> {retailerDetails.tradeName}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>Name:</strong> {retailerDetails.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>Address:</strong> {retailerDetails.address}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>Town/City:</strong> {retailerDetails.townCity}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Typography>
|
||||||
|
<strong>District:</strong> {retailerDetails.district}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>State:</strong> {retailerDetails.state}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>Pincode:</strong> {retailerDetails.pincode}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>Mobile Number:</strong> {retailerDetails.mobileNumber}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>Mapped Principal Distributor:</strong> {retailerDetails.mappedDistributor}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
<Paper sx={{ p: 2, mb: 3 }}>
|
||||||
|
<Typography variant="h6" gutterBottom>
|
||||||
|
Documents
|
||||||
|
</Typography>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Typography>
|
||||||
|
<strong>PAN Number:</strong> {retailerDetails.documents.panNumber}
|
||||||
|
</Typography>
|
||||||
|
<Avatar
|
||||||
|
variant="square"
|
||||||
|
src={retailerDetails.documents.panCard}
|
||||||
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
|
/>
|
||||||
|
<Typography>
|
||||||
|
<strong>Aadhar Number:</strong> {retailerDetails.documents.aadharNumber}
|
||||||
|
</Typography>
|
||||||
|
<Avatar
|
||||||
|
variant="square"
|
||||||
|
src={retailerDetails.documents.aadharCard}
|
||||||
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
|
/>
|
||||||
|
<Typography>
|
||||||
|
<strong>GST Number:</strong> {retailerDetails.documents.gstNumber}
|
||||||
|
</Typography>
|
||||||
|
<Avatar
|
||||||
|
variant="square"
|
||||||
|
src={retailerDetails.documents.gstRegistration}
|
||||||
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Typography>
|
||||||
|
<strong>Pesticide License:</strong>
|
||||||
|
</Typography>
|
||||||
|
<Avatar
|
||||||
|
variant="square"
|
||||||
|
src={retailerDetails.documents.pesticideLicense}
|
||||||
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
|
/>
|
||||||
|
<Typography>
|
||||||
|
<strong>Fertilizer License (optional):</strong>
|
||||||
|
</Typography>
|
||||||
|
<Avatar
|
||||||
|
variant="square"
|
||||||
|
src={retailerDetails.documents.fertilizerLicense}
|
||||||
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
|
/>
|
||||||
|
<Typography>
|
||||||
|
<strong>Selfie of Entrance Board:</strong>
|
||||||
|
</Typography>
|
||||||
|
<Avatar
|
||||||
|
variant="square"
|
||||||
|
src={retailerDetails.documents.entranceBoardSelfie}
|
||||||
|
sx={{ width: 100, height: 100, mb: 2 }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
<Paper sx={{ p: 2, mb: 3 }}>
|
||||||
|
<Typography variant="h6" gutterBottom>
|
||||||
|
Block 3: Sales Coordinators/Territory Manager Details
|
||||||
|
</Typography>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Typography>
|
||||||
|
<strong>Designation:</strong> {retailerDetails.salesCoordinator.designation}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>Name:</strong> {retailerDetails.salesCoordinator.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>Employee ID:</strong> {retailerDetails.salesCoordinator.employeeId}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Typography>
|
||||||
|
<strong>Uploaded on:</strong>{' '}
|
||||||
|
{format(retailerDetails.salesCoordinator.uploadedOn, 'yyyy-MM-dd HH:mm:ss')}
|
||||||
|
</Typography>
|
||||||
|
<Typography>
|
||||||
|
<strong>Resubmitted on:</strong>{' '}
|
||||||
|
{format(retailerDetails.salesCoordinator.resubmittedOn, 'yyyy-MM-dd HH:mm:ss')}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
<Paper sx={{ p: 2, mb: 3 }}>
|
||||||
|
<Typography variant="h6" gutterBottom>
|
||||||
|
Block 4: Notes
|
||||||
|
</Typography>
|
||||||
|
{retailerDetails.notes.map((note, index) => (
|
||||||
|
<Typography key={index}>{note}</Typography>
|
||||||
|
))}
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default KycDetails
|
106
src/views/pages/forgetPassword.js
Normal file
106
src/views/pages/forgetPassword.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { cilUser } from '@coreui/icons'
|
||||||
|
import CIcon from '@coreui/icons-react'
|
||||||
|
import {
|
||||||
|
CButton,
|
||||||
|
CCard,
|
||||||
|
CCardBody,
|
||||||
|
CCardGroup,
|
||||||
|
CCol,
|
||||||
|
CContainer,
|
||||||
|
CForm,
|
||||||
|
CFormInput,
|
||||||
|
CInputGroup,
|
||||||
|
CInputGroupText,
|
||||||
|
CRow,
|
||||||
|
CSpinner,
|
||||||
|
} from '@coreui/react'
|
||||||
|
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import Swal from 'sweetalert2'
|
||||||
|
import Axios from '../../axios'
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
|
import { faEnvelope } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
const ForgetPassword = () => {
|
||||||
|
const [email, setEmail] = useState('')
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
try {
|
||||||
|
const res = await Axios.post('/api/v1/user/password/forgot', { email })
|
||||||
|
console.log(res)
|
||||||
|
if (res?.status === 200) {
|
||||||
|
Swal.fire('success', res?.data?.message, 'success')
|
||||||
|
navigate('/login')
|
||||||
|
} else if (res?.status === 305) {
|
||||||
|
Swal.fire('error', res?.data?.message, 'error')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
Swal.fire('error', 'User Not found with this email ', 'error')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
|
||||||
|
<CContainer>
|
||||||
|
<CRow className="justify-content-center">
|
||||||
|
<CCol md={8}>
|
||||||
|
<CCardGroup>
|
||||||
|
<CCard className="p-4">
|
||||||
|
<CCardBody>
|
||||||
|
<CForm onSubmit={handleSubmit}>
|
||||||
|
<h1>Forget Password</h1>
|
||||||
|
<p className="text-body-secondary">
|
||||||
|
Enter your email we will send you the password
|
||||||
|
</p>
|
||||||
|
<CInputGroup className="mb-3">
|
||||||
|
<CInputGroupText>
|
||||||
|
<FontAwesomeIcon icon={faEnvelope} />
|
||||||
|
</CInputGroupText>
|
||||||
|
<CFormInput
|
||||||
|
type="email"
|
||||||
|
required
|
||||||
|
placeholder="abc@gmail.com"
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
value={email}
|
||||||
|
name="email"
|
||||||
|
autoComplete="email"
|
||||||
|
/>
|
||||||
|
</CInputGroup>
|
||||||
|
|
||||||
|
<CRow>
|
||||||
|
<CCol xs={12}>
|
||||||
|
<CButton
|
||||||
|
color="primary"
|
||||||
|
type="submit"
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
className="px-4"
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
{loading ? <CSpinner variant="grow" /> : 'Generate password '}
|
||||||
|
</CButton>
|
||||||
|
</CCol>
|
||||||
|
<CCol xs={6} className="text-right">
|
||||||
|
<span className="text-body-secondary">
|
||||||
|
If you know you password? Continue to
|
||||||
|
</span>
|
||||||
|
<CButton onClick={() => navigate('/login')} color="link" className="px-2">
|
||||||
|
Sign in?
|
||||||
|
</CButton>
|
||||||
|
</CCol>
|
||||||
|
</CRow>
|
||||||
|
</CForm>
|
||||||
|
</CCardBody>
|
||||||
|
</CCard>
|
||||||
|
</CCardGroup>
|
||||||
|
</CCol>
|
||||||
|
</CRow>
|
||||||
|
</CContainer>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ForgetPassword
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import {
|
import {
|
||||||
CButton,
|
CButton,
|
||||||
CCard,
|
CCard,
|
||||||
@ -12,11 +12,110 @@ import {
|
|||||||
CInputGroup,
|
CInputGroup,
|
||||||
CInputGroupText,
|
CInputGroupText,
|
||||||
CRow,
|
CRow,
|
||||||
|
CSpinner,
|
||||||
} from '@coreui/react'
|
} from '@coreui/react'
|
||||||
import CIcon from '@coreui/icons-react'
|
import CIcon from '@coreui/icons-react'
|
||||||
import { cilLockLocked, cilUser } from '@coreui/icons'
|
import { cilLockLocked, cilUser } from '@coreui/icons'
|
||||||
|
// import axios from 'axios'
|
||||||
|
import Axios from '../../../axios'
|
||||||
|
import Swal from 'sweetalert2'
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [validForm, setValidForm] = useState(false)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const [auth, setAuth] = useState({
|
||||||
|
email: '',
|
||||||
|
password: '',
|
||||||
|
})
|
||||||
|
const [errors, setErrors] = useState({
|
||||||
|
emailError: '',
|
||||||
|
passwordError: '',
|
||||||
|
})
|
||||||
|
const validEmailRegex = RegExp(
|
||||||
|
/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i,
|
||||||
|
)
|
||||||
|
const validPasswordRegex = RegExp(/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{7,}$/)
|
||||||
|
// const history = useNavigate()
|
||||||
|
// const handleChange = (e) => (event) => {
|
||||||
|
|
||||||
|
// setAuth({ ...auth, [e]: event.target.value });
|
||||||
|
// };
|
||||||
|
const validateForm = () => {
|
||||||
|
let valid = true
|
||||||
|
Object.values(errors).forEach((val) => {
|
||||||
|
if (val.length > 0) {
|
||||||
|
valid = false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Object.values(auth).forEach((val) => {
|
||||||
|
if (val.length <= 0) {
|
||||||
|
valid = false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
//cheking email and password
|
||||||
|
useEffect(() => {
|
||||||
|
if (validateForm()) {
|
||||||
|
setValidForm(true)
|
||||||
|
} else {
|
||||||
|
setValidForm(false)
|
||||||
|
}
|
||||||
|
}, [errors])
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const { name, value } = e.target
|
||||||
|
|
||||||
|
switch (name) {
|
||||||
|
case 'email':
|
||||||
|
setErrors({
|
||||||
|
...errors,
|
||||||
|
emailError: validEmailRegex.test(value) ? '' : 'Email is not valid!',
|
||||||
|
})
|
||||||
|
|
||||||
|
break
|
||||||
|
case 'password':
|
||||||
|
setErrors((errors) => ({
|
||||||
|
...errors,
|
||||||
|
passwordError: validPasswordRegex.test(value)
|
||||||
|
? ''
|
||||||
|
: 'Password Shoud Be 8 Characters Long, Atleast One Uppercase, Atleast One Lowercase,Atleast One Digit, Atleast One Special Character',
|
||||||
|
}))
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
setAuth({ ...auth, [name]: value })
|
||||||
|
}
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
if (!(auth.email && auth.password)) {
|
||||||
|
return Swal.fire('Error!', 'All fields are required', 'error')
|
||||||
|
}
|
||||||
|
setLoading({ loading: 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') {
|
||||||
|
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') {
|
||||||
|
setLoading(false)
|
||||||
|
Swal.fire('error', 'Please login through the PD Credentials ', 'error')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false)
|
||||||
|
|
||||||
|
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>
|
||||||
@ -32,26 +131,53 @@ const Login = () => {
|
|||||||
<CInputGroupText>
|
<CInputGroupText>
|
||||||
<CIcon icon={cilUser} />
|
<CIcon icon={cilUser} />
|
||||||
</CInputGroupText>
|
</CInputGroupText>
|
||||||
<CFormInput placeholder="Username" autoComplete="username" />
|
<CFormInput
|
||||||
|
type="email"
|
||||||
|
placeholder="Email"
|
||||||
|
onChange={handleChange}
|
||||||
|
value={auth.email}
|
||||||
|
name="email"
|
||||||
|
autoComplete="email"
|
||||||
|
/>
|
||||||
</CInputGroup>
|
</CInputGroup>
|
||||||
|
{errors.emailError && (
|
||||||
|
<p className="text-center py-2 text-danger">{errors.emailError}</p>
|
||||||
|
)}
|
||||||
<CInputGroup className="mb-4">
|
<CInputGroup className="mb-4">
|
||||||
<CInputGroupText>
|
<CInputGroupText>
|
||||||
<CIcon icon={cilLockLocked} />
|
<CIcon icon={cilLockLocked} />
|
||||||
</CInputGroupText>
|
</CInputGroupText>
|
||||||
<CFormInput
|
<CFormInput
|
||||||
type="password"
|
type="password"
|
||||||
|
name="password"
|
||||||
|
value={auth.password}
|
||||||
|
onChange={handleChange}
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
/>
|
/>
|
||||||
</CInputGroup>
|
</CInputGroup>
|
||||||
|
|
||||||
|
{errors.passwordError && (
|
||||||
|
<p className="text-center py-2 text-danger">{errors.passwordError}</p>
|
||||||
|
)}
|
||||||
<CRow>
|
<CRow>
|
||||||
<CCol xs={6}>
|
<CCol xs={6}>
|
||||||
<CButton color="primary" className="px-4">
|
<CButton
|
||||||
Login
|
color="primary"
|
||||||
|
type="submit"
|
||||||
|
className="px-4"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
{loading ? <CSpinner variant="grow" /> : 'Login'}
|
||||||
</CButton>
|
</CButton>
|
||||||
</CCol>
|
</CCol>
|
||||||
<CCol xs={6} className="text-right">
|
<CCol xs={6} className="text-right">
|
||||||
<CButton color="link" className="px-0">
|
<CButton
|
||||||
|
onClick={() => navigate('/forget-password')}
|
||||||
|
color="link"
|
||||||
|
className="px-0"
|
||||||
|
>
|
||||||
Forgot password?
|
Forgot password?
|
||||||
</CButton>
|
</CButton>
|
||||||
</CCol>
|
</CCol>
|
||||||
@ -59,22 +185,6 @@ const Login = () => {
|
|||||||
</CForm>
|
</CForm>
|
||||||
</CCardBody>
|
</CCardBody>
|
||||||
</CCard>
|
</CCard>
|
||||||
<CCard className="text-white bg-primary py-5" style={{ width: '44%' }}>
|
|
||||||
<CCardBody className="text-center">
|
|
||||||
<div>
|
|
||||||
<h2>Sign up</h2>
|
|
||||||
<p>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
|
||||||
tempor incididunt ut labore et dolore magna aliqua.
|
|
||||||
</p>
|
|
||||||
<Link to="/register">
|
|
||||||
<CButton color="primary" className="mt-3" active tabIndex={-1}>
|
|
||||||
Register Now!
|
|
||||||
</CButton>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</CCardBody>
|
|
||||||
</CCard>
|
|
||||||
</CCardGroup>
|
</CCardGroup>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
|
@ -2,79 +2,117 @@ import React, { useState } from 'react'
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faAngleLeft, faEnvelope, faLockOpen, faUnlockAlt } from '@fortawesome/free-solid-svg-icons'
|
import { faAngleLeft, faEnvelope, faLockOpen, faUnlockAlt } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { Col, Row, Form, Card, Button, Container, InputGroup } from '@themesberg/react-bootstrap'
|
import { Col, Row, Form, Card, Button, Container, InputGroup } from '@themesberg/react-bootstrap'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
// import axios from 'axios'
|
// import axios from 'axios'
|
||||||
// import { Routes } from '../../routes'
|
// import { Routes } from '../../routes'
|
||||||
|
|
||||||
import Swal from 'sweetalert2'
|
import Swal from 'sweetalert2'
|
||||||
|
import { isAutheticated } from '../../../auth'
|
||||||
|
import Axios from '../../../axios'
|
||||||
// import Axios from '../../axios'
|
// import Axios from '../../axios'
|
||||||
|
|
||||||
const ChangePassword = () => {
|
const ChangePassword = () => {
|
||||||
const [Loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
const navigate = useNavigate()
|
||||||
const [formData, setFormData] = useState({
|
const token = isAutheticated()
|
||||||
|
const [user, setUser] = useState({
|
||||||
oldPassword: '',
|
oldPassword: '',
|
||||||
newPassword: '',
|
newPassword: '',
|
||||||
|
confirmPassword: '',
|
||||||
})
|
})
|
||||||
|
const [errors, setErrors] = useState({
|
||||||
// console.log(formData);
|
confirmPasswordError: '',
|
||||||
const handleInputChange = (e) => {
|
newPasswordError: '',
|
||||||
|
oldPasswordError: '',
|
||||||
|
passwordMismatchError: '',
|
||||||
|
})
|
||||||
|
const validEmailRegex = RegExp(
|
||||||
|
/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i,
|
||||||
|
)
|
||||||
|
const validPasswordRegex = RegExp(/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{7,}$/)
|
||||||
|
const handleChange = (e) => {
|
||||||
const { name, value } = e.target
|
const { name, value } = e.target
|
||||||
setFormData((prevData) => ({ ...prevData, [name]: value }))
|
|
||||||
|
switch (name) {
|
||||||
|
case 'oldPassword':
|
||||||
|
setErrors({
|
||||||
|
...errors,
|
||||||
|
oldPasswordError: validPasswordRegex.test(value)
|
||||||
|
? ''
|
||||||
|
: 'Password Shoud Be 8 Characters Long, Atleast One Uppercase, Atleast One Lowercase,Atleast One Digit, Atleast One Special Character',
|
||||||
|
})
|
||||||
|
|
||||||
|
break
|
||||||
|
case 'newPassword':
|
||||||
|
setErrors({
|
||||||
|
...errors,
|
||||||
|
newPasswordError: validPasswordRegex.test(value)
|
||||||
|
? ''
|
||||||
|
: 'Password Shoud Be 8 Characters Long, Atleast One Uppercase, Atleast One Lowercase,Atleast One Digit, Atleast One Special Character',
|
||||||
|
})
|
||||||
|
|
||||||
|
break
|
||||||
|
case 'confirmPassword':
|
||||||
|
setErrors({
|
||||||
|
...errors,
|
||||||
|
confirmPasswordError: validPasswordRegex.test(value)
|
||||||
|
? ''
|
||||||
|
: 'Password should be 8 characters long, contain at least one uppercase letter, one lowercase letter, one digit, and one special character',
|
||||||
|
passwordMismatchError: value !== user.newPassword ? 'Passwords do not match' : '',
|
||||||
|
})
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
setUser({ ...user, [name]: value })
|
||||||
}
|
}
|
||||||
const formHandler = async (e) => {
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
|
if (!(user.oldPassword && user.newPassword && user.confirmPassword)) {
|
||||||
|
return Swal.fire('Error!', 'All fields are required', 'error')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(user.newPassword.length >= 8)) {
|
||||||
|
return Swal.fire('Error!', 'New password must be 8 characters long', 'error')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.newPassword !== user.confirmPassword) {
|
||||||
|
return Swal.fire('Error!', 'New Password and Confirm Password do not match!', 'error')
|
||||||
|
}
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
// const jwt = localStorage.getItem('jwt')
|
|
||||||
// console.log(jwt);
|
|
||||||
|
|
||||||
// try {
|
try {
|
||||||
// const response = await Axios.post(
|
const res = await Axios.put(
|
||||||
// '/api/password',
|
'/api/v1/user/password/update',
|
||||||
// {
|
{ ...user },
|
||||||
// oldPassword: formData.oldPassword,
|
{
|
||||||
// newPassword: formData.newPassword,
|
headers: {
|
||||||
// },
|
Authorization: `Bearer ${token}`,
|
||||||
// {
|
},
|
||||||
// headers: {
|
},
|
||||||
// jwt: `${jwt}`,
|
)
|
||||||
// 'Content-Type': 'application/json',
|
console.log(res)
|
||||||
// },
|
if (res?.data.success) {
|
||||||
// },
|
Swal.fire({
|
||||||
// )
|
title: 'Done',
|
||||||
// // console.log("response ", response);
|
text: 'Password Changed',
|
||||||
// if (response.status === 200) {
|
icon: 'success',
|
||||||
// // Display success alert
|
confirmButtonText: 'ok',
|
||||||
// Swal.fire({
|
confirmButtonColor: '#303c54',
|
||||||
// icon: 'success',
|
iconColor: '#303c54',
|
||||||
// title: 'Password Changed Successfully',
|
}).then(() => {
|
||||||
// text: 'Your password has been changed successfully!',
|
navigate('/dashboard')
|
||||||
// }).then((result) => {
|
})
|
||||||
// if (result.isConfirmed) {
|
}
|
||||||
// history.push(Routes.Presentation.path)
|
} catch (error) {
|
||||||
// // history.push(Routes.Dashboard.path);
|
Swal.fire('Error!', error.response?.data.message || 'Something went wrong', 'error')
|
||||||
// }
|
} finally {
|
||||||
// })
|
setLoading(false)
|
||||||
|
}
|
||||||
// // Redirect to the dashboard
|
|
||||||
// } else {
|
|
||||||
// // Handle other scenarios if needed
|
|
||||||
// Swal.fire({
|
|
||||||
// icon: 'error',
|
|
||||||
// title: 'Password Change Failed',
|
|
||||||
// text: 'There was an issue changing your password. Please try again.',
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// } catch (err) {
|
|
||||||
// console.log('error is ', err)
|
|
||||||
// Swal.fire({
|
|
||||||
// icon: 'error',
|
|
||||||
// title: 'Password Change Failed',
|
|
||||||
// text: 'There was an error changing your password. Please try again.',
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
setLoading(false)
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
@ -93,7 +131,7 @@ const ChangePassword = () => {
|
|||||||
>
|
>
|
||||||
<div className="bg-white shadow-soft border rounded border-light p-4 p-lg-5 w-100 fmxw-500">
|
<div className="bg-white shadow-soft border rounded border-light p-4 p-lg-5 w-100 fmxw-500">
|
||||||
<h3 className="mb-4">Change Password</h3>
|
<h3 className="mb-4">Change Password</h3>
|
||||||
<Form onSubmit={formHandler}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<Form.Group id="password" className="mb-4">
|
<Form.Group id="password" className="mb-4">
|
||||||
<Form.Label>Old Password</Form.Label>
|
<Form.Label>Old Password</Form.Label>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
@ -105,13 +143,16 @@ const ChangePassword = () => {
|
|||||||
type="password"
|
type="password"
|
||||||
placeholder="old password"
|
placeholder="old password"
|
||||||
name="oldPassword"
|
name="oldPassword"
|
||||||
value={formData.oldPassword}
|
value={user.oldPassword}
|
||||||
onChange={handleInputChange}
|
onChange={handleChange}
|
||||||
pattern="^(?=.*[a-z](){}[])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
|
pattern="^(?=.*[a-z](){}[])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
|
||||||
title="The password should have 1 upper-case letter, 1 lower-case letter, 1 number, 1 special character and at least 8 characters."
|
title="The password should have 1 upper-case letter, 1 lower-case letter, 1 number, 1 special character and at least 8 characters."
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
{errors.oldPasswordError && (
|
||||||
|
<p className="text-center py-2 text-danger">{errors.oldPasswordError}</p>
|
||||||
|
)}
|
||||||
<Form.Group id="password" className="mb-4">
|
<Form.Group id="password" className="mb-4">
|
||||||
<Form.Label>New Password</Form.Label>
|
<Form.Label>New Password</Form.Label>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
@ -123,16 +164,40 @@ const ChangePassword = () => {
|
|||||||
type="password"
|
type="password"
|
||||||
placeholder="new password"
|
placeholder="new password"
|
||||||
name="newPassword"
|
name="newPassword"
|
||||||
value={formData.newPassword}
|
value={user.newPassword}
|
||||||
onChange={handleInputChange}
|
onChange={handleChange}
|
||||||
pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
|
pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
|
||||||
title="The password should have 1 upper-case letter, 1 lower-case letter, 1 number, 1 special character and at least 8 characters."
|
title="The password should have 1 upper-case letter, 1 lower-case letter, 1 number, 1 special character and at least 8 characters."
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
{errors.newPasswordError && (
|
||||||
|
<p className="text-center py-2 text-danger">{errors.newPasswordError}</p>
|
||||||
|
)}
|
||||||
|
<Form.Group id="password" className="mb-4">
|
||||||
|
<Form.Label>Confirm Password</Form.Label>
|
||||||
|
<InputGroup>
|
||||||
|
<InputGroup.Text>
|
||||||
|
<FontAwesomeIcon icon={faLockOpen} />
|
||||||
|
</InputGroup.Text>
|
||||||
|
<Form.Control
|
||||||
|
required
|
||||||
|
type="password"
|
||||||
|
placeholder="Confirm password"
|
||||||
|
name="confirmPassword"
|
||||||
|
value={user.confirmPassword}
|
||||||
|
onChange={handleChange}
|
||||||
|
pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
|
||||||
|
title="The password should have 1 upper-case letter, 1 lower-case letter, 1 number, 1 special character and at least 8 characters."
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
</Form.Group>
|
||||||
|
{errors.confirmPasswordError && (
|
||||||
|
<p className="text-center py-2 text-danger">{errors.confirmPasswordError}</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<Button variant="primary" type="submit" className="w-100">
|
<Button variant="primary" type="submit" className="w-100">
|
||||||
{Loading ? <>Loading...</> : <> Change Password </>}
|
{loading ? <>Loading...</> : <> Change Password </>}
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,6 +10,9 @@ import {
|
|||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { Col, Row, Form, Card, Button, Container, InputGroup } from '@themesberg/react-bootstrap'
|
import { Col, Row, Form, Card, Button, Container, InputGroup } from '@themesberg/react-bootstrap'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
|
import { isAutheticated } from '../../../auth'
|
||||||
|
import Axios from '../../../axios'
|
||||||
|
import Swal from 'sweetalert2'
|
||||||
// import { Axios } from 'axios'
|
// import { Axios } from 'axios'
|
||||||
// import Axios from '../../axios'
|
// import Axios from '../../axios'
|
||||||
// import { Routes } from '../../routes'
|
// import { Routes } from '../../routes'
|
||||||
@ -17,98 +20,91 @@ import { Link, useNavigate } from 'react-router-dom'
|
|||||||
// import Swal from 'sweetalert2'
|
// import Swal from 'sweetalert2'
|
||||||
|
|
||||||
const MyProfile = () => {
|
const MyProfile = () => {
|
||||||
const navigate = useNavigate()
|
const [image, setImage] = useState('')
|
||||||
const [Loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [imagesPreview, setImagesPreview] = useState()
|
||||||
|
const token = isAutheticated()
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [ownerDetails, setOwnerDetails] = useState({
|
||||||
mobile: '',
|
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
|
phone: '',
|
||||||
})
|
})
|
||||||
|
const history = useNavigate()
|
||||||
|
|
||||||
console.log(formData)
|
const getData = async () => {
|
||||||
|
let res = await Axios.get(`/api/v1/user/details`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (res.data.success) {
|
||||||
|
setOwnerDetails({ ...res.data.user })
|
||||||
|
|
||||||
// console.log(formData);
|
if (res.data.user.avatar) {
|
||||||
const handleInputChange = (e) => {
|
setImagesPreview(res.data.user.avatar.url)
|
||||||
const { name, value } = e.target
|
}
|
||||||
setFormData((prevData) => ({ ...prevData, [name]: value }))
|
}
|
||||||
}
|
}
|
||||||
const formHandler = async (e) => {
|
const handleChange = (event) => {
|
||||||
|
const { name, value } = event.target
|
||||||
|
setOwnerDetails({ ...ownerDetails, [name]: value })
|
||||||
|
}
|
||||||
|
async function handleSubmit(e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
// const jwt = localStorage.getItem('jwt')
|
if (ownerDetails.name === '' || ownerDetails.email === '' || ownerDetails.phone === '') {
|
||||||
// console.log(jwt);
|
Swal.fire({
|
||||||
|
title: 'Warning',
|
||||||
|
text: 'Fill all mandatory fields',
|
||||||
|
icon: 'error',
|
||||||
|
button: 'Close',
|
||||||
|
dangerMode: true,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('name', ownerDetails.name)
|
||||||
|
formData.append('email', ownerDetails.email)
|
||||||
|
formData.append('phone', ownerDetails.phone)
|
||||||
|
|
||||||
// try {
|
setLoading(true)
|
||||||
// const response = await Axios.post(
|
try {
|
||||||
// '/api/user',
|
const res = await Axios.put(`/api/v1/user/update/profile`, formData, {
|
||||||
// {
|
headers: {
|
||||||
// username: formData.name,
|
'Access-Control-Allow-Origin': '*',
|
||||||
// newNumber: formData.mobile,
|
Authorization: `Bearer ${token}`,
|
||||||
// email: formData.email,
|
'Content-Type': 'multipart/formdata',
|
||||||
// },
|
},
|
||||||
// {
|
})
|
||||||
// headers: {
|
if (res.data.success === true) {
|
||||||
// jwt: `${jwt}`,
|
setLoading(false)
|
||||||
// 'Content-Type': 'application/json',
|
Swal.fire({
|
||||||
// },
|
title: 'Edited',
|
||||||
// },
|
text: 'Profile Edited Successfully!',
|
||||||
// )
|
icon: 'success',
|
||||||
// // console.log("response ", response);
|
button: 'Return',
|
||||||
// if (response.status === 200) {
|
})
|
||||||
// // Display success alert
|
}
|
||||||
// Swal.fire({
|
} catch (error) {
|
||||||
// icon: 'success',
|
const message = error?.response?.data?.message || 'Something went wrong!'
|
||||||
// title: 'Profile Updated Successfully',
|
setLoading(false)
|
||||||
// text: 'Your Profile has been Updated successfully!',
|
Swal.fire({
|
||||||
// }).then((result) => {
|
title: 'Warning',
|
||||||
// if (result.isConfirmed) {
|
text: message,
|
||||||
// history.push(Routes.Presentation.path)
|
icon: 'error',
|
||||||
// // history.push(Routes.Dashboard.path);
|
button: 'Retry',
|
||||||
// }
|
dangerMode: true,
|
||||||
// })
|
})
|
||||||
|
}
|
||||||
// // Redirect to the dashboard
|
|
||||||
// } else {
|
|
||||||
// // Handle other scenarios if needed
|
|
||||||
// Swal.fire({
|
|
||||||
// icon: 'error',
|
|
||||||
// title: 'Profile Update Failed',
|
|
||||||
// text: 'There was an issue updating your profile. Please try again.',
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// } catch (err) {
|
|
||||||
// console.log('error is ', err)
|
|
||||||
// Swal.fire({
|
|
||||||
// icon: 'error',
|
|
||||||
// title: 'Profile Update Failed',
|
|
||||||
// text: 'There was an issue updating your profile. Please try again.',
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
// const getMe = async () => {
|
console.log(ownerDetails)
|
||||||
// const jwt = localStorage.getItem('jwt')
|
const handleCancle = () => {
|
||||||
|
Navigate('/dashboard')
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
getData()
|
||||||
|
}, [])
|
||||||
|
|
||||||
// try {
|
|
||||||
// const respose = await Axios.get('/api/getMe', {
|
|
||||||
// headers: {
|
|
||||||
// jwt: `${jwt}`,
|
|
||||||
// 'Content-Type': 'application/json',
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
|
|
||||||
// // console.log(respose.data);
|
|
||||||
// setFormData({
|
|
||||||
// mobile: respose?.data?.number,
|
|
||||||
// name: respose?.data?.name,
|
|
||||||
// email: respose?.data?.email,
|
|
||||||
// })
|
|
||||||
// } catch (err) {
|
|
||||||
// console.log('error in get user', err)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// useEffect(() => {
|
|
||||||
// getMe()
|
|
||||||
// }, [])
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<section className="bg-soft d-flex align-items-center my-5 mt-lg-6 mb-lg-5">
|
<section className="bg-soft d-flex align-items-center my-5 mt-lg-6 mb-lg-5">
|
||||||
@ -122,7 +118,7 @@ const MyProfile = () => {
|
|||||||
<Col xs={12} className="d-flex align-items-center justify-content-center">
|
<Col xs={12} className="d-flex align-items-center justify-content-center">
|
||||||
<div className="bg-white shadow-soft border rounded border-light p-4 p-lg-5 w-100 fmxw-500">
|
<div className="bg-white shadow-soft border rounded border-light p-4 p-lg-5 w-100 fmxw-500">
|
||||||
<h3 className="mb-4">Profile</h3>
|
<h3 className="mb-4">Profile</h3>
|
||||||
<Form onSubmit={formHandler}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<Form.Group id="name" className="mb-4">
|
<Form.Group id="name" className="mb-4">
|
||||||
<Form.Label>Name</Form.Label>
|
<Form.Label>Name</Form.Label>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
@ -134,8 +130,8 @@ const MyProfile = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
placeholder="Your Name"
|
placeholder="Your Name"
|
||||||
name="name"
|
name="name"
|
||||||
value={formData.name}
|
value={ownerDetails.name}
|
||||||
onChange={handleInputChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
@ -152,9 +148,9 @@ const MyProfile = () => {
|
|||||||
type="email"
|
type="email"
|
||||||
placeholder="example@gmail.com"
|
placeholder="example@gmail.com"
|
||||||
name="email"
|
name="email"
|
||||||
value={formData.email}
|
value={ownerDetails.email}
|
||||||
onChange={handleInputChange}
|
onChange={handleChange}
|
||||||
pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
|
// pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
|
||||||
title="Please enter a valid email address"
|
title="Please enter a valid email address"
|
||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
@ -171,8 +167,8 @@ const MyProfile = () => {
|
|||||||
type="tel"
|
type="tel"
|
||||||
placeholder="Your Mobile Number"
|
placeholder="Your Mobile Number"
|
||||||
name="mobile"
|
name="mobile"
|
||||||
value={formData.mobile}
|
value={ownerDetails.phone}
|
||||||
onChange={handleInputChange}
|
onChange={handleChange}
|
||||||
// pattern="[0-9]{10}" // Assuming a 10-digit mobile number, adjust as needed
|
// pattern="[0-9]{10}" // Assuming a 10-digit mobile number, adjust as needed
|
||||||
title="Please enter a valid 10-digit mobile number"
|
title="Please enter a valid 10-digit mobile number"
|
||||||
/>
|
/>
|
||||||
@ -180,7 +176,7 @@ const MyProfile = () => {
|
|||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
<Button variant="primary" type="submit" className="w-100">
|
<Button variant="primary" type="submit" className="w-100">
|
||||||
{Loading ? <>Loading...</> : <>Update</>}
|
{loading ? <>Loading...</> : <>Update</>}
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,58 @@
|
|||||||
import React from 'react'
|
import {
|
||||||
|
Box,
|
||||||
|
Card,
|
||||||
|
CircularProgress,
|
||||||
|
Container,
|
||||||
|
FormControl,
|
||||||
|
Grid,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
|
Typography,
|
||||||
|
} from '@mui/material'
|
||||||
|
import cardData from '../../assets/data/cardjson.json'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import ShopCard from './shopCard'
|
||||||
|
|
||||||
const Shop = () => {
|
const Shop = () => {
|
||||||
|
const [option, setOption] = useState('all')
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
setOption(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredData =
|
||||||
|
option === 'all' ? cardData : cardData.filter((item) => item.categoryName === option)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>Shop</div>
|
<Container>
|
||||||
|
<Typography sx={{ fontWeight: 'bold' }} variant="h4">
|
||||||
|
Categories
|
||||||
|
</Typography>
|
||||||
|
<Select
|
||||||
|
sx={{ width: '400px', mt: '1rem' }}
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
value={option}
|
||||||
|
label=""
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
<MenuItem value="all">All</MenuItem>
|
||||||
|
<MenuItem value="camera">Camera</MenuItem>
|
||||||
|
<MenuItem value="phone">Phone</MenuItem>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<Box mt={3}>
|
||||||
|
{/* Cards */}
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{filteredData.map((item, i) => (
|
||||||
|
<Grid key={i} item xs={12} sm={6} md={4} lg={4}>
|
||||||
|
<ShopCard item={item} />
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</Container>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
33
src/views/shops/shopCard.js
Normal file
33
src/views/shops/shopCard.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { Button, Card, CardContent, CardMedia, Typography } from '@mui/material'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/prop-types
|
||||||
|
const ShopCard = ({ item }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Card>
|
||||||
|
<CardMedia component="img" height="150" image={item?.image} alt={item?.name} />
|
||||||
|
<CardContent>
|
||||||
|
<Typography gutterBottom variant="h5" component="div">
|
||||||
|
{item?.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
${item?.price}
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
fullWidth
|
||||||
|
// onClick={handleAddToCart}
|
||||||
|
sx={{ marginTop: '10px' }}
|
||||||
|
>
|
||||||
|
Add to Cart
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ShopCard
|
Loading…
Reference in New Issue
Block a user