title of page changes , product page done and content page completed
This commit is contained in:
parent
d40bcdbff4
commit
34948d795b
@ -41,19 +41,22 @@
|
|||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@material-ui/core": "^4.12.4",
|
"@material-ui/core": "^4.12.4",
|
||||||
"@material-ui/data-grid": "^4.0.0-alpha.37",
|
"@material-ui/data-grid": "^4.0.0-alpha.37",
|
||||||
"@mui/icons-material": "^5.14.13",
|
"@mui/icons-material": "^5.14.14",
|
||||||
"@mui/material": "^5.11.12",
|
"@mui/material": "^5.11.12",
|
||||||
"@reduxjs/toolkit": "^1.9.2",
|
"@reduxjs/toolkit": "^1.9.2",
|
||||||
"axios": "^0.25.0",
|
"axios": "^0.25.0",
|
||||||
"bootstrap": "^5.1.3",
|
"bootstrap": "^5.1.3",
|
||||||
"country-state-city": "^3.1.2",
|
"country-state-city": "^3.1.2",
|
||||||
|
"md5": "^2.3.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
"quill": "^1.3.7",
|
||||||
"react": "18.0.0",
|
"react": "18.0.0",
|
||||||
"react-bootstrap": "^2.7.0",
|
"react-bootstrap": "^2.7.0",
|
||||||
"react-datepicker": "^4.8.0",
|
"react-datepicker": "^4.8.0",
|
||||||
"react-dom": "^18.0.0",
|
"react-dom": "^18.0.0",
|
||||||
"react-hot-toast": "^2.4.0",
|
"react-hot-toast": "^2.4.0",
|
||||||
"react-qr-code": "^2.0.11",
|
"react-qr-code": "^2.0.11",
|
||||||
|
"react-quill": "^2.0.0",
|
||||||
"react-redux": "^7.2.9",
|
"react-redux": "^7.2.9",
|
||||||
"react-router-dom": "^6.7.0",
|
"react-router-dom": "^6.7.0",
|
||||||
"react-spinners": "^0.11.0",
|
"react-spinners": "^0.11.0",
|
||||||
@ -67,6 +70,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"auto-changelog": "~2.3.0",
|
"auto-changelog": "~2.3.0",
|
||||||
|
"fuse.js": "^6.6.2",
|
||||||
"react-scripts": "^4.0.3",
|
"react-scripts": "^4.0.3",
|
||||||
"sass": "^1.43.5"
|
"sass": "^1.43.5"
|
||||||
},
|
},
|
||||||
|
@ -7,23 +7,34 @@
|
|||||||
* License MIT
|
* License MIT
|
||||||
-->
|
-->
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
<head>
|
||||||
<head>
|
<meta charset="utf-8" />
|
||||||
<meta charset="utf-8">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
name="viewport"
|
||||||
<meta name="description" content="CoreUI for React - Open Source Bootstrap Admin Template">
|
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||||
<meta name="author" content="Łukasz Holeczek">
|
/>
|
||||||
<meta name="keyword" content="Bootstrap,Admin,Template,Open,Source,CSS,SCSS,HTML,RWD,Dashboard,React">
|
<meta
|
||||||
<title>SOLAR Sign Admin</title>
|
name="description"
|
||||||
|
content="CoreUI for React - Open Source Bootstrap Admin Template"
|
||||||
|
/>
|
||||||
|
<meta name="author" content="Łukasz Holeczek" />
|
||||||
|
<meta
|
||||||
|
name="keyword"
|
||||||
|
content="Bootstrap,Admin,Template,Open,Source,CSS,SCSS,HTML,RWD,Dashboard,React"
|
||||||
|
/>
|
||||||
|
<title>The Solar Sign</title>
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is added to the
|
manifest.json provides metadata used when your web app is added to the
|
||||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||||
-->
|
-->
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
|
<link
|
||||||
<link rel="react" href="https://coreui.io/react/">
|
rel="stylesheet"
|
||||||
|
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
|
||||||
|
/>
|
||||||
|
<link rel="react" href="https://coreui.io/react/" />
|
||||||
|
|
||||||
<!-- <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script> -->
|
<!-- <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script> -->
|
||||||
<!--
|
<!--
|
||||||
@ -40,12 +51,10 @@
|
|||||||
|
|
||||||
<!-- <link href="/assets/libs/bootstrap-datepicker/css/bootstrap-datepicker.min.css" rel="stylesheet" /> -->
|
<!-- <link href="/assets/libs/bootstrap-datepicker/css/bootstrap-datepicker.min.css" rel="stylesheet" /> -->
|
||||||
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" /> -->
|
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" /> -->
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript> You need to enable JavaScript to run this app. </noscript>
|
||||||
You need to enable JavaScript to run this app.
|
|
||||||
</noscript>
|
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<!--
|
<!--
|
||||||
This HTML file is a template.
|
This HTML file is a template.
|
||||||
@ -57,9 +66,6 @@
|
|||||||
To begin the development, run `npm start` or `yarn start`.
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
-->
|
-->
|
||||||
|
</body>
|
||||||
|
<!-- <script src="/assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script> -->
|
||||||
</body>
|
|
||||||
<!-- <script src="/assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script> -->
|
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -107,6 +107,12 @@ const _nav = [
|
|||||||
icon: <CIcon icon={cilContact} customClassName="nav-icon" />,
|
icon: <CIcon icon={cilContact} customClassName="nav-icon" />,
|
||||||
to: "/contact/request",
|
to: "/contact/request",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
component: CNavItem,
|
||||||
|
name: "Content ",
|
||||||
|
icon: <CIcon icon={cilText} customClassName="nav-icon" />,
|
||||||
|
to: "/content",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,38 +1,43 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from "react";
|
||||||
import { useSelector, useDispatch } from 'react-redux'
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { CSidebar, CSidebarBrand, CSidebarNav, CSidebarToggler } from '@coreui/react'
|
import {
|
||||||
import CIcon from '@coreui/icons-react'
|
CSidebar,
|
||||||
|
CSidebarBrand,
|
||||||
|
CSidebarNav,
|
||||||
|
CSidebarToggler,
|
||||||
|
} from "@coreui/react";
|
||||||
|
import CIcon from "@coreui/icons-react";
|
||||||
|
|
||||||
import { AppSidebarNav } from './AppSidebarNav'
|
import { AppSidebarNav } from "./AppSidebarNav";
|
||||||
|
|
||||||
import { logoNegative } from 'src/assets/brand/logo-negative'
|
import { logoNegative } from "src/assets/brand/logo-negative";
|
||||||
import { sygnet } from 'src/assets/brand/sygnet'
|
import { sygnet } from "src/assets/brand/sygnet";
|
||||||
|
|
||||||
import SimpleBar from 'simplebar-react'
|
import SimpleBar from "simplebar-react";
|
||||||
import 'simplebar/dist/simplebar.min.css'
|
import "simplebar/dist/simplebar.min.css";
|
||||||
|
|
||||||
// sidebar nav config
|
// sidebar nav config
|
||||||
import navigation from '../_nav'
|
import navigation from "../_nav";
|
||||||
import { isAutheticated } from 'src/auth'
|
import { isAutheticated } from "src/auth";
|
||||||
import axios from 'axios'
|
import axios from "axios";
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
const AppSidebar = () => {
|
const AppSidebar = () => {
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch();
|
||||||
const unfoldable = useSelector((state) => state.sidebarUnfoldable)
|
const unfoldable = useSelector((state) => state.sidebarUnfoldable);
|
||||||
const sidebarShow = useSelector((state) => state.sidebarShow)
|
const sidebarShow = useSelector((state) => state.sidebarShow);
|
||||||
|
|
||||||
///----------------------//
|
///----------------------//
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const token = isAutheticated()
|
const token = isAutheticated();
|
||||||
|
|
||||||
// urlcreated images
|
// urlcreated images
|
||||||
const [AppName, setAppName] = useState('')
|
const [AppName, setAppName] = useState("");
|
||||||
const [HeaderlogoUrl, setHeaderlogoUrl] = useState('')
|
const [HeaderlogoUrl, setHeaderlogoUrl] = useState("");
|
||||||
const [FooterlogoUrl, setFooterlogoUrl] = useState('')
|
const [FooterlogoUrl, setFooterlogoUrl] = useState("");
|
||||||
const [AdminlogoUrl, setAdminlogoUrl] = useState('')
|
const [AdminlogoUrl, setAdminlogoUrl] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getConfiguration() {
|
async function getConfiguration() {
|
||||||
@ -40,16 +45,16 @@ const AppSidebar = () => {
|
|||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
setAppName(configDetails.data.result[0]?.appName)
|
setAppName(configDetails.data.result[0]?.appName);
|
||||||
configDetails.data.result.map((item) => {
|
configDetails.data.result.map((item) => {
|
||||||
setHeaderlogoUrl(item?.logo[0]?.Headerlogo)
|
setHeaderlogoUrl(item?.logo[0]?.Headerlogo);
|
||||||
setFooterlogoUrl(item?.logo[0]?.Footerlogo)
|
setFooterlogoUrl(item?.logo[0]?.Footerlogo);
|
||||||
setAdminlogoUrl(item?.logo[0]?.Adminlogo)
|
setAdminlogoUrl(item?.logo[0]?.Adminlogo);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
getConfiguration()
|
getConfiguration();
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
//---------------------------//
|
//---------------------------//
|
||||||
return (
|
return (
|
||||||
@ -58,13 +63,25 @@ const AppSidebar = () => {
|
|||||||
unfoldable={unfoldable}
|
unfoldable={unfoldable}
|
||||||
visible={sidebarShow}
|
visible={sidebarShow}
|
||||||
onVisibleChange={(visible) => {
|
onVisibleChange={(visible) => {
|
||||||
dispatch({ type: 'set', sidebarShow: visible })
|
dispatch({ type: "set", sidebarShow: visible });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CSidebarBrand className="d-none d-md-flex" style={{ background: 'rgb(140, 213, 213)' }} to="/">
|
<CSidebarBrand
|
||||||
|
className="d-none d-md-flex"
|
||||||
|
style={{ background: "rgb(140, 213, 213)" }}
|
||||||
|
to="/"
|
||||||
|
>
|
||||||
{/* <CIcon className="sidebar-brand-full" icon={logoNegative} height={35} /> */}
|
{/* <CIcon className="sidebar-brand-full" icon={logoNegative} height={35} /> */}
|
||||||
|
|
||||||
{HeaderlogoUrl ? <Link to='/dashboard'><img src={HeaderlogoUrl} alt='' width='100%' /></Link> : { AppName } ? <h2>Solar Sign </h2> : ''}
|
{HeaderlogoUrl ? (
|
||||||
|
<Link to="/dashboard">
|
||||||
|
<img src={HeaderlogoUrl} alt="" width="100%" />
|
||||||
|
</Link>
|
||||||
|
) : { AppName } ? (
|
||||||
|
<h2>The Solar Sign </h2>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
{/* <CIcon className="sidebar-brand-narrow" height={35} /> */}
|
{/* <CIcon className="sidebar-brand-narrow" height={35} /> */}
|
||||||
<CIcon className="sidebar-brand-narrow" icon={sygnet} height={35} />
|
<CIcon className="sidebar-brand-narrow" icon={sygnet} height={35} />
|
||||||
</CSidebarBrand>
|
</CSidebarBrand>
|
||||||
@ -75,10 +92,12 @@ const AppSidebar = () => {
|
|||||||
</CSidebarNav>
|
</CSidebarNav>
|
||||||
<CSidebarToggler
|
<CSidebarToggler
|
||||||
className="d-none d-lg-flex"
|
className="d-none d-lg-flex"
|
||||||
onClick={() => dispatch({ type: 'set', sidebarUnfoldable: !unfoldable })}
|
onClick={() =>
|
||||||
|
dispatch({ type: "set", sidebarUnfoldable: !unfoldable })
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</CSidebar>
|
</CSidebar>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default React.memo(AppSidebar)
|
export default React.memo(AppSidebar);
|
||||||
|
@ -83,6 +83,11 @@ import ViewHealthCareProvider from "./views/Business/ViewHealthCareProvider";
|
|||||||
import Campaign from "./views/Campaigns/Campaign.js";
|
import Campaign from "./views/Campaigns/Campaign.js";
|
||||||
import AddCampaign from "./views/Campaigns/AddCampaign.js";
|
import AddCampaign from "./views/Campaigns/AddCampaign.js";
|
||||||
import Categories from "./views/Categories/categories";
|
import Categories from "./views/Categories/categories";
|
||||||
|
import Content from "./views/Content/content";
|
||||||
|
|
||||||
|
import EditPrivacyPolicy from "./views/Content/editPrivacyPolicy";
|
||||||
|
import EditTermsConditions from "./views/Content/editTermsConditions";
|
||||||
|
import EditShippingPolicy from "./views/Content/editShippingPolicy";
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: "/", exact: true, name: "Home" },
|
{ path: "/", exact: true, name: "Home" },
|
||||||
{
|
{
|
||||||
@ -183,6 +188,30 @@ const routes = [
|
|||||||
name: "AddContact Request",
|
name: "AddContact Request",
|
||||||
element: AddContactRequest,
|
element: AddContactRequest,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Content ---- >
|
||||||
|
|
||||||
|
{
|
||||||
|
path: "/content",
|
||||||
|
name: "Content",
|
||||||
|
element: Content,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/content/terms-and-conditions",
|
||||||
|
name: "Content",
|
||||||
|
element: EditTermsConditions,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/content/privacy-policy",
|
||||||
|
name: "Content",
|
||||||
|
element: EditPrivacyPolicy,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/content/shipping-policy",
|
||||||
|
name: "Content",
|
||||||
|
element: EditShippingPolicy,
|
||||||
|
},
|
||||||
|
|
||||||
// { path: '/complaint/view/:id', name: 'view Complain', element: ViewComplaint },
|
// { path: '/complaint/view/:id', name: 'view Complain', element: ViewComplaint },
|
||||||
//Complaints
|
//Complaints
|
||||||
{ path: "/testimonials", name: "Testimonials", element: Testimonials },
|
{ path: "/testimonials", name: "Testimonials", element: Testimonials },
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
$enable-ltr: true;
|
$enable-ltr: true;
|
||||||
$enable-rtl: true;
|
$enable-rtl: true;
|
||||||
|
|
||||||
|
|
||||||
// Import CoreUI for React components library
|
// Import CoreUI for React components library
|
||||||
//@import "@coreui/coreui/scss/coreui";
|
//@import "@coreui/coreui/scss/coreui";
|
||||||
// Import Chart.js custom tooltips styles
|
// Import Chart.js custom tooltips styles
|
||||||
@ -15,3 +14,9 @@ $enable-rtl: true;
|
|||||||
|
|
||||||
// If you want to add custom CSS you can put it here.
|
// If you want to add custom CSS you can put it here.
|
||||||
@import "custom";
|
@import "custom";
|
||||||
|
|
||||||
|
.container .ql-editor {
|
||||||
|
min-height: 5in;
|
||||||
|
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
@ -277,11 +277,23 @@ const Categories = () => {
|
|||||||
placeholder="category name"
|
placeholder="category name"
|
||||||
value={categoryName}
|
value={categoryName}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
inputProps={{
|
||||||
|
maxLength: 25,
|
||||||
|
}}
|
||||||
style={{
|
style={{
|
||||||
padding: "1rem",
|
padding: "1rem",
|
||||||
}}
|
}}
|
||||||
onChange={(e) => setCategoryName(e.target.value)}
|
onChange={(e) => setCategoryName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
{categoryName ? (
|
||||||
|
<>
|
||||||
|
<small className="charLeft mt-2 ml-3 fst-italic">
|
||||||
|
{25 - categoryName.length} characters left
|
||||||
|
</small>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
<Box
|
<Box
|
||||||
p={2}
|
p={2}
|
||||||
display={"flex"}
|
display={"flex"}
|
||||||
|
86
src/views/Content/content.js
Normal file
86
src/views/Content/content.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Paper,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
|
import React from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
export default function Content() {
|
||||||
|
const pages = [
|
||||||
|
{
|
||||||
|
name: "Terms & Conditions ",
|
||||||
|
action: "Edit",
|
||||||
|
path: "/content/terms-and-conditions",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Privacy Policy ",
|
||||||
|
action: "Edit",
|
||||||
|
path: "/content/privacy-policy",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Shipping Policy ",
|
||||||
|
action: "Edit",
|
||||||
|
path: "/content/shipping-policy",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="main-content">
|
||||||
|
<Typography variant="h6" fontWeight={"bold"}>
|
||||||
|
Content
|
||||||
|
</Typography>
|
||||||
|
<TableContainer component={Paper}>
|
||||||
|
<Table sx={{ minWidth: 650 }} aria-label="simple table">
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell style={{ fontWeight: "bold" }}>Page</TableCell>
|
||||||
|
<TableCell style={{ fontWeight: "bold" }} align="right">
|
||||||
|
Action
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{pages.map((row) => (
|
||||||
|
<TableRow
|
||||||
|
key={row.name}
|
||||||
|
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||||
|
>
|
||||||
|
<TableCell component="th" scope="row">
|
||||||
|
{row.name}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="right">
|
||||||
|
{" "}
|
||||||
|
<Link to={row.path}>
|
||||||
|
<button
|
||||||
|
style={{
|
||||||
|
color: "white",
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className="
|
||||||
|
btn btn-info btn-sm
|
||||||
|
waves-effect waves-light
|
||||||
|
btn-table
|
||||||
|
mt-1
|
||||||
|
mx-1
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{row.action}
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
160
src/views/Content/editPrivacyPolicy.js
Normal file
160
src/views/Content/editPrivacyPolicy.js
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
import { Typography } from "@material-ui/core";
|
||||||
|
import { Box, Button, TextField } from "@mui/material";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import ReactrichTextEditor from "./reactrichTextEditor";
|
||||||
|
import ReactQuill from "react-quill";
|
||||||
|
import "react-quill/dist/quill.snow.css";
|
||||||
|
import axios from "axios";
|
||||||
|
import { isAutheticated } from "src/auth";
|
||||||
|
import { useNavigate, useNavigation } from "react-router-dom";
|
||||||
|
|
||||||
|
const TOOLBAR_OPTIONS = [
|
||||||
|
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||||
|
[{ font: [] }],
|
||||||
|
[{ list: "ordered" }, { list: "bullet" }],
|
||||||
|
["bold", "italic", "underline"],
|
||||||
|
[{ color: [] }, { background: [] }],
|
||||||
|
[{ align: [] }],
|
||||||
|
];
|
||||||
|
export default function EditPrivacyPolicy() {
|
||||||
|
const [title, setTitle] = useState("Privacy Policy");
|
||||||
|
const [content, setContent] = useState("");
|
||||||
|
const [added, setAdded] = useState(false);
|
||||||
|
const [olderContent, setOlderContent] = useState("");
|
||||||
|
const navigation = useNavigate();
|
||||||
|
|
||||||
|
const token = isAutheticated();
|
||||||
|
const handleContentChange = (content, delta, source, editor) => {
|
||||||
|
setContent(editor.getHTML());
|
||||||
|
};
|
||||||
|
const getPrivacyPolicy = async () => {
|
||||||
|
const response = await axios.get("/api/content/privacy-and-policy", {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log(response);
|
||||||
|
|
||||||
|
setContent(response?.data?.privacyAndPolicy[0]?.privacyAndPolicyContent);
|
||||||
|
setOlderContent(
|
||||||
|
response?.data?.privacyAndPolicy[0]?.privacyAndPolicyContent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addPrivacyPolicy = async () => {
|
||||||
|
const response = await axios.post(
|
||||||
|
"/api/content/privacy-and-policy",
|
||||||
|
{ content },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.status == 201) {
|
||||||
|
swal({
|
||||||
|
title: "Congratulations!!",
|
||||||
|
text: "Terms and condition added successfully!",
|
||||||
|
icon: "success",
|
||||||
|
button: "OK",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleCancelClick = () => {
|
||||||
|
setContent(olderContent);
|
||||||
|
};
|
||||||
|
const updateContent = async () => {
|
||||||
|
const response = await axios.patch(
|
||||||
|
"/api/content/privacy-and-policy-update",
|
||||||
|
{ content },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.status === 200) {
|
||||||
|
swal({
|
||||||
|
title: "Congratulations!!",
|
||||||
|
text: "Terms and condition updated successfully!",
|
||||||
|
icon: "success",
|
||||||
|
button: "OK",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
swal({
|
||||||
|
title: "Sorry, please try again",
|
||||||
|
text: "Something went wrong!",
|
||||||
|
icon: "error",
|
||||||
|
button: "Retry",
|
||||||
|
dangerMode: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleSaveClick = async () => {
|
||||||
|
if (olderContent === undefined) {
|
||||||
|
await addPrivacyPolicy();
|
||||||
|
setAdded(true);
|
||||||
|
} else {
|
||||||
|
await updateContent();
|
||||||
|
setAdded(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload terms and conditions
|
||||||
|
await getPrivacyPolicy();
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
// addTermsandConditions();
|
||||||
|
getPrivacyPolicy();
|
||||||
|
}, [added]);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleSaveClick}
|
||||||
|
style={{
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: "1rem",
|
||||||
|
textTransform: "capitalize",
|
||||||
|
marginRight: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleCancelClick}
|
||||||
|
style={{
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: "1rem",
|
||||||
|
textTransform: "capitalize",
|
||||||
|
marginRight: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Box style={{ background: "#FFFFFF", color: "black", padding: "1rem" }}>
|
||||||
|
<Typography
|
||||||
|
style={{ margin: "0.5rem 0rem", fontWeight: "bold" }}
|
||||||
|
variant="h6"
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
Privacy and policy:{" "}
|
||||||
|
</Typography>
|
||||||
|
<Typography style={{ margin: "0.5rem 0rem" }}>Body</Typography>
|
||||||
|
<ReactQuill
|
||||||
|
theme="snow"
|
||||||
|
value={content}
|
||||||
|
onChange={handleContentChange}
|
||||||
|
modules={{ toolbar: TOOLBAR_OPTIONS }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
166
src/views/Content/editShippingPolicy.js
Normal file
166
src/views/Content/editShippingPolicy.js
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
import { Typography } from "@material-ui/core";
|
||||||
|
import { Box, Button, TextField } from "@mui/material";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import ReactrichTextEditor from "./reactrichTextEditor";
|
||||||
|
import ReactQuill from "react-quill";
|
||||||
|
import "react-quill/dist/quill.snow.css";
|
||||||
|
import axios from "axios";
|
||||||
|
import { isAutheticated } from "src/auth";
|
||||||
|
import { useNavigate, useNavigation } from "react-router-dom";
|
||||||
|
|
||||||
|
const TOOLBAR_OPTIONS = [
|
||||||
|
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||||
|
[{ font: [] }],
|
||||||
|
[{ list: "ordered" }, { list: "bullet" }],
|
||||||
|
["bold", "italic", "underline"],
|
||||||
|
[{ color: [] }, { background: [] }],
|
||||||
|
[{ align: [] }],
|
||||||
|
];
|
||||||
|
export default function EditShippingPolicy() {
|
||||||
|
const [title, setTitle] = useState("Shipping Policy");
|
||||||
|
const [content, setContent] = useState("");
|
||||||
|
const [added, setAdded] = useState(false);
|
||||||
|
const [olderContent, setOlderContent] = useState("");
|
||||||
|
const navigation = useNavigate();
|
||||||
|
|
||||||
|
const token = isAutheticated();
|
||||||
|
const handleContentChange = (content, delta, source, editor) => {
|
||||||
|
setContent(editor.getHTML());
|
||||||
|
};
|
||||||
|
const getShipping = async () => {
|
||||||
|
const response = await axios.get("/api/content/shipping-and-policy", {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log(response);
|
||||||
|
|
||||||
|
setContent(response?.data?.shipping[0]?.shippingContent);
|
||||||
|
setOlderContent(response?.data?.shipping[0]?.shippingContent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addShipping = async () => {
|
||||||
|
const response = await axios.post(
|
||||||
|
"/api/content/shipping-and-policy",
|
||||||
|
{ content },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.status == 201) {
|
||||||
|
swal({
|
||||||
|
title: "Congratulations!!",
|
||||||
|
text: "Terms and condition added successfully!",
|
||||||
|
icon: "success",
|
||||||
|
button: "OK",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleCancelClick = () => {
|
||||||
|
setContent(olderContent);
|
||||||
|
};
|
||||||
|
const updateContent = async () => {
|
||||||
|
const response = await axios.patch(
|
||||||
|
"/api/content/shipping-and-policy-update",
|
||||||
|
{ content },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.status === 200) {
|
||||||
|
swal({
|
||||||
|
title: "Congratulations!!",
|
||||||
|
text: "Terms and condition updated successfully!",
|
||||||
|
icon: "success",
|
||||||
|
button: "OK",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
swal({
|
||||||
|
title: "Sorry, please try again",
|
||||||
|
text: "Something went wrong!",
|
||||||
|
icon: "error",
|
||||||
|
button: "Retry",
|
||||||
|
dangerMode: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleSaveClick = async () => {
|
||||||
|
if (olderContent === undefined) {
|
||||||
|
await addShipping();
|
||||||
|
setAdded(true);
|
||||||
|
} else {
|
||||||
|
await updateContent();
|
||||||
|
setAdded(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload terms and conditions
|
||||||
|
await getShipping();
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
// addTermsandConditions();
|
||||||
|
getShipping();
|
||||||
|
}, [added]);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleSaveClick}
|
||||||
|
style={{
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: "1rem",
|
||||||
|
textTransform: "capitalize",
|
||||||
|
marginRight: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleCancelClick}
|
||||||
|
style={{
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: "1rem",
|
||||||
|
textTransform: "capitalize",
|
||||||
|
marginRight: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Box style={{ background: "#FFFFFF", color: "black", padding: "1rem" }}>
|
||||||
|
{/* <TextField
|
||||||
|
type="text"
|
||||||
|
value={title}
|
||||||
|
onChange={(e) => setTitle(e.target.value)}
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
/> */}
|
||||||
|
<Typography
|
||||||
|
style={{ margin: "0.5rem 0rem", fontWeight: "bold" }}
|
||||||
|
variant="h6"
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
Shipping and policy:{" "}
|
||||||
|
</Typography>
|
||||||
|
<Typography style={{ margin: "0.5rem 0rem" }}>Body</Typography>
|
||||||
|
<ReactQuill
|
||||||
|
theme="snow"
|
||||||
|
value={content}
|
||||||
|
onChange={handleContentChange}
|
||||||
|
modules={{ toolbar: TOOLBAR_OPTIONS }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
167
src/views/Content/editTermsConditions.js
Normal file
167
src/views/Content/editTermsConditions.js
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
import { Typography } from "@material-ui/core";
|
||||||
|
import { Box, Button, TextField } from "@mui/material";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import ReactrichTextEditor from "./reactrichTextEditor";
|
||||||
|
import ReactQuill from "react-quill";
|
||||||
|
import "react-quill/dist/quill.snow.css";
|
||||||
|
import axios from "axios";
|
||||||
|
import { isAutheticated } from "src/auth";
|
||||||
|
import { useNavigate, useNavigation } from "react-router-dom";
|
||||||
|
|
||||||
|
const TOOLBAR_OPTIONS = [
|
||||||
|
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||||
|
[{ font: [] }],
|
||||||
|
[{ list: "ordered" }, { list: "bullet" }],
|
||||||
|
["bold", "italic", "underline"],
|
||||||
|
[{ color: [] }, { background: [] }],
|
||||||
|
[{ align: [] }],
|
||||||
|
];
|
||||||
|
export default function EditTermsConditions() {
|
||||||
|
const [title, setTitle] = useState("Terms and conditions");
|
||||||
|
const [content, setContent] = useState("");
|
||||||
|
const [added, setAdded] = useState(false);
|
||||||
|
const [olderContent, setOlderContent] = useState("");
|
||||||
|
const navigation = useNavigate();
|
||||||
|
|
||||||
|
const token = isAutheticated();
|
||||||
|
const handleContentChange = (content, delta, source, editor) => {
|
||||||
|
setContent(editor.getHTML());
|
||||||
|
};
|
||||||
|
const getTermsAndConditions = async () => {
|
||||||
|
const response = await axios.get("/api/content/terms-and-conditions", {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log(response);
|
||||||
|
setContent(response?.data?.termsAndCondition[0]?.termsAndContionContent);
|
||||||
|
setOlderContent(
|
||||||
|
response?.data?.termsAndCondition[0]?.termsAndContionContent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addTermsandConditions = async () => {
|
||||||
|
const response = await axios.post(
|
||||||
|
"/api/content/terms-and-conditions",
|
||||||
|
{ content },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.status == 201) {
|
||||||
|
swal({
|
||||||
|
title: "Congratulations!!",
|
||||||
|
text: "Terms and condition added successfully!",
|
||||||
|
icon: "success",
|
||||||
|
button: "OK",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleCancelClick = () => {
|
||||||
|
setContent(olderContent);
|
||||||
|
};
|
||||||
|
const updateContent = async () => {
|
||||||
|
const response = await axios.patch(
|
||||||
|
"/api/content/terms-and-condition-update",
|
||||||
|
{ content },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.status === 200) {
|
||||||
|
swal({
|
||||||
|
title: "Congratulations!!",
|
||||||
|
text: "Terms and condition updated successfully!",
|
||||||
|
icon: "success",
|
||||||
|
button: "OK",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
swal({
|
||||||
|
title: "Sorry, please try again",
|
||||||
|
text: "Something went wrong!",
|
||||||
|
icon: "error",
|
||||||
|
button: "Retry",
|
||||||
|
dangerMode: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleSaveClick = async () => {
|
||||||
|
if (olderContent === undefined) {
|
||||||
|
await addTermsandConditions();
|
||||||
|
setAdded(true);
|
||||||
|
} else {
|
||||||
|
await updateContent();
|
||||||
|
setAdded(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload terms and conditions
|
||||||
|
await getTermsAndConditions();
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
// addTermsandConditions();
|
||||||
|
getTermsAndConditions();
|
||||||
|
}, [added]);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleSaveClick}
|
||||||
|
style={{
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: "1rem",
|
||||||
|
textTransform: "capitalize",
|
||||||
|
marginRight: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleCancelClick}
|
||||||
|
style={{
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: "1rem",
|
||||||
|
textTransform: "capitalize",
|
||||||
|
marginRight: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Box style={{ background: "#FFFFFF", color: "black", padding: "1rem" }}>
|
||||||
|
{/* <TextField
|
||||||
|
type="text"
|
||||||
|
value={title}
|
||||||
|
onChange={(e) => setTitle(e.target.value)}
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
/> */}
|
||||||
|
<Typography
|
||||||
|
style={{ margin: "0.5rem 0rem", fontWeight: "bold" }}
|
||||||
|
variant="h6"
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
Terms and policy:{" "}
|
||||||
|
</Typography>
|
||||||
|
<Typography style={{ margin: "0.5rem 0rem" }}>Body</Typography>
|
||||||
|
<ReactQuill
|
||||||
|
theme="snow"
|
||||||
|
value={content}
|
||||||
|
onChange={handleContentChange}
|
||||||
|
modules={{ toolbar: TOOLBAR_OPTIONS }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
33
src/views/Content/reactrichTextEditor.js
Normal file
33
src/views/Content/reactrichTextEditor.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
import ReactQuill from "react-quill";
|
||||||
|
|
||||||
|
const TOOLBAR_OPTIONS = [
|
||||||
|
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||||
|
[{ font: [] }],
|
||||||
|
[{ list: "ordered" }, { list: "bullet" }],
|
||||||
|
["bold", "italic", "underline"],
|
||||||
|
[{ color: [] }, { background: [] }],
|
||||||
|
[{ align: [] }],
|
||||||
|
];
|
||||||
|
export default function ReactrichTextEditor() {
|
||||||
|
const [content, setContent] = useState("");
|
||||||
|
const handleContentChange = (content, delta, source, editor) => {
|
||||||
|
setContent(editor.getHTML());
|
||||||
|
};
|
||||||
|
// const wrapperRef = useCallback((wrapper) => {
|
||||||
|
// if (wrapper == null) return;
|
||||||
|
// wrapper.innerHTML = "";
|
||||||
|
// const editor = document.createElement("div");
|
||||||
|
// wrapper.append(editor);
|
||||||
|
// new Quill(editor, { theme: "snow", modules: { toolbar: TOOLBAR_OPTIONS } });
|
||||||
|
// }, []);
|
||||||
|
// return <div className="container" ref={wrapperRef}></div>;
|
||||||
|
return (
|
||||||
|
<ReactQuill
|
||||||
|
theme="snow"
|
||||||
|
value={content}
|
||||||
|
onChange={handleContentChange}
|
||||||
|
modules={{ toolbar: TOOLBAR_OPTIONS }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
0
src/views/Content/texteditorstyle.css
Normal file
0
src/views/Content/texteditorstyle.css
Normal file
@ -4,6 +4,16 @@ import { Link, useNavigate } from "react-router-dom";
|
|||||||
import swal from "sweetalert";
|
import swal from "sweetalert";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { isAutheticated } from "src/auth";
|
import { isAutheticated } from "src/auth";
|
||||||
|
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
||||||
|
import DeleteSharpIcon from "@mui/icons-material/DeleteSharp";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
FormControl,
|
||||||
|
IconButton,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
|
TextField,
|
||||||
|
} from "@mui/material";
|
||||||
// import { WebsiteURL } from '../WebsiteURL'
|
// import { WebsiteURL } from '../WebsiteURL'
|
||||||
|
|
||||||
const AddProduct = () => {
|
const AddProduct = () => {
|
||||||
@ -15,33 +25,50 @@ const AddProduct = () => {
|
|||||||
const [categories, setCategoies] = useState([]);
|
const [categories, setCategoies] = useState([]);
|
||||||
|
|
||||||
const [imagesPreview, setImagesPreview] = useState([]);
|
const [imagesPreview, setImagesPreview] = useState([]);
|
||||||
const [allimage, setAllImage] = useState([]);
|
// const [allimage, setAllImage] = useState([]);
|
||||||
|
const [name, setName] = useState("");
|
||||||
|
const [description, setDescription] = useState("");
|
||||||
|
const [productImages, setProductImages] = useState([]);
|
||||||
|
const [price, setPrice] = useState("");
|
||||||
|
const [categoryName, setCategoryName] = useState("");
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
const handleFileChange = (e) => {
|
||||||
const getAllTax = async () => {
|
const files = e.target.files;
|
||||||
const res = await axios.get(`/api/tax/view_tax`, {
|
|
||||||
headers: {
|
// Check the total number of selected files
|
||||||
"Access-Control-Allow-Origin": "*",
|
if (productImages.length + files.length > 4) {
|
||||||
Authorization: `Bearer ${token}`,
|
setError("You can only upload up to 4 images.");
|
||||||
},
|
return;
|
||||||
});
|
}
|
||||||
if (res.data) {
|
|
||||||
setAllTax(res.data);
|
// Check file types and append to selectedFiles
|
||||||
|
const allowedTypes = ["image/jpeg", "image/png", "image/jpg"];
|
||||||
|
const selected = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
if (productImages.length + selected.length >= 4) {
|
||||||
|
break; // Don't allow more than 4 images
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowedTypes.includes(files[i].type)) {
|
||||||
|
selected.push(files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected.length === 0) {
|
||||||
|
setError("Please upload only PNG, JPEG, or JPG files.");
|
||||||
|
} else {
|
||||||
|
setError("");
|
||||||
|
setProductImages([...productImages, ...selected]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
getAllTax();
|
|
||||||
getCategories();
|
|
||||||
}, [token]);
|
|
||||||
const [data, setData] = useState({
|
|
||||||
image: [],
|
|
||||||
imageURL: [],
|
|
||||||
name: "",
|
|
||||||
description: "",
|
|
||||||
|
|
||||||
price: "",
|
|
||||||
category: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const handelDelete = (image) => {
|
||||||
|
const filtered = productImages.filter((item) => item !== image);
|
||||||
|
setProductImages(filtered);
|
||||||
|
};
|
||||||
|
// get All categories
|
||||||
const getCategories = async () => {
|
const getCategories = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get("/api/category/getCategories", {
|
const response = await axios.get("/api/category/getCategories", {
|
||||||
@ -63,108 +90,118 @@ const AddProduct = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// Get all tax
|
||||||
const handleChange = (e) => {
|
const getAllTax = async () => {
|
||||||
if (e.target.id === "image") {
|
const res = await axios.get(`/api/tax/view_tax`, {
|
||||||
if (
|
headers: {
|
||||||
e.target.files[0]?.type === "image/jpeg" ||
|
"Access-Control-Allow-Origin": "*",
|
||||||
e.target.files[0]?.type === "image/png" ||
|
Authorization: `Bearer ${token}`,
|
||||||
e.target.files[0]?.type === "image/jpg"
|
},
|
||||||
) {
|
|
||||||
if (imagesPreview.length > 3) {
|
|
||||||
swal({
|
|
||||||
title: "Warning",
|
|
||||||
text: "maximum Four image Upload ",
|
|
||||||
icon: "error",
|
|
||||||
button: "Close",
|
|
||||||
dangerMode: true,
|
|
||||||
});
|
});
|
||||||
return;
|
if (res.data) {
|
||||||
}
|
setAllTax(res.data);
|
||||||
// only for file preview------------------------------------
|
|
||||||
const files = Array.from(e.target.files);
|
|
||||||
files.forEach((file) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onload = () => {
|
|
||||||
if (reader.readyState === 2) {
|
|
||||||
setImagesPreview((old) => [...old, reader.result]);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
getAllTax();
|
||||||
|
getCategories();
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
reader.readAsDataURL(file);
|
// const handleChange = (e) => {
|
||||||
});
|
// if (e.target.id === "image") {
|
||||||
// -----------------------------------------------------------------------------
|
// if (
|
||||||
|
// e.target.files[0]?.type === "image/jpeg" ||
|
||||||
|
// e.target.files[0]?.type === "image/png" ||
|
||||||
|
// e.target.files[0]?.type === "image/jpg"
|
||||||
|
// ) {
|
||||||
|
// if (imagesPreview.length > 3) {
|
||||||
|
// swal({
|
||||||
|
// title: "Warning",
|
||||||
|
// text: "maximum Four image Upload ",
|
||||||
|
// icon: "error",
|
||||||
|
// button: "Close",
|
||||||
|
// dangerMode: true,
|
||||||
|
// });
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// // only for file preview------------------------------------
|
||||||
|
// const files = Array.from(e.target.files);
|
||||||
|
// files.forEach((file) => {
|
||||||
|
// const reader = new FileReader();
|
||||||
|
|
||||||
setData((prev) => ({
|
// reader.onload = () => {
|
||||||
...prev,
|
// if (reader.readyState === 2) {
|
||||||
|
// setImagesPreview((old) => [...old, reader.result]);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
image: [...data.image, ...e.target.files],
|
// reader.readAsDataURL(file);
|
||||||
}));
|
// });
|
||||||
return;
|
// // -----------------------------------------------------------------------------
|
||||||
} else {
|
|
||||||
swal({
|
|
||||||
title: "Warning",
|
|
||||||
text: "Upload jpg, jpeg, png only.",
|
|
||||||
icon: "error",
|
|
||||||
button: "Close",
|
|
||||||
dangerMode: true,
|
|
||||||
});
|
|
||||||
setData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
imageURL: "",
|
|
||||||
image: "",
|
|
||||||
}));
|
|
||||||
e.target.value = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setData((prev) => ({ ...prev, [e.target.id]: e.target.value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const TaxRatechange = async (e) => {
|
// setData((prev) => ({
|
||||||
let taxDetails = {
|
// ...prev,
|
||||||
name: e.target.value.slice(12, 16),
|
|
||||||
rate: Number(e.target.value.slice(4, 6)),
|
|
||||||
|
|
||||||
taxId: e.target.value.slice(24),
|
// image: [...data.image, ...e.target.files],
|
||||||
};
|
// }));
|
||||||
|
// return;
|
||||||
|
// } else {
|
||||||
|
// swal({
|
||||||
|
// title: "Warning",
|
||||||
|
// text: "Upload jpg, jpeg, png only.",
|
||||||
|
// icon: "error",
|
||||||
|
// button: "Close",
|
||||||
|
// dangerMode: true,
|
||||||
|
// });
|
||||||
|
// setData((prev) => ({
|
||||||
|
// ...prev,
|
||||||
|
// imageURL: "",
|
||||||
|
// image: "",
|
||||||
|
// }));
|
||||||
|
// e.target.value = null;
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// setData((prev) => ({ ...prev, [e.target.id]: e.target.value }));
|
||||||
|
// };
|
||||||
|
|
||||||
let trRate = taxDetails.rate / 100;
|
// const TaxRatechange = async (e) => {
|
||||||
let PriceWithT = Number(data.price);
|
// let taxDetails = {
|
||||||
PriceWithT += +(PriceWithT * trRate).toFixed();
|
// name: e.target.value.slice(12, 16),
|
||||||
|
// rate: Number(e.target.value.slice(4, 6)),
|
||||||
|
|
||||||
//price_Level_2_With_Tax
|
// taxId: e.target.value.slice(24),
|
||||||
let price_Level_2_With_Tax = Number(data.price_Level_2);
|
// };
|
||||||
price_Level_2_With_Tax += +(price_Level_2_With_Tax * trRate).toFixed();
|
|
||||||
//
|
|
||||||
//price_Level_3_With_Tax
|
|
||||||
let price_Level_3_With_Tax = Number(data.price_Level_3);
|
|
||||||
price_Level_3_With_Tax += +(price_Level_3_With_Tax * trRate).toFixed();
|
|
||||||
setData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
price_With_Tax: PriceWithT,
|
|
||||||
|
|
||||||
price_Level_2_With_Tax: price_Level_2_With_Tax,
|
// let trRate = taxDetails.rate / 100;
|
||||||
|
// let PriceWithT = Number(data.price);
|
||||||
|
// PriceWithT += +(PriceWithT * trRate).toFixed();
|
||||||
|
|
||||||
price_Level_3_With_Tax: price_Level_3_With_Tax,
|
// //price_Level_2_With_Tax
|
||||||
taxId: taxDetails.taxId,
|
// let price_Level_2_With_Tax = Number(data.price_Level_2);
|
||||||
}));
|
// price_Level_2_With_Tax += +(price_Level_2_With_Tax * trRate).toFixed();
|
||||||
};
|
// //
|
||||||
|
// //price_Level_3_With_Tax
|
||||||
|
// let price_Level_3_With_Tax = Number(data.price_Level_3);
|
||||||
|
// price_Level_3_With_Tax += +(price_Level_3_With_Tax * trRate).toFixed();
|
||||||
|
// setData((prev) => ({
|
||||||
|
// ...prev,
|
||||||
|
// price_With_Tax: PriceWithT,
|
||||||
|
|
||||||
|
// price_Level_2_With_Tax: price_Level_2_With_Tax,
|
||||||
|
|
||||||
|
// price_Level_3_With_Tax: price_Level_3_With_Tax,
|
||||||
|
// taxId: taxDetails.taxId,
|
||||||
|
// }));
|
||||||
|
// };
|
||||||
|
|
||||||
// console.log(data.image.length)
|
// console.log(data.image.length)
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (
|
if (
|
||||||
data.name.trim() === "" ||
|
name == "" ||
|
||||||
data.description.trim() === "" ||
|
description == "" ||
|
||||||
data.price === "" ||
|
productImages.length == 0 ||
|
||||||
data.image === ""
|
price == ""
|
||||||
// data.price_With_Tax === '' ||
|
|
||||||
// data.price_Level_2 === '' ||
|
|
||||||
// data.price_Level_2_With_Tax === '' ||
|
|
||||||
// data.price_Level_3 === '' ||
|
|
||||||
// data.price_Level_3_With_Tax === '' ||
|
|
||||||
// data.imageURL.trim() === ''
|
|
||||||
) {
|
) {
|
||||||
swal({
|
swal({
|
||||||
title: "Warning",
|
title: "Warning",
|
||||||
@ -177,13 +214,13 @@ const AddProduct = () => {
|
|||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("name", data.name);
|
formData.append("name", name);
|
||||||
|
|
||||||
formData.append("description", data.description);
|
formData.append("description", description);
|
||||||
formData.append("price", data.price);
|
formData.append("price", price);
|
||||||
formData.append("category", data.category);
|
formData.append("category", categoryName);
|
||||||
|
|
||||||
data.image.forEach((Singleimage) => {
|
productImages.forEach((Singleimage) => {
|
||||||
// console.log(Singleimage)
|
// console.log(Singleimage)
|
||||||
formData.append("image", Singleimage);
|
formData.append("image", Singleimage);
|
||||||
});
|
});
|
||||||
@ -220,8 +257,8 @@ const AddProduct = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
console.log(data);
|
// console.log(data);
|
||||||
|
console.log(productImages);
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
@ -285,14 +322,14 @@ const AddProduct = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="name"
|
id="name"
|
||||||
value={data.name}
|
value={name}
|
||||||
maxLength={25}
|
maxLength={25}
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
{data.name ? (
|
{name ? (
|
||||||
<>
|
<>
|
||||||
<small className="charLeft mt-4 fst-italic">
|
<small className="charLeft mt-4 fst-italic">
|
||||||
{25 - data.name.length} characters left
|
{25 - name.length} characters left
|
||||||
</small>
|
</small>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@ -308,14 +345,14 @@ const AddProduct = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="description"
|
id="description"
|
||||||
value={data.description}
|
value={description}
|
||||||
maxLength="100"
|
maxLength="100"
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
/>
|
/>
|
||||||
{data.description ? (
|
{description ? (
|
||||||
<>
|
<>
|
||||||
<small className="charLeft mt-4 fst-italic">
|
<small className="charLeft mt-4 fst-italic">
|
||||||
{100 - data.description.length} characters left
|
{100 - description.length} characters left
|
||||||
</small>
|
</small>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@ -327,21 +364,100 @@ const AddProduct = () => {
|
|||||||
<label htmlFor="image" className="form-label">
|
<label htmlFor="image" className="form-label">
|
||||||
Product Image*
|
Product Image*
|
||||||
</label>
|
</label>
|
||||||
<input
|
<Box>
|
||||||
|
<label htmlFor="upload-Image">
|
||||||
|
<TextField
|
||||||
|
style={{
|
||||||
|
display: "none",
|
||||||
|
width: "350px",
|
||||||
|
height: "350px",
|
||||||
|
borderRadius: "10%",
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
id="upload-Image"
|
||||||
type="file"
|
type="file"
|
||||||
className="form-control"
|
accept=".jpg , .png ,.jpeg"
|
||||||
id="image"
|
label="file"
|
||||||
accept="image/*"
|
|
||||||
multiple
|
multiple
|
||||||
onChange={(e) => handleChange(e)}
|
variant="outlined"
|
||||||
|
onChange={(e) => handleFileChange(e)}
|
||||||
/>
|
/>
|
||||||
|
<Box
|
||||||
|
style={{ borderRadius: "10%" }}
|
||||||
|
sx={{
|
||||||
|
margin: "1rem 0rem",
|
||||||
|
cursor: "pointer",
|
||||||
|
width: "140px",
|
||||||
|
height: "140px",
|
||||||
|
border: "2px solid grey",
|
||||||
|
// borderRadius: '50%',
|
||||||
|
|
||||||
|
"&:hover": {
|
||||||
|
background: "rgba(112,112,112,0.5)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CloudUploadIcon
|
||||||
|
style={{
|
||||||
|
color: "grey",
|
||||||
|
margin: "auto",
|
||||||
|
fontSize: "5rem",
|
||||||
|
}}
|
||||||
|
fontSize="large"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</label>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{error && <p style={{ color: "red" }}>{error}</p>}
|
||||||
<p className="pt-1 pl-2 text-secondary">
|
<p className="pt-1 pl-2 text-secondary">
|
||||||
Upload jpg, jpeg and png only*
|
Upload jpg, jpeg and png only*
|
||||||
</p>
|
</p>
|
||||||
|
<Box style={{ display: "flex" }}>
|
||||||
|
{productImages &&
|
||||||
|
productImages.map((image, i) => (
|
||||||
|
<Box marginRight={"2rem"}>
|
||||||
|
<img
|
||||||
|
src={URL.createObjectURL(image)}
|
||||||
|
alt="profileImage"
|
||||||
|
style={{
|
||||||
|
width: 70,
|
||||||
|
height: 70,
|
||||||
|
|
||||||
|
marginBottom: "1rem",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* <IconButton
|
||||||
|
onClick={() => handelDelete(image)}
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
fontSize: "small",
|
||||||
|
"&:hover": {
|
||||||
|
background: "black",
|
||||||
|
},
|
||||||
|
background: "black",
|
||||||
|
}}
|
||||||
|
> */}
|
||||||
|
<DeleteSharpIcon
|
||||||
|
onClick={() => handelDelete(image)}
|
||||||
|
fontSize="small"
|
||||||
|
sx={{
|
||||||
|
color: "white",
|
||||||
|
position: "absolute",
|
||||||
|
cursor: "pointer",
|
||||||
|
padding: "0.2rem",
|
||||||
|
background: "black",
|
||||||
|
borderRadius: "50%",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* </IconButton> */}
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong className="fs-6 fst-italic">
|
<strong className="fs-6 fst-italic">
|
||||||
*Please Upload maximum four images
|
*You cannot upload more than 4 images !!
|
||||||
</strong>
|
</strong>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -363,23 +479,23 @@ const AddProduct = () => {
|
|||||||
<div className="card-body px-5">
|
<div className="card-body px-5">
|
||||||
<div className="mb-3 me-3">
|
<div className="mb-3 me-3">
|
||||||
<label htmlFor="title" className="form-label">
|
<label htmlFor="title" className="form-label">
|
||||||
Price (optional)
|
Price*
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="price"
|
id="price"
|
||||||
value={data.price}
|
value={price}
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => setPrice(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="categorySelect">Select a Category:</label>
|
<label htmlFor="categorySelect">Select a Category:</label>
|
||||||
<select
|
{/* <select
|
||||||
id="category"
|
id="category"
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
onChange={handleChange}
|
value={categoryName}
|
||||||
value={data.category}
|
onChange={(e) => setCategoryName(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value={""}>None</option>
|
<option value={""}>None</option>
|
||||||
{categories.map((category, index) => (
|
{categories.map((category, index) => (
|
||||||
@ -387,7 +503,44 @@ const AddProduct = () => {
|
|||||||
{category.categoryName}
|
{category.categoryName}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select> */}
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<Select
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
fullWidth
|
||||||
|
value={categoryName}
|
||||||
|
onChange={(e) => setCategoryName(e.target.value)}
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "left",
|
||||||
|
textAlign: "left",
|
||||||
|
padding: "0.5rem",
|
||||||
|
}}
|
||||||
|
value={""}
|
||||||
|
>
|
||||||
|
None
|
||||||
|
</MenuItem>
|
||||||
|
{categories.map((category, i) => (
|
||||||
|
<MenuItem
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "left",
|
||||||
|
textAlign: "left",
|
||||||
|
padding: "0.5rem",
|
||||||
|
}}
|
||||||
|
key={i}
|
||||||
|
value={category.categoryName}
|
||||||
|
>
|
||||||
|
{category.categoryName}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{allTax.length > 0 && (
|
{allTax.length > 0 && (
|
||||||
|
@ -4,6 +4,17 @@ import { Link, useNavigate, useParams } from "react-router-dom";
|
|||||||
import swal from "sweetalert";
|
import swal from "sweetalert";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { isAutheticated } from "src/auth";
|
import { isAutheticated } from "src/auth";
|
||||||
|
|
||||||
|
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
||||||
|
import DeleteSharpIcon from "@mui/icons-material/DeleteSharp";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
FormControl,
|
||||||
|
IconButton,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
|
TextField,
|
||||||
|
} from "@mui/material";
|
||||||
// import { WebsiteURL } from '../WebsiteURL'
|
// import { WebsiteURL } from '../WebsiteURL'
|
||||||
|
|
||||||
const EditProduct = () => {
|
const EditProduct = () => {
|
||||||
@ -11,20 +22,18 @@ const EditProduct = () => {
|
|||||||
|
|
||||||
const token = isAutheticated();
|
const token = isAutheticated();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [data, setData] = useState({
|
|
||||||
image: [],
|
|
||||||
imageURL: [],
|
|
||||||
name: "",
|
|
||||||
description: "",
|
|
||||||
category: "",
|
|
||||||
|
|
||||||
price: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [allTax, setAllTax] = useState([]);
|
const [allTax, setAllTax] = useState([]);
|
||||||
const [categories, setCatgories] = useState([]);
|
const [categories, setCatgories] = useState([]);
|
||||||
const [imagesPreview, setImagesPreview] = useState([]);
|
const [imagesPreview, setImagesPreview] = useState([]);
|
||||||
|
const [name, setName] = useState("");
|
||||||
|
const [description, setDescription] = useState("");
|
||||||
|
const [productImages, setProductImages] = useState([]);
|
||||||
|
const [price, setPrice] = useState("");
|
||||||
|
const [categoryName, setCategoryName] = useState("");
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const [newUpdatedImages, setNewUpdatedImages] = useState([]);
|
||||||
|
|
||||||
//get Productdata
|
//get Productdata
|
||||||
const getProduct = async () => {
|
const getProduct = async () => {
|
||||||
@ -36,23 +45,22 @@ const EditProduct = () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
// console.log(res.data?.product?.image)
|
setName(res?.data?.product.name);
|
||||||
// if (res.data?.product?.image) {
|
setDescription(res.data.product.description);
|
||||||
// res.data?.product?.image.map(item => {
|
setProductImages(res.data.product.image);
|
||||||
// })
|
setPrice(res.data.product.price);
|
||||||
|
setCategoryName(res.data.product.category);
|
||||||
// }
|
|
||||||
|
|
||||||
// setImagesPreview(res.data?.product?.image)
|
|
||||||
setData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
...res.data?.product,
|
|
||||||
imageURL: res.data?.product?.image?.url,
|
|
||||||
}));
|
|
||||||
})
|
})
|
||||||
.catch((err) => {});
|
.catch((err) => {
|
||||||
|
swal({
|
||||||
|
title: error,
|
||||||
|
text: " Can not fetch the product ",
|
||||||
|
icon: "error",
|
||||||
|
button: "Retry",
|
||||||
|
dangerMode: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
// console.log(imagesPreview)
|
|
||||||
|
|
||||||
const getCategories = async () => {
|
const getCategories = async () => {
|
||||||
try {
|
try {
|
||||||
@ -95,101 +103,12 @@ const EditProduct = () => {
|
|||||||
getAllTax();
|
getAllTax();
|
||||||
}, [token]);
|
}, [token]);
|
||||||
|
|
||||||
const handleChange = (e) => {
|
|
||||||
if (e.target.id === "image") {
|
|
||||||
if (
|
|
||||||
e.target.files[0]?.type === "image/jpeg" ||
|
|
||||||
e.target.files[0]?.type === "image/png" ||
|
|
||||||
e.target.files[0]?.type === "image/jpg"
|
|
||||||
) {
|
|
||||||
if (imagesPreview.length > 3) {
|
|
||||||
swal({
|
|
||||||
title: "Warning",
|
|
||||||
text: "maximum Four image Upload ",
|
|
||||||
icon: "error",
|
|
||||||
button: "Close",
|
|
||||||
dangerMode: true,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// only for file preview------------------------------------
|
|
||||||
const files = Array.from(e.target.files);
|
|
||||||
files.forEach((file) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onload = () => {
|
|
||||||
if (reader.readyState === 2) {
|
|
||||||
setImagesPreview((old) => [...old, reader.result]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
});
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
setData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
|
|
||||||
image: [...data.image, ...e.target.files],
|
|
||||||
}));
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
swal({
|
|
||||||
title: "Warning",
|
|
||||||
text: "Upload jpg, jpeg, png only.",
|
|
||||||
icon: "error",
|
|
||||||
button: "Close",
|
|
||||||
dangerMode: true,
|
|
||||||
});
|
|
||||||
setData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
imageURL: "",
|
|
||||||
image: "",
|
|
||||||
}));
|
|
||||||
e.target.value = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setData((prev) => ({ ...prev, [e.target.id]: e.target.value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const TaxRatechange = async (e) => {
|
|
||||||
let taxDetails = {
|
|
||||||
name: e.target.value.slice(12, 16),
|
|
||||||
rate: Number(e.target.value.slice(4, 6)),
|
|
||||||
|
|
||||||
taxId: e.target.value.slice(24),
|
|
||||||
};
|
|
||||||
|
|
||||||
let trRate = taxDetails.rate / 100;
|
|
||||||
let PriceWithT = Number(data.price);
|
|
||||||
PriceWithT += +(PriceWithT * trRate).toFixed();
|
|
||||||
|
|
||||||
//price_Level_2_With_Tax
|
|
||||||
let price_Level_2_With_Tax = Number(data.price_Level_2);
|
|
||||||
price_Level_2_With_Tax += +(price_Level_2_With_Tax * trRate).toFixed();
|
|
||||||
//
|
|
||||||
//price_Level_3_With_Tax
|
|
||||||
let price_Level_3_With_Tax = Number(data.price_Level_3);
|
|
||||||
price_Level_3_With_Tax += +(price_Level_3_With_Tax * trRate).toFixed();
|
|
||||||
setData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
price_With_Tax: PriceWithT,
|
|
||||||
|
|
||||||
price_Level_2_With_Tax: price_Level_2_With_Tax,
|
|
||||||
|
|
||||||
price_Level_3_With_Tax: price_Level_3_With_Tax,
|
|
||||||
taxId: taxDetails.taxId,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
// console.log(data.image.length)
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (
|
if (
|
||||||
data.name.trim() === "" ||
|
name == "" ||
|
||||||
data.description.trim() === "" ||
|
description == "" ||
|
||||||
data.price === "" ||
|
price == "" ||
|
||||||
data.image === ""
|
(productImages.length == 0 && newUpdatedImages.length == 0)
|
||||||
// data.price_With_Tax === '' ||
|
// data.price_With_Tax === '' ||
|
||||||
// data.price_Level_2 === '' ||
|
// data.price_Level_2 === '' ||
|
||||||
// data.price_Level_2_With_Tax === '' ||
|
// data.price_Level_2_With_Tax === '' ||
|
||||||
@ -208,21 +127,25 @@ const EditProduct = () => {
|
|||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("name", data.name);
|
formData.append("name", name);
|
||||||
|
|
||||||
formData.append("description", data.description);
|
formData.append("description", description);
|
||||||
formData.append("price", data.price);
|
formData.append("price", price);
|
||||||
formData.append("category", data.category);
|
formData.append("category", categoryName);
|
||||||
|
|
||||||
data.image.forEach((Singleimage) => {
|
newUpdatedImages.length > 0 &&
|
||||||
formData.append("image", Singleimage);
|
newUpdatedImages.forEach((Singleimage) => {
|
||||||
|
formData.append("newImages", Singleimage);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
formData.append("image", JSON.stringify(productImages));
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.put(`/api/product/update/${id}`, formData, {
|
.patch(`/api/product/update/${id}`, formData, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
"Content-Type": "multipart/formdata",
|
"Content-Type": "multipart/form-data",
|
||||||
|
|
||||||
"Access-Control-Allow-Origin": "*",
|
"Access-Control-Allow-Origin": "*",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -238,6 +161,7 @@ const EditProduct = () => {
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
const message = err.response?.data?.message
|
const message = err.response?.data?.message
|
||||||
? err.response?.data?.message
|
? err.response?.data?.message
|
||||||
: "Something went wrong!";
|
: "Something went wrong!";
|
||||||
@ -250,7 +174,63 @@ const EditProduct = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const handleFileChange = (e) => {
|
||||||
|
const files = e.target.files;
|
||||||
|
|
||||||
|
// Check the total number of selected files
|
||||||
|
if (newUpdatedImages.length + files.length > 4 - productImages.length) {
|
||||||
|
setError("You can only upload up to 4 images.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check file types and append to selectedFiles
|
||||||
|
const allowedTypes = ["image/jpeg", "image/png", "image/jpg"];
|
||||||
|
const selected = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
if (
|
||||||
|
newUpdatedImages.length + selected.length >=
|
||||||
|
4 - productImages.length
|
||||||
|
) {
|
||||||
|
break; // Don't allow more than 4 images
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowedTypes.includes(files[i].type)) {
|
||||||
|
selected.push(files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected.length === 0) {
|
||||||
|
setError("Please upload only PNG, JPEG, or JPG files.");
|
||||||
|
} else {
|
||||||
|
setError("");
|
||||||
|
setNewUpdatedImages([...newUpdatedImages, ...selected]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handelDelete = async (public_id) => {
|
||||||
|
const ary = public_id.split("/");
|
||||||
|
|
||||||
|
const res = await axios.delete(
|
||||||
|
`/api/product/deleteImage/jatinMor/product/${ary[2]}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res) {
|
||||||
|
const filtered = productImages.filter(
|
||||||
|
(item) => item.public_id !== public_id
|
||||||
|
);
|
||||||
|
setProductImages(filtered);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handellocalDelete = (image) => {
|
||||||
|
const filtered = productImages.filter((item) => item !== image);
|
||||||
|
setProductImages(filtered);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
@ -314,14 +294,14 @@ const EditProduct = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="name"
|
id="name"
|
||||||
value={data.name}
|
value={name}
|
||||||
maxLength={25}
|
maxLength={25}
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
{data.name ? (
|
{name ? (
|
||||||
<>
|
<>
|
||||||
<small className="charLeft mt-4 fst-italic">
|
<small className="charLeft mt-4 fst-italic">
|
||||||
{25 - data.name.length} characters left
|
{25 - name.length} characters left
|
||||||
</small>
|
</small>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@ -337,14 +317,14 @@ const EditProduct = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="description"
|
id="description"
|
||||||
value={data.description}
|
value={description}
|
||||||
maxLength="100"
|
maxLength="100"
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
/>
|
/>
|
||||||
{data.description ? (
|
{description ? (
|
||||||
<>
|
<>
|
||||||
<small className="charLeft mt-4 fst-italic">
|
<small className="charLeft mt-4 fst-italic">
|
||||||
{100 - data.description.length} characters left
|
{100 - description.length} characters left
|
||||||
</small>
|
</small>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@ -352,40 +332,119 @@ const EditProduct = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-3">
|
<Box>
|
||||||
<label htmlFor="image" className="form-label">
|
<label htmlFor="upload-Image">
|
||||||
Product Image*
|
<TextField
|
||||||
</label>
|
style={{
|
||||||
<input
|
display: "none",
|
||||||
|
width: "350px",
|
||||||
|
height: "350px",
|
||||||
|
borderRadius: "10%",
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
id="upload-Image"
|
||||||
type="file"
|
type="file"
|
||||||
className="form-control"
|
accept=".jpg , .png ,.jpeg"
|
||||||
id="image"
|
label="file"
|
||||||
accept="image/*"
|
|
||||||
multiple
|
multiple
|
||||||
onChange={(e) => handleChange(e)}
|
variant="outlined"
|
||||||
|
onChange={(e) => handleFileChange(e)}
|
||||||
/>
|
/>
|
||||||
<p className="pt-1 pl-2 text-secondary">
|
<Box
|
||||||
Upload jpg, jpeg and png only*
|
style={{ borderRadius: "10%" }}
|
||||||
</p>
|
sx={{
|
||||||
</div>
|
margin: "1rem 0rem",
|
||||||
|
cursor: "pointer",
|
||||||
|
width: "140px",
|
||||||
|
height: "140px",
|
||||||
|
border: "2px solid grey",
|
||||||
|
// borderRadius: '50%',
|
||||||
|
|
||||||
|
"&:hover": {
|
||||||
|
background: "rgba(112,112,112,0.5)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CloudUploadIcon
|
||||||
|
style={{
|
||||||
|
color: "grey",
|
||||||
|
margin: "auto",
|
||||||
|
fontSize: "5rem",
|
||||||
|
}}
|
||||||
|
fontSize="large"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</label>
|
||||||
|
</Box>
|
||||||
|
{error && <p style={{ color: "red" }}>{error}</p>}
|
||||||
<div>
|
<div>
|
||||||
<strong className="fs-6 fst-italic">
|
<strong className="fs-6 fst-italic">
|
||||||
*Please Upload maximum four images
|
*You cannot upload more than 4 images
|
||||||
</strong>
|
</strong>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{imagesPreview.length > 0 && (
|
<Box style={{ display: "flex" }}>
|
||||||
<div id="createProductFormImage" className="w-25 d-flex">
|
{productImages &&
|
||||||
{imagesPreview.map((image, index) => (
|
productImages.map((image, i) => (
|
||||||
|
<Box marginRight={"2rem"}>
|
||||||
<img
|
<img
|
||||||
className=" w-50 p-1 "
|
src={image.url}
|
||||||
key={index}
|
alt="profileImage"
|
||||||
src={image}
|
style={{
|
||||||
alt="Product Preview"
|
width: 70,
|
||||||
|
height: 70,
|
||||||
|
|
||||||
|
marginBottom: "1rem",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{productImages.length + newUpdatedImages.length > 1 && (
|
||||||
|
<DeleteSharpIcon
|
||||||
|
onClick={() => handelDelete(image.public_id)}
|
||||||
|
fontSize="small"
|
||||||
|
sx={{
|
||||||
|
color: "white",
|
||||||
|
position: "absolute",
|
||||||
|
cursor: "pointer",
|
||||||
|
padding: "0.2rem",
|
||||||
|
background: "black",
|
||||||
|
borderRadius: "50%",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
{/* </IconButton> */}
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
{newUpdatedImages &&
|
||||||
|
newUpdatedImages.map((image, i) => (
|
||||||
|
<Box marginRight={"2rem"}>
|
||||||
|
<img
|
||||||
|
src={URL.createObjectURL(image)}
|
||||||
|
alt="profileImage"
|
||||||
|
style={{
|
||||||
|
width: 70,
|
||||||
|
height: 70,
|
||||||
|
|
||||||
|
marginBottom: "1rem",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{productImages.length + newUpdatedImages.length > 1 && (
|
||||||
|
<DeleteSharpIcon
|
||||||
|
onClick={() => handellocalDelete(image)}
|
||||||
|
fontSize="small"
|
||||||
|
sx={{
|
||||||
|
color: "white",
|
||||||
|
position: "absolute",
|
||||||
|
cursor: "pointer",
|
||||||
|
padding: "0.2rem",
|
||||||
|
background: "black",
|
||||||
|
borderRadius: "50%",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{/* </IconButton> */}
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -400,17 +459,17 @@ const EditProduct = () => {
|
|||||||
type="number"
|
type="number"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="price"
|
id="price"
|
||||||
value={data.price}
|
value={price}
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => setPrice(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="categorySelect">Select a Category:</label>
|
<label htmlFor="categorySelect">Select a Category:</label>
|
||||||
<select
|
{/* <select
|
||||||
id="category"
|
id="category"
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
value={data.category}
|
value={categoryName}
|
||||||
onChange={handleChange}
|
onChange={(e) => setCategoryName(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value={""}>None</option>
|
<option value={""}>None</option>
|
||||||
{categories.map((category, index) => (
|
{categories.map((category, index) => (
|
||||||
@ -418,7 +477,44 @@ const EditProduct = () => {
|
|||||||
{category.categoryName}
|
{category.categoryName}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select> */}
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<Select
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
fullWidth
|
||||||
|
value={categoryName}
|
||||||
|
onChange={(e) => setCategoryName(e.target.value)}
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "left",
|
||||||
|
textAlign: "left",
|
||||||
|
padding: "0.5rem",
|
||||||
|
}}
|
||||||
|
value={""}
|
||||||
|
>
|
||||||
|
None
|
||||||
|
</MenuItem>
|
||||||
|
{categories.map((category, i) => (
|
||||||
|
<MenuItem
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "left",
|
||||||
|
textAlign: "left",
|
||||||
|
padding: "0.5rem",
|
||||||
|
}}
|
||||||
|
key={i}
|
||||||
|
value={category.categoryName}
|
||||||
|
>
|
||||||
|
{category.categoryName}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{allTax.length > 0 && (
|
{allTax.length > 0 && (
|
||||||
|
@ -1,27 +1,40 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from "react";
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from "react-router-dom";
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from "@material-ui/core/Button";
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from "react-router-dom";
|
||||||
import axios from 'axios'
|
import axios from "axios";
|
||||||
import { isAutheticated } from 'src/auth'
|
import { isAutheticated } from "src/auth";
|
||||||
|
import swal from "sweetalert";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
FormControl,
|
||||||
|
IconButton,
|
||||||
|
InputLabel,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
|
TextField,
|
||||||
|
} from "@mui/material";
|
||||||
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
|
import Fuse from "fuse.js";
|
||||||
|
import { Typography } from "@material-ui/core";
|
||||||
const Products = () => {
|
const Products = () => {
|
||||||
const token = isAutheticated()
|
const token = isAutheticated();
|
||||||
const navigate = useNavigate()
|
const [query, setQuery] = useState("");
|
||||||
const [loading, setLoading] = useState(true)
|
const navigate = useNavigate();
|
||||||
const [success, setSuccess] = useState(true)
|
const [loading, setLoading] = useState(true);
|
||||||
const [productsData, setProductsData] = useState([])
|
const [success, setSuccess] = useState(true);
|
||||||
|
const [productsData, setProductsData] = useState([]);
|
||||||
|
const [filterData, setFilterData] = useState([]);
|
||||||
|
const [queryData, setQueryData] = useState([]);
|
||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState(1)
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [itemPerPage, setItemPerPage] = useState(10)
|
const [itemPerPage, setItemPerPage] = useState(10);
|
||||||
const [showData, setShowData] = useState(productsData)
|
const [showData, setShowData] = useState(productsData);
|
||||||
|
|
||||||
const handleShowEntries = (e) => {
|
const handleShowEntries = (e) => {
|
||||||
setCurrentPage(1)
|
setCurrentPage(1);
|
||||||
setItemPerPage(e.target.value)
|
setItemPerPage(e.target.value);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const getProductsData = async () => {
|
const getProductsData = async () => {
|
||||||
axios
|
axios
|
||||||
@ -31,63 +44,119 @@ const Products = () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setProductsData(res.data?.product)
|
setProductsData(res.data?.product);
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((error) => {
|
||||||
setLoading(false)
|
swal({
|
||||||
})
|
title: error,
|
||||||
}
|
text: "please login to access the resource or refresh the page ",
|
||||||
|
icon: "error",
|
||||||
|
button: "Retry",
|
||||||
|
dangerMode: true,
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getProductsData()
|
getProductsData();
|
||||||
}, [success])
|
}, [success]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadData = () => {
|
const loadData = () => {
|
||||||
const indexOfLastPost = currentPage * itemPerPage
|
const indexOfLastPost = currentPage * itemPerPage;
|
||||||
const indexOfFirstPost = indexOfLastPost - itemPerPage
|
const indexOfFirstPost = indexOfLastPost - itemPerPage;
|
||||||
setShowData(productsData.slice(indexOfFirstPost, indexOfLastPost))
|
setShowData(productsData.slice(indexOfFirstPost, indexOfLastPost));
|
||||||
}
|
};
|
||||||
loadData()
|
loadData();
|
||||||
}, [currentPage, itemPerPage, productsData])
|
}, [currentPage, itemPerPage, productsData]);
|
||||||
|
|
||||||
const handleDelete = (id) => {
|
const handleDelete = (id) => {
|
||||||
swal({
|
swal({
|
||||||
title: 'Are you sure?',
|
title: "Are you sure?",
|
||||||
icon: 'error',
|
icon: "error",
|
||||||
buttons: { Yes: { text: 'Yes', value: true }, Cancel: { text: 'Cancel', value: 'cancel' } },
|
buttons: {
|
||||||
|
Yes: { text: "Yes", value: true },
|
||||||
|
Cancel: { text: "Cancel", value: "cancel" },
|
||||||
|
},
|
||||||
}).then((value) => {
|
}).then((value) => {
|
||||||
if (value === true) {
|
if (value === true) {
|
||||||
axios
|
axios
|
||||||
.delete(`/api/product/delete/${id}`, {
|
.delete(`/api/product/delete/${id}`, {
|
||||||
headers: {
|
headers: {
|
||||||
'Access-Control-Allow-Origin': '*',
|
"Access-Control-Allow-Origin": "*",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
swal({
|
swal({
|
||||||
title: 'Deleted',
|
title: "Deleted",
|
||||||
text: 'Product Deleted successfully!',
|
text: "Product Deleted successfully!",
|
||||||
icon: 'success',
|
icon: "success",
|
||||||
button: 'ok',
|
button: "ok",
|
||||||
})
|
});
|
||||||
setSuccess((prev) => !prev)
|
setSuccess((prev) => !prev);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
swal({
|
swal({
|
||||||
title: 'Warning',
|
title: "Warning",
|
||||||
text: 'Something went wrong!',
|
text: "Something went wrong!",
|
||||||
icon: 'error',
|
icon: "error",
|
||||||
button: 'Retry',
|
button: "Retry",
|
||||||
dangerMode: true,
|
dangerMode: true,
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const [filterCategory, setFilterCategory] = useState("");
|
||||||
|
|
||||||
|
const handleSearchClick = (query) => {
|
||||||
|
const option = {
|
||||||
|
isCaseSensitive: true,
|
||||||
|
includeScore: false,
|
||||||
|
shouldSort: true,
|
||||||
|
includeMatches: false,
|
||||||
|
findAllMatches: false,
|
||||||
|
minMatchCharLength: 1,
|
||||||
|
location: 0,
|
||||||
|
threshold: 0.6,
|
||||||
|
distance: 100,
|
||||||
|
useExtendedSearch: true,
|
||||||
|
ignoreLocation: false,
|
||||||
|
ignoreFieldNorm: false,
|
||||||
|
fieldNormWeight: 1,
|
||||||
|
keys: ["name"],
|
||||||
|
};
|
||||||
|
|
||||||
|
const fuse = new Fuse(productsData, option);
|
||||||
|
const result = fuse.search(query);
|
||||||
|
|
||||||
|
const searchedResult = result.map((result) => result.item);
|
||||||
|
|
||||||
|
setQueryData(searchedResult);
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
if (query !== "") {
|
||||||
|
setFilterCategory("");
|
||||||
|
}
|
||||||
|
setTimeout(() => handleSearchClick(query), 100);
|
||||||
|
}, [query]);
|
||||||
|
useEffect(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (filterCategory !== "") {
|
||||||
|
const filteredProducts = productsData.filter(
|
||||||
|
(product) => product.category === filterCategory
|
||||||
|
);
|
||||||
|
setFilterData(filteredProducts);
|
||||||
|
} else {
|
||||||
|
// If no category is selected, show all products
|
||||||
|
setShowData(productsData);
|
||||||
|
// setFilterData(filteredProducts);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}, [filterCategory, productsData]);
|
||||||
return (
|
return (
|
||||||
<div className="main-content">
|
<div className="main-content">
|
||||||
<div className="page-content">
|
<div className="page-content">
|
||||||
@ -102,7 +171,7 @@ const Products = () => {
|
|||||||
justify-content-between
|
justify-content-between
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div style={{ fontSize: '22px' }} className="fw-bold">
|
<div style={{ fontSize: "22px" }} className="fw-bold">
|
||||||
Products
|
Products
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -111,12 +180,12 @@ const Products = () => {
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
style={{
|
style={{
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
marginBottom: '1rem',
|
marginBottom: "1rem",
|
||||||
textTransform: 'capitalize',
|
textTransform: "capitalize",
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate('/product/add', { replace: true })
|
navigate("/product/add", { replace: true });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Add Product
|
Add Product
|
||||||
@ -130,13 +199,13 @@ const Products = () => {
|
|||||||
<div className="col-lg-12">
|
<div className="col-lg-12">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<div className="row ml-0 mr-0 mb-10">
|
<div className="row ml-0 mr-0 mb-10 ">
|
||||||
<div className="col-sm-12 col-md-12">
|
<div className="col-sm-12 col-md-12">
|
||||||
<div className="dataTables_length">
|
<div className="dataTables_length">
|
||||||
<label className="w-100">
|
<label className="w-100">
|
||||||
Show
|
Show
|
||||||
<select
|
<select
|
||||||
style={{ width: '10%' }}
|
style={{ width: "10%" }}
|
||||||
name=""
|
name=""
|
||||||
onChange={(e) => handleShowEntries(e)}
|
onChange={(e) => handleShowEntries(e)}
|
||||||
className="
|
className="
|
||||||
@ -152,6 +221,112 @@ const Products = () => {
|
|||||||
</select>
|
</select>
|
||||||
entries
|
entries
|
||||||
</label>
|
</label>
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
display: "flex",
|
||||||
|
margin: "1rem 1rem 1rem 0rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <input
|
||||||
|
value={query}
|
||||||
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
|
placeholder="Type your keywords..."
|
||||||
|
/>
|
||||||
|
<button onClick={() => handleSearchClick(query)}>
|
||||||
|
search
|
||||||
|
</button>{" "} */}
|
||||||
|
<Typography
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Search by product name :
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
style={{
|
||||||
|
background: "#ECECEC",
|
||||||
|
padding: "0.2rem 0.5rem",
|
||||||
|
borderRadius: "8px",
|
||||||
|
flex: "1",
|
||||||
|
border: " 1px solid #EEF2F6",
|
||||||
|
marginRight: "2rem",
|
||||||
|
}}
|
||||||
|
placeholder="Search here..."
|
||||||
|
variant="standard"
|
||||||
|
color="white"
|
||||||
|
value={query}
|
||||||
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
background: "blue",
|
||||||
|
color: "white",
|
||||||
|
marginTop: "0.1rem",
|
||||||
|
}}
|
||||||
|
onClick={() => handleSearchClick(query)}
|
||||||
|
>
|
||||||
|
<SearchIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
),
|
||||||
|
disableUnderline: true,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: "1",
|
||||||
|
display: "flex",
|
||||||
|
margin: "1rem 0rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Filter by Category name :
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<FormControl style={{ flex: "1" }}>
|
||||||
|
<Select
|
||||||
|
labelId="demo-simple-select-label"
|
||||||
|
id="demo-simple-select"
|
||||||
|
fullWidth
|
||||||
|
value={filterCategory}
|
||||||
|
onChange={(e) =>
|
||||||
|
setFilterCategory(e.target.value)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{showData.map((product, i) => (
|
||||||
|
<MenuItem
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "left",
|
||||||
|
textAlign: "left",
|
||||||
|
padding: "0.5rem",
|
||||||
|
}}
|
||||||
|
value={product.category}
|
||||||
|
>
|
||||||
|
{product.category}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -159,13 +334,17 @@ const Products = () => {
|
|||||||
<div className="table-responsive table-shoot mt-3">
|
<div className="table-responsive table-shoot mt-3">
|
||||||
<table
|
<table
|
||||||
className="table table-centered table-nowrap"
|
className="table table-centered table-nowrap"
|
||||||
style={{ border: '1px solid' }}
|
style={{ border: "1px solid" }}
|
||||||
|
>
|
||||||
|
<thead
|
||||||
|
className="thead-info"
|
||||||
|
style={{ background: "rgb(140, 213, 213)" }}
|
||||||
>
|
>
|
||||||
<thead className="thead-info" style={{ background: 'rgb(140, 213, 213)' }}>
|
|
||||||
<tr>
|
<tr>
|
||||||
|
|
||||||
<th className="text-start">Product Name</th>
|
|
||||||
<th className="text-start">Image</th>
|
<th className="text-start">Image</th>
|
||||||
|
<th className="text-start">Product Name</th>
|
||||||
|
<th className="text-start">Category Name</th>
|
||||||
|
|
||||||
<th className="text-start">Price</th>
|
<th className="text-start">Price</th>
|
||||||
<th className="text-start">Added On</th>
|
<th className="text-start">Added On</th>
|
||||||
<th className="text-start">Actions</th>
|
<th className="text-start">Actions</th>
|
||||||
@ -185,36 +364,50 @@ const Products = () => {
|
|||||||
Loading...
|
Loading...
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
) : (
|
) : query === "" && filterCategory == "" ? (
|
||||||
showData.map((product, i) => {
|
showData.map((product, i) => {
|
||||||
return (
|
return (
|
||||||
<tr key={i}>
|
<tr key={i}>
|
||||||
<td className="text-start">{product.name}</td>
|
|
||||||
<th>
|
<th>
|
||||||
{product.image &&
|
{product.image &&
|
||||||
product.image.map(i =>
|
product.image.map((i, j) => (
|
||||||
<img className="me-2" src={`${i?.url}`} width="40" alt="" />
|
<img
|
||||||
)}
|
key={j}
|
||||||
|
className="me-2"
|
||||||
|
src={`${i?.url}`}
|
||||||
|
width="40"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</th>
|
</th>
|
||||||
<th className="text-start">₹{product.price}</th>
|
<td className="text-start">{product.name}</td>
|
||||||
<td className="text-start">
|
<td className="text-start">
|
||||||
{new Date(product.createdAt).toLocaleString('en-IN', {
|
{product.category !== ""
|
||||||
weekday: 'short',
|
? product.category
|
||||||
month: 'short',
|
: "Category Not selected "}
|
||||||
day: 'numeric',
|
</td>
|
||||||
year: 'numeric',
|
<th className="text-start">${product.price}</th>
|
||||||
hour: 'numeric',
|
<td className="text-start">
|
||||||
minute: 'numeric',
|
{new Date(product.createdAt).toLocaleString(
|
||||||
|
"en-IN",
|
||||||
|
{
|
||||||
|
weekday: "short",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "numeric",
|
||||||
|
minute: "numeric",
|
||||||
hour12: true,
|
hour12: true,
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="text-start">
|
<td className="text-start">
|
||||||
|
|
||||||
<Link to={`/product/view/${product._id}`}>
|
<Link to={`/product/view/${product._id}`}>
|
||||||
<button
|
<button
|
||||||
style={{ color: 'white', marginRight: '1rem' }}
|
style={{
|
||||||
|
color: "white",
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
className="
|
className="
|
||||||
btn btn-primary btn-sm
|
btn btn-primary btn-sm
|
||||||
@ -229,7 +422,10 @@ const Products = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
<Link to={`/product/edit/${product._id}`}>
|
<Link to={`/product/edit/${product._id}`}>
|
||||||
<button
|
<button
|
||||||
style={{ color: 'white', marginRight: '1rem' }}
|
style={{
|
||||||
|
color: "white",
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
className="
|
className="
|
||||||
btn btn-info btn-sm
|
btn btn-info btn-sm
|
||||||
@ -243,13 +439,13 @@ const Products = () => {
|
|||||||
</button>
|
</button>
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
to={'#'}
|
to={"#"}
|
||||||
style={{
|
style={{
|
||||||
marginRight: '1rem',
|
marginRight: "1rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
style={{ color: 'white' }}
|
style={{ color: "white" }}
|
||||||
type="button"
|
type="button"
|
||||||
className="
|
className="
|
||||||
btn btn-danger btn-sm
|
btn btn-danger btn-sm
|
||||||
@ -260,7 +456,7 @@ const Products = () => {
|
|||||||
|
|
||||||
"
|
"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleDelete(product._id)
|
handleDelete(product._id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
@ -268,7 +464,210 @@ const Products = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)
|
);
|
||||||
|
})
|
||||||
|
) : query !== "" ? (
|
||||||
|
queryData.map((product, i) => {
|
||||||
|
return (
|
||||||
|
<tr key={i}>
|
||||||
|
<th>
|
||||||
|
{product.image &&
|
||||||
|
product.image.map((i, j) => (
|
||||||
|
<img
|
||||||
|
key={j}
|
||||||
|
className="me-2"
|
||||||
|
src={`${i?.url}`}
|
||||||
|
width="40"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</th>
|
||||||
|
<td className="text-start">{product.name}</td>
|
||||||
|
<td className="text-start">
|
||||||
|
{product.category !== ""
|
||||||
|
? product.category
|
||||||
|
: "Category Not selected "}
|
||||||
|
</td>
|
||||||
|
<th className="text-start">₹{product.price}</th>
|
||||||
|
<td className="text-start">
|
||||||
|
{new Date(product.createdAt).toLocaleString(
|
||||||
|
"en-IN",
|
||||||
|
{
|
||||||
|
weekday: "short",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "numeric",
|
||||||
|
minute: "numeric",
|
||||||
|
hour12: true,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="text-start">
|
||||||
|
<Link to={`/product/view/${product._id}`}>
|
||||||
|
<button
|
||||||
|
style={{
|
||||||
|
color: "white",
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className="
|
||||||
|
btn btn-primary btn-sm
|
||||||
|
waves-effect waves-light
|
||||||
|
btn-table
|
||||||
|
mx-1
|
||||||
|
mt-1
|
||||||
|
"
|
||||||
|
>
|
||||||
|
View
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
<Link to={`/product/edit/${product._id}`}>
|
||||||
|
<button
|
||||||
|
style={{
|
||||||
|
color: "white",
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className="
|
||||||
|
btn btn-info btn-sm
|
||||||
|
waves-effect waves-light
|
||||||
|
btn-table
|
||||||
|
mt-1
|
||||||
|
mx-1
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to={"#"}
|
||||||
|
style={{
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
style={{ color: "white" }}
|
||||||
|
type="button"
|
||||||
|
className="
|
||||||
|
btn btn-danger btn-sm
|
||||||
|
waves-effect waves-light
|
||||||
|
btn-table
|
||||||
|
mt-1
|
||||||
|
mx-1
|
||||||
|
|
||||||
|
"
|
||||||
|
onClick={() => {
|
||||||
|
handleDelete(product._id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
query == "" &&
|
||||||
|
filterData.map((product, i) => {
|
||||||
|
return (
|
||||||
|
<tr key={i}>
|
||||||
|
<th>
|
||||||
|
{product.image &&
|
||||||
|
product.image.map((i, j) => (
|
||||||
|
<img
|
||||||
|
key={j}
|
||||||
|
className="me-2"
|
||||||
|
src={`${i?.url}`}
|
||||||
|
width="40"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</th>
|
||||||
|
<td className="text-start">{product.name}</td>
|
||||||
|
<td className="text-start">
|
||||||
|
{product.category}
|
||||||
|
</td>
|
||||||
|
<th className="text-start">₹{product.price}</th>
|
||||||
|
<td className="text-start">
|
||||||
|
{new Date(product.createdAt).toLocaleString(
|
||||||
|
"en-IN",
|
||||||
|
{
|
||||||
|
weekday: "short",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "numeric",
|
||||||
|
minute: "numeric",
|
||||||
|
hour12: true,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="text-start">
|
||||||
|
<Link to={`/product/view/${product._id}`}>
|
||||||
|
<button
|
||||||
|
style={{
|
||||||
|
color: "white",
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className="
|
||||||
|
btn btn-primary btn-sm
|
||||||
|
waves-effect waves-light
|
||||||
|
btn-table
|
||||||
|
mx-1
|
||||||
|
mt-1
|
||||||
|
"
|
||||||
|
>
|
||||||
|
View
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
<Link to={`/product/edit/${product._id}`}>
|
||||||
|
<button
|
||||||
|
style={{
|
||||||
|
color: "white",
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className="
|
||||||
|
btn btn-info btn-sm
|
||||||
|
waves-effect waves-light
|
||||||
|
btn-table
|
||||||
|
mt-1
|
||||||
|
mx-1
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to={"#"}
|
||||||
|
style={{
|
||||||
|
marginRight: "1rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
style={{ color: "white" }}
|
||||||
|
type="button"
|
||||||
|
className="
|
||||||
|
btn btn-danger btn-sm
|
||||||
|
waves-effect waves-light
|
||||||
|
btn-table
|
||||||
|
mt-1
|
||||||
|
mx-1
|
||||||
|
|
||||||
|
"
|
||||||
|
onClick={() => {
|
||||||
|
handleDelete(product._id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -283,9 +682,12 @@ const Products = () => {
|
|||||||
role="status"
|
role="status"
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
>
|
>
|
||||||
Showing {currentPage * itemPerPage - itemPerPage + 1} to{' '}
|
Showing {currentPage * itemPerPage - itemPerPage + 1} to{" "}
|
||||||
{Math.min(currentPage * itemPerPage, productsData.length)} of{' '}
|
{Math.min(
|
||||||
{productsData.length} entries
|
currentPage * itemPerPage,
|
||||||
|
productsData.length
|
||||||
|
)}{" "}
|
||||||
|
of {productsData.length} entries
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -295,13 +697,13 @@ const Products = () => {
|
|||||||
<li
|
<li
|
||||||
className={
|
className={
|
||||||
currentPage === 1
|
currentPage === 1
|
||||||
? 'paginate_button page-item previous disabled'
|
? "paginate_button page-item previous disabled"
|
||||||
: 'paginate_button page-item previous'
|
: "paginate_button page-item previous"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="page-link"
|
className="page-link"
|
||||||
style={{ cursor: 'pointer' }}
|
style={{ cursor: "pointer" }}
|
||||||
onClick={() => setCurrentPage((prev) => prev - 1)}
|
onClick={() => setCurrentPage((prev) => prev - 1)}
|
||||||
>
|
>
|
||||||
Previous
|
Previous
|
||||||
@ -312,8 +714,10 @@ const Products = () => {
|
|||||||
<li className="paginate_button page-item">
|
<li className="paginate_button page-item">
|
||||||
<span
|
<span
|
||||||
className="page-link"
|
className="page-link"
|
||||||
style={{ cursor: 'pointer' }}
|
style={{ cursor: "pointer" }}
|
||||||
onClick={(e) => setCurrentPage((prev) => prev - 1)}
|
onClick={(e) =>
|
||||||
|
setCurrentPage((prev) => prev - 1)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{currentPage - 1}
|
{currentPage - 1}
|
||||||
</span>
|
</span>
|
||||||
@ -321,7 +725,10 @@ const Products = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<li className="paginate_button page-item active">
|
<li className="paginate_button page-item active">
|
||||||
<span className="page-link" style={{ cursor: 'pointer' }}>
|
<span
|
||||||
|
className="page-link"
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
>
|
||||||
{currentPage}
|
{currentPage}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
@ -333,9 +740,9 @@ const Products = () => {
|
|||||||
<li className="paginate_button page-item ">
|
<li className="paginate_button page-item ">
|
||||||
<span
|
<span
|
||||||
className="page-link"
|
className="page-link"
|
||||||
style={{ cursor: 'pointer' }}
|
style={{ cursor: "pointer" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentPage((prev) => prev + 1)
|
setCurrentPage((prev) => prev + 1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{currentPage + 1}
|
{currentPage + 1}
|
||||||
@ -349,13 +756,13 @@ const Products = () => {
|
|||||||
(currentPage + 1) * itemPerPage - itemPerPage >
|
(currentPage + 1) * itemPerPage - itemPerPage >
|
||||||
productsData.length - 1
|
productsData.length - 1
|
||||||
)
|
)
|
||||||
? 'paginate_button page-item next'
|
? "paginate_button page-item next"
|
||||||
: 'paginate_button page-item next disabled'
|
: "paginate_button page-item next disabled"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="page-link"
|
className="page-link"
|
||||||
style={{ cursor: 'pointer' }}
|
style={{ cursor: "pointer" }}
|
||||||
onClick={() => setCurrentPage((prev) => prev + 1)}
|
onClick={() => setCurrentPage((prev) => prev + 1)}
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
@ -372,7 +779,7 @@ const Products = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Products
|
export default Products;
|
||||||
|
@ -36,6 +36,7 @@ function ViewProduct() {
|
|||||||
return strTime;
|
return strTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// console.log(product);
|
||||||
return (
|
return (
|
||||||
<div className=" main-content">
|
<div className=" main-content">
|
||||||
<div className=" my-3 page-content">
|
<div className=" my-3 page-content">
|
||||||
@ -45,13 +46,13 @@ function ViewProduct() {
|
|||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="page-title-box d-flex align-items-center justify-content-between">
|
<div className="page-title-box d-flex align-items-center justify-content-between">
|
||||||
<h4 className="mb-3">Product</h4>
|
<h4 className="mb-3">Product</h4>
|
||||||
<Link to="/product/add">
|
<Link to="/products">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-info float-end mb-3 ml-4"
|
className="btn btn-info float-end mb-3 ml-4"
|
||||||
>
|
>
|
||||||
{" "}
|
{" "}
|
||||||
+ Add Product
|
Back
|
||||||
</button>
|
</button>
|
||||||
</Link>
|
</Link>
|
||||||
{/* <div className="page-title-right">
|
{/* <div className="page-title-right">
|
||||||
@ -78,7 +79,7 @@ function ViewProduct() {
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Id</th>{" "}
|
<th>Id</th>{" "}
|
||||||
<td>
|
<td>
|
||||||
<h5>{product?._id}</h5>
|
<h5>{product.uniqueId}</h5>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -106,7 +107,7 @@ function ViewProduct() {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Base Price</th>
|
<th>Base Price</th>
|
||||||
<td>₹{product?.price}</td>
|
<td>${product?.price}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{/* <tr><th>Product Time</th><td>{product?.time}</td></tr>
|
{/* <tr><th>Product Time</th><td>{product?.time}</td></tr>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from "react";
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
CButton,
|
CButton,
|
||||||
CCard,
|
CCard,
|
||||||
@ -12,129 +12,122 @@ import {
|
|||||||
CInputGroup,
|
CInputGroup,
|
||||||
CInputGroupText,
|
CInputGroupText,
|
||||||
CRow,
|
CRow,
|
||||||
} 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 ClipLoader from "react-spinners/ClipLoader";
|
import ClipLoader from "react-spinners/ClipLoader";
|
||||||
import { useState } from 'react'
|
import { useState } from "react";
|
||||||
import axios from 'axios'
|
import axios from "axios";
|
||||||
import { useHistory } from 'react-router-dom'
|
import { useHistory } from "react-router-dom";
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [validForm, setValidForm] = useState(false)
|
const [validForm, setValidForm] = useState(false);
|
||||||
const [auth, setAuth] = useState({
|
const [auth, setAuth] = useState({
|
||||||
email: "",
|
email: "",
|
||||||
password: ""
|
password: "",
|
||||||
});
|
});
|
||||||
const [errors, setErrors] = useState({
|
const [errors, setErrors] = useState({
|
||||||
emailError: '',
|
emailError: "",
|
||||||
passwordError: '',
|
passwordError: "",
|
||||||
|
});
|
||||||
})
|
|
||||||
const validEmailRegex = RegExp(
|
const validEmailRegex = RegExp(
|
||||||
/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i,
|
/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
|
||||||
)
|
);
|
||||||
const validPasswordRegex = RegExp(/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{7,}$/)
|
const validPasswordRegex = RegExp(
|
||||||
|
/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{7,}$/
|
||||||
|
);
|
||||||
const history = useNavigate();
|
const history = useNavigate();
|
||||||
// const handleChange = (e) => (event) => {
|
// const handleChange = (e) => (event) => {
|
||||||
|
|
||||||
// setAuth({ ...auth, [e]: event.target.value });
|
// setAuth({ ...auth, [e]: event.target.value });
|
||||||
// };
|
// };
|
||||||
const validateForm = () => {
|
const validateForm = () => {
|
||||||
let valid = true
|
let valid = true;
|
||||||
Object.values(errors).forEach((val) => {
|
Object.values(errors).forEach((val) => {
|
||||||
if (val.length > 0) {
|
if (val.length > 0) {
|
||||||
valid = false
|
valid = false;
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
Object.values(auth).forEach((val) => {
|
Object.values(auth).forEach((val) => {
|
||||||
if (val.length <= 0) {
|
if (val.length <= 0) {
|
||||||
valid = false
|
valid = false;
|
||||||
return false
|
return false;
|
||||||
}
|
|
||||||
})
|
|
||||||
return valid
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
return valid;
|
||||||
|
};
|
||||||
|
|
||||||
//cheking email and password
|
//cheking email and password
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (validateForm()) {
|
if (validateForm()) {
|
||||||
setValidForm(true)
|
setValidForm(true);
|
||||||
} else {
|
} else {
|
||||||
setValidForm(false)
|
setValidForm(false);
|
||||||
}
|
}
|
||||||
}, [errors])
|
}, [errors]);
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const { name, value } = e.target
|
const { name, value } = e.target;
|
||||||
|
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'email':
|
case "email":
|
||||||
setErrors({
|
setErrors({
|
||||||
...errors,
|
...errors,
|
||||||
emailError: validEmailRegex.test(value) ? '' : 'Email is not valid!',
|
emailError: validEmailRegex.test(value) ? "" : "Email is not valid!",
|
||||||
})
|
});
|
||||||
|
|
||||||
break
|
break;
|
||||||
case 'password':
|
case "password":
|
||||||
setErrors((errors) => ({
|
setErrors((errors) => ({
|
||||||
...errors,
|
...errors,
|
||||||
passwordError: validPasswordRegex.test(value)
|
passwordError: validPasswordRegex.test(value)
|
||||||
? ''
|
? ""
|
||||||
: 'Password Shoud Be 8 Characters Long, Atleast One Uppercase, Atleast One Lowercase,Atleast One Digit, Atleast One Special Character',
|
: "Password Shoud Be 8 Characters Long, Atleast One Uppercase, Atleast One Lowercase,Atleast One Digit, Atleast One Special Character",
|
||||||
}))
|
}));
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setAuth({ ...auth, [name]: value })
|
setAuth({ ...auth, [name]: value });
|
||||||
}
|
};
|
||||||
|
|
||||||
const Login = async () => {
|
const Login = async () => {
|
||||||
if (!(auth.email && auth.password)) {
|
if (!(auth.email && auth.password)) {
|
||||||
|
return swal("Error!", "All fields are required", "error");
|
||||||
return swal('Error!', 'All fields are required', 'error')
|
|
||||||
}
|
}
|
||||||
setLoading({ loading: true })
|
setLoading({ loading: true });
|
||||||
try {
|
try {
|
||||||
const res = await axios.post("/api/v1/user/login/", auth);
|
const res = await axios.post("/api/v1/user/login/", auth);
|
||||||
if (res.data.success == true) {
|
if (res.data.success == true) {
|
||||||
localStorage.setItem("authToken", res.data.token)
|
localStorage.setItem("authToken", res.data.token);
|
||||||
let response = await axios.get(`/api/v1/user/details`, {
|
let response = await axios.get(`/api/v1/user/details`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${res.data.token}`,
|
Authorization: `Bearer ${res.data.token}`,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
// console.log(response.data)
|
// console.log(response.data)
|
||||||
const data = response.data
|
const data = response.data;
|
||||||
if (data.user.role === 'admin') {
|
if (data.user.role === "admin") {
|
||||||
history('/dashboard')
|
history("/dashboard");
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
window.location.reload()
|
window.location.reload();
|
||||||
}
|
} else {
|
||||||
else {
|
swal("Error!", "please try with admin credential!!", "error");
|
||||||
swal('Error!', 'please try with admin credential!!', 'error')
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
swal('Error!', 'Invalid Credentials', 'error')
|
swal("Error!", "Invalid Credentials", "error");
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
swal('Error!', 'Invalid Credentials', 'error')
|
swal("Error!", "Invalid Credentials", "error");
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-light min-vh-100 d-flex flex-row align-items-center">
|
<div className="bg-light min-vh-100 d-flex flex-row align-items-center">
|
||||||
@ -145,16 +138,27 @@ const Login = () => {
|
|||||||
<CCard className="p-4">
|
<CCard className="p-4">
|
||||||
<CCardBody>
|
<CCardBody>
|
||||||
<CForm>
|
<CForm>
|
||||||
<h1>Login</h1>
|
<h1>The Solar Sign</h1>
|
||||||
<p className="text-medium-emphasis">Sign In to Your SOLAR Sign Admin Dashboard Account.</p>
|
<p className="text-medium-emphasis">
|
||||||
|
Sign In to Your SOLAR Sign Admin Dashboard Account.
|
||||||
|
</p>
|
||||||
<CInputGroup className="mb-3">
|
<CInputGroup className="mb-3">
|
||||||
<CInputGroupText>
|
<CInputGroupText>
|
||||||
<CIcon icon={cilUser} />
|
<CIcon icon={cilUser} />
|
||||||
</CInputGroupText>
|
</CInputGroupText>
|
||||||
<CFormInput type="email" placeholder="Email" onChange={handleChange} value={auth.email} name="email" autoComplete="email" />
|
<CFormInput
|
||||||
|
type="email"
|
||||||
|
placeholder="Email"
|
||||||
|
onChange={handleChange}
|
||||||
|
value={auth.email}
|
||||||
|
name="email"
|
||||||
|
autoComplete="email"
|
||||||
|
/>
|
||||||
</CInputGroup>
|
</CInputGroup>
|
||||||
{errors.emailError && (
|
{errors.emailError && (
|
||||||
<p className="text-center py-2 text-danger">{errors.emailError}</p>
|
<p className="text-center py-2 text-danger">
|
||||||
|
{errors.emailError}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
<CInputGroup className="mb-4">
|
<CInputGroup className="mb-4">
|
||||||
<CInputGroupText>
|
<CInputGroupText>
|
||||||
@ -171,15 +175,20 @@ const Login = () => {
|
|||||||
</CInputGroup>
|
</CInputGroup>
|
||||||
|
|
||||||
{errors.passwordError && (
|
{errors.passwordError && (
|
||||||
<p className="text-center py-2 text-danger">{errors.passwordError}</p>
|
<p className="text-center py-2 text-danger">
|
||||||
|
{errors.passwordError}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
<CButton color="primary" className="px-4" disabled={!validForm} onClick={Login}>
|
<CButton
|
||||||
|
color="primary"
|
||||||
|
className="px-4"
|
||||||
|
disabled={!validForm}
|
||||||
|
onClick={Login}
|
||||||
|
>
|
||||||
<ClipLoader loading={loading} size={18} />
|
<ClipLoader loading={loading} size={18} />
|
||||||
{!loading && "Login"}
|
{!loading && "Login"}
|
||||||
|
|
||||||
</CButton>
|
</CButton>
|
||||||
|
|
||||||
|
|
||||||
<Link to="/">
|
<Link to="/">
|
||||||
<CButton color="dark" className="px-4 ms-2">
|
<CButton color="dark" className="px-4 ms-2">
|
||||||
Cancel
|
Cancel
|
||||||
@ -188,12 +197,8 @@ const Login = () => {
|
|||||||
<br />
|
<br />
|
||||||
|
|
||||||
<CButton color="link" className="px-0">
|
<CButton color="link" className="px-0">
|
||||||
<Link to="/password/forgot">
|
<Link to="/password/forgot">Forgot password.?</Link>
|
||||||
Forgot password.?
|
|
||||||
</Link>
|
|
||||||
</CButton>
|
</CButton>
|
||||||
|
|
||||||
|
|
||||||
</CForm>
|
</CForm>
|
||||||
</CCardBody>
|
</CCardBody>
|
||||||
{/* <CButton color="" className="px-0">
|
{/* <CButton color="" className="px-0">
|
||||||
@ -202,18 +207,17 @@ const Login = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
</CButton> */}
|
</CButton> */}
|
||||||
</CCard>
|
</CCard>
|
||||||
|
|
||||||
</CCardGroup>
|
</CCardGroup>
|
||||||
</CCol>
|
</CCol>
|
||||||
</CRow>
|
</CRow>
|
||||||
</CContainer>
|
</CContainer>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Login
|
export default Login;
|
||||||
|
|
||||||
// < Route path = "/" name = "Home" render = {(props) => (
|
// < Route path = "/" name = "Home" render = {(props) => (
|
||||||
// userdata && userdata.role === 'admin' ? <DefaultLayout {...props} /> :
|
// userdata && userdata.role === 'admin' ? <DefaultLayout {...props} /> :
|
||||||
// <><Login {...props} /></>
|
// <><Login {...props} /></>
|
||||||
// )} />
|
// )} />
|
||||||
|
Loading…
Reference in New Issue
Block a user