product page updated

This commit is contained in:
print-signs 2023-10-17 16:52:15 +05:30
parent 06924cbaa1
commit d40bcdbff4
4 changed files with 961 additions and 841 deletions

View File

@ -34,7 +34,7 @@ const Categories = () => {
const [saveLoding, setSaveLoading] = useState(true); const [saveLoding, setSaveLoading] = useState(true);
const [edit, setEdit] = useState(false); const [edit, setEdit] = useState(false);
const [categoryName, setCategoryName] = useState(""); const [categoryName, setCategoryName] = useState("");
const [success, setSuccess] = useState(false);
const [categoryId, setCategoryId] = useState(""); const [categoryId, setCategoryId] = useState("");
const [category, setCategory] = useState([]); const [category, setCategory] = useState([]);
const [itemPerPage, setItemPerPage] = useState(10); const [itemPerPage, setItemPerPage] = useState(10);

View File

@ -1,383 +1,427 @@
import React, { useEffect, useState } from "react";
import Button from "@material-ui/core/Button";
import { Link, useNavigate } from "react-router-dom";
import React, { useEffect, useState } from 'react' import swal from "sweetalert";
import Button from '@material-ui/core/Button' import axios from "axios";
import { Link, useNavigate } from 'react-router-dom' import { isAutheticated } from "src/auth";
import swal from 'sweetalert'
import axios from 'axios'
import { isAutheticated } from 'src/auth'
// import { WebsiteURL } from '../WebsiteURL' // import { WebsiteURL } from '../WebsiteURL'
const AddProduct = () => { const AddProduct = () => {
const token = isAutheticated() const token = isAutheticated();
const navigate = useNavigate() const navigate = useNavigate();
const [data, setData] = useState({
image: [],
imageURL: [],
name: '',
description: '',
price: '', const [loading, setLoading] = useState(false);
const [allTax, setAllTax] = useState([]);
const [categories, setCategoies] = useState([]);
const [imagesPreview, setImagesPreview] = useState([]);
const [allimage, setAllImage] = useState([]);
}) useEffect(() => {
const getAllTax = async () => {
const res = await axios.get(`/api/tax/view_tax`, {
headers: {
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
if (res.data) {
setAllTax(res.data);
}
};
getAllTax();
getCategories();
}, [token]);
const [data, setData] = useState({
image: [],
imageURL: [],
name: "",
description: "",
price: "",
category: "",
});
const [loading, setLoading] = useState(false) const getCategories = async () => {
const [allTax, setAllTax] = useState([]) try {
const response = await axios.get("/api/category/getCategories", {
headers: {
Authorization: `Bearer ${token}`,
},
});
const [imagesPreview, setImagesPreview] = useState([]); if (response.status === 200) {
const [allimage, setAllImage] = useState([]); setCategoies(response?.data?.categories);
}
} catch (error) {
useEffect(() => { swal({
const getAllTax = async () => { title: error,
const res = await axios.get(`/api/tax/view_tax`, { text: " please login to access the resource ",
headers: { 'Access-Control-Allow-Origin': '*', Authorization: `Bearer ${token}` }, icon: "error",
}) button: "Retry",
if (res.data) { dangerMode: true,
setAllTax(res.data) });
}
}
getAllTax()
}, [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 handleChange = (e) => {
const TaxRatechange = async (e) => { if (e.target.id === "image") {
let taxDetails = { if (
name: e.target.value.slice(12, 16), e.target.files[0]?.type === "image/jpeg" ||
rate: Number(e.target.value.slice(4, 6)), e.target.files[0]?.type === "image/png" ||
e.target.files[0]?.type === "image/jpg"
taxId: e.target.value.slice(24) ) {
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();
let trRate = taxDetails.rate / 100 reader.onload = () => {
let PriceWithT = Number(data.price); if (reader.readyState === 2) {
PriceWithT += +((PriceWithT * trRate).toFixed()); setImagesPreview((old) => [...old, reader.result]);
}
//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 = () => {
if (
data.name.trim() === '' ||
data.description.trim() === '' ||
data.price === '' ||
data.image === ''
// 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({
title: 'Warning',
text: 'Fill all mandatory fields',
icon: 'error',
button: 'Close',
dangerMode: true,
})
return
}
setLoading(true)
const formData = new FormData()
formData.append('name', data.name)
formData.append('description', data.description)
formData.append('price', data.price)
data.image.forEach((Singleimage) => {
// console.log(Singleimage)
formData.append("image", Singleimage);
reader.readAsDataURL(file);
}); });
// -----------------------------------------------------------------------------
setData((prev) => ({
...prev,
axios image: [...data.image, ...e.target.files],
.post(`/api/product/create/`, formData, { }));
headers: { return;
Authorization: `Bearer ${token}`, } else {
'Content-Type': 'multipart/formdata', swal({
'Access-Control-Allow-Origin': '*', title: "Warning",
}, text: "Upload jpg, jpeg, png only.",
}) icon: "error",
.then((res) => { button: "Close",
swal({ dangerMode: true,
title: 'Added', });
text: 'Product added successfully!', setData((prev) => ({
icon: 'success', ...prev,
button: 'ok', imageURL: "",
}) image: "",
setLoading(false) }));
navigate('/products', { replace: true }) e.target.value = null;
}) return;
.catch((err) => { }
setLoading(false)
const message = err.response?.data?.message ? err.response?.data?.message : 'Something went wrong!'
swal({
title: 'Warning',
text: message,
icon: 'error',
button: 'Retry',
dangerMode: true,
})
})
} }
setData((prev) => ({ ...prev, [e.target.id]: e.target.value }));
};
return ( const TaxRatechange = async (e) => {
<div className="container"> let taxDetails = {
<div className="row"> name: e.target.value.slice(12, 16),
<div className="col-12"> rate: Number(e.target.value.slice(4, 6)),
<div
className=" 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 = () => {
if (
data.name.trim() === "" ||
data.description.trim() === "" ||
data.price === "" ||
data.image === ""
// 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({
title: "Warning",
text: "Fill all mandatory fields",
icon: "error",
button: "Close",
dangerMode: true,
});
return;
}
setLoading(true);
const formData = new FormData();
formData.append("name", data.name);
formData.append("description", data.description);
formData.append("price", data.price);
formData.append("category", data.category);
data.image.forEach((Singleimage) => {
// console.log(Singleimage)
formData.append("image", Singleimage);
});
axios
.post(`/api/product/create/`, formData, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "multipart/formdata",
"Access-Control-Allow-Origin": "*",
},
})
.then((res) => {
swal({
title: "Added",
text: "Product added successfully!",
icon: "success",
button: "ok",
});
setLoading(false);
navigate("/products", { replace: true });
})
.catch((err) => {
setLoading(false);
const message = err.response?.data?.message
? err.response?.data?.message
: "Something went wrong!";
swal({
title: "Warning",
text: message,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
console.log(data);
return (
<div className="container">
<div className="row">
<div className="col-12">
<div
className="
page-title-box page-title-box
d-flex d-flex
align-items-center align-items-center
justify-content-between justify-content-between
" "
> >
<div style={{ fontSize: '22px' }} className="fw-bold"> <div style={{ fontSize: "22px" }} className="fw-bold">
Add Product Add Product
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<h4 className="mb-0"></h4>
</div>
<div className="page-title-right">
<Button
variant="contained"
color="primary"
style={{
fontWeight: 'bold',
marginBottom: '1rem',
textTransform: 'capitalize',
marginRight: '5px',
}}
onClick={() => handleSubmit()}
disabled={loading}
>
{loading ? 'Loading' : 'Save'}
</Button>
<Link to="/products">
<Button
variant="contained"
color="secondary"
style={{
fontWeight: 'bold',
marginBottom: '1rem',
textTransform: 'capitalize',
}}
>
Back
</Button>
</Link>
</div>
</div>
</div>
</div> </div>
<div className="row"> <div style={{ display: "flex", gap: "1rem" }}>
<div className="col-lg-6 col-md-6 col-sm-12 my-1"> <h4 className="mb-0"></h4>
<div className="card h-100">
<div className="card-body px-5">
<div className="mb-3">
<label htmlFor="title" className="form-label">
Product Name*
</label>
<input
type="text"
className="form-control"
id="name"
value={data.name}
maxLength={25}
onChange={(e) => handleChange(e)}
/>
{data.name ? <><small className="charLeft mt-4 fst-italic">
{25 - data.name.length} characters left
</small></> : <></>
} </div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Description*
</label>
<input
type="text"
className="form-control"
id="description"
value={data.description}
maxLength="100"
onChange={(e) => handleChange(e)}
/>
{data.description ? <><small className="charLeft mt-4 fst-italic">
{100 - data.description.length} characters left
</small></> : <></>
}
</div>
<div className="mb-3">
<label htmlFor="image" className="form-label">
Product Image*
</label>
<input
type="file"
className="form-control"
id="image"
accept="image/*"
multiple
onChange={(e) => handleChange(e)}
/>
<p className="pt-1 pl-2 text-secondary">Upload jpg, jpeg and png only*</p>
</div>
<div><strong className="fs-6 fst-italic">*Please Upload maximum four images</strong></div>
<div id="createProductFormImage" className="w-25 d-flex">
{imagesPreview.map((image, index) => (
<img className=" w-50 p-1 " key={index} src={image} alt="Product Preview" />
))}
</div>
</div>
</div>
</div>
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
<div className="card h-100">
<div className="card-body px-5">
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Price (optional)
</label>
<input
type="number"
className="form-control"
id="price"
value={data.price}
onChange={(e) => handleChange(e)}
/>
</div>
{allTax.length > 0 && <div className=" mb-3">
<label htmlFor="title" className="form-label">
Tax*
</label> <select className=" form-control" name="" id=""
onChange={(e) => TaxRatechange(e)}
>
<option value="" disabled>-----</option>
{allTax.map((t, i) =>
<option key={i} value={`tax:${t.tax},name:${t.name} ,taxId:${t._id}`}>{t.tax}% {t.name}</option>
)}
</select>
</div>
}
</div>
</div>
</div>
</div> </div>
<div className="page-title-right">
<Button
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
marginRight: "5px",
}}
onClick={() => handleSubmit()}
disabled={loading}
>
{loading ? "Loading" : "Save"}
</Button>
<Link to="/products">
<Button
variant="contained"
color="secondary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
>
Back
</Button>
</Link>
</div>
</div>
</div> </div>
) </div>
} <div className="row">
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
<div className="card h-100">
<div className="card-body px-5">
<div className="mb-3">
<label htmlFor="title" className="form-label">
Product Name*
</label>
<input
type="text"
className="form-control"
id="name"
value={data.name}
maxLength={25}
onChange={(e) => handleChange(e)}
/>
{data.name ? (
<>
<small className="charLeft mt-4 fst-italic">
{25 - data.name.length} characters left
</small>
</>
) : (
<></>
)}{" "}
</div>
export default AddProduct <div className="mb-3">
<label htmlFor="title" className="form-label">
Description*
</label>
<input
type="text"
className="form-control"
id="description"
value={data.description}
maxLength="100"
onChange={(e) => handleChange(e)}
/>
{data.description ? (
<>
<small className="charLeft mt-4 fst-italic">
{100 - data.description.length} characters left
</small>
</>
) : (
<></>
)}
</div>
<div className="mb-3">
<label htmlFor="image" className="form-label">
Product Image*
</label>
<input
type="file"
className="form-control"
id="image"
accept="image/*"
multiple
onChange={(e) => handleChange(e)}
/>
<p className="pt-1 pl-2 text-secondary">
Upload jpg, jpeg and png only*
</p>
</div>
<div>
<strong className="fs-6 fst-italic">
*Please Upload maximum four images
</strong>
</div>
<div id="createProductFormImage" className="w-25 d-flex">
{imagesPreview.map((image, index) => (
<img
className=" w-50 p-1 "
key={index}
src={image}
alt="Product Preview"
/>
))}
</div>
</div>
</div>
</div>
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
<div className="card h-100">
<div className="card-body px-5">
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Price (optional)
</label>
<input
type="number"
className="form-control"
id="price"
value={data.price}
onChange={(e) => handleChange(e)}
/>
</div>
<div>
<label htmlFor="categorySelect">Select a Category:</label>
<select
id="category"
style={{ width: "100%" }}
onChange={handleChange}
value={data.category}
>
<option value={""}>None</option>
{categories.map((category, index) => (
<option key={index} value={category.categoryName}>
{category.categoryName}
</option>
))}
</select>
</div>
{allTax.length > 0 && (
<div className=" mb-3">
<label htmlFor="title" className="form-label">
Tax*
</label>{" "}
<select
className=" form-control"
name=""
id=""
onChange={(e) => TaxRatechange(e)}
>
<option value="" disabled>
-----
</option>
{allTax.map((t, i) => (
<option
key={i}
value={`tax:${t.tax},name:${t.name} ,taxId:${t._id}`}
>
{t.tax}% {t.name}
</option>
))}
</select>
</div>
)}
</div>
</div>
</div>
</div>
</div>
);
};
export default AddProduct;

View File

@ -1,414 +1,458 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useState } from 'react' import Button from "@material-ui/core/Button";
import Button from '@material-ui/core/Button' import { Link, useNavigate, useParams } from "react-router-dom";
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 { WebsiteURL } from '../WebsiteURL' // import { WebsiteURL } from '../WebsiteURL'
const EditProduct = () => { const EditProduct = () => {
const id = useParams()?.id const id = useParams()?.id;
const token = isAutheticated() const token = isAutheticated();
const navigate = useNavigate() const navigate = useNavigate();
const [data, setData] = useState({ const [data, setData] = useState({
image: [], image: [],
imageURL: [], imageURL: [],
name: '', name: "",
description: '', description: "",
category: "",
price: '', price: "",
});
const [loading, setLoading] = useState(false);
const [allTax, setAllTax] = useState([]);
const [categories, setCatgories] = useState([]);
const [imagesPreview, setImagesPreview] = useState([]);
}) //get Productdata
const getProduct = async () => {
axios
.get(`/api/product/getOne/${id}`, {
headers: {
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
// console.log(res.data?.product?.image)
// if (res.data?.product?.image) {
// res.data?.product?.image.map(item => {
// })
// }
const [loading, setLoading] = useState(false) // setImagesPreview(res.data?.product?.image)
const [allTax, setAllTax] = useState([])
const [imagesPreview, setImagesPreview] = useState([]);
//get Productdata
const getProduct = async () => {
axios
.get(`/api/product/getOne/${id}`, {
headers: {
'Access-Control-Allow-Origin': '*',
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
// console.log(res.data?.product?.image)
// if (res.data?.product?.image) {
// res.data?.product?.image.map(item => {
// })
// }
// setImagesPreview(res.data?.product?.image)
setData((prev) => ({
...prev,
...res.data?.product,
imageURL: res.data?.product?.image?.url,
}))
})
.catch((err) => { })
}
// console.log(imagesPreview)
useEffect(() => {
getProduct()
}, [])
useEffect(() => {
const getAllTax = async () => {
const res = await axios.get(`/api/tax/view_tax`, {
headers: { 'Access-Control-Allow-Origin': '*', Authorization: `Bearer ${token}` },
})
if (res.data) {
setAllTax(res.data)
}
}
getAllTax()
}, [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) => ({ setData((prev) => ({
...prev, ...prev,
price_With_Tax: PriceWithT, ...res.data?.product,
imageURL: res.data?.product?.image?.url,
}));
})
.catch((err) => {});
};
// console.log(imagesPreview)
price_Level_2_With_Tax: price_Level_2_With_Tax, const getCategories = async () => {
try {
const response = await axios.get("/api/category/getCategories", {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (response.status === 200) {
price_Level_3_With_Tax: price_Level_3_With_Tax, setCatgories(response?.data?.categories);
taxId: taxDetails.taxId }
} catch (error) {
})) swal({
title: error,
text: " please login to access the resource ",
icon: "error",
button: "Retry",
dangerMode: true,
});
} }
};
useEffect(() => {
getProduct();
getCategories();
}, []);
// console.log(data.image.length) useEffect(() => {
const handleSubmit = () => { const getAllTax = async () => {
if ( const res = await axios.get(`/api/tax/view_tax`, {
data.name.trim() === '' || headers: {
"Access-Control-Allow-Origin": "*",
Authorization: `Bearer ${token}`,
},
});
if (res.data) {
setAllTax(res.data);
}
};
getAllTax();
}, [token]);
data.description.trim() === '' || const handleChange = (e) => {
data.price === '' || if (e.target.id === "image") {
data.image === '' if (
// data.price_With_Tax === '' || e.target.files[0]?.type === "image/jpeg" ||
// data.price_Level_2 === '' || e.target.files[0]?.type === "image/png" ||
// data.price_Level_2_With_Tax === '' || e.target.files[0]?.type === "image/jpg"
// data.price_Level_3 === '' || ) {
// data.price_Level_3_With_Tax === '' || if (imagesPreview.length > 3) {
// data.imageURL.trim() === '' swal({
) { title: "Warning",
swal({ text: "maximum Four image Upload ",
title: 'Warning', icon: "error",
text: 'Fill all mandatory fields', button: "Close",
icon: 'error', dangerMode: true,
button: 'Close', });
dangerMode: true, return;
})
return
} }
setLoading(true) // only for file preview------------------------------------
const formData = new FormData() const files = Array.from(e.target.files);
formData.append('name', data.name) files.forEach((file) => {
const reader = new FileReader();
formData.append('description', data.description) reader.onload = () => {
formData.append('price', data.price) if (reader.readyState === 2) {
setImagesPreview((old) => [...old, reader.result]);
}
};
data.image.forEach((Singleimage) => {
formData.append("image", Singleimage);
reader.readAsDataURL(file);
}); });
// -----------------------------------------------------------------------------
setData((prev) => ({
...prev,
axios image: [...data.image, ...e.target.files],
.put(`/api/product/update/${id}`, formData, { }));
headers: { return;
Authorization: `Bearer ${token}`, } else {
'Content-Type': 'multipart/formdata', swal({
'Access-Control-Allow-Origin': '*', title: "Warning",
}, text: "Upload jpg, jpeg, png only.",
}) icon: "error",
.then((res) => { button: "Close",
swal({ dangerMode: true,
title: 'Updated', });
text: 'Product Updated successfully!', setData((prev) => ({
icon: 'success', ...prev,
button: 'ok', imageURL: "",
}) image: "",
setLoading(false) }));
navigate('/products', { replace: true }) e.target.value = null;
}) return;
.catch((err) => { }
setLoading(false)
const message = err.response?.data?.message ? err.response?.data?.message : 'Something went wrong!'
swal({
title: 'Warning',
text: message,
icon: 'error',
button: 'Retry',
dangerMode: true,
})
})
} }
setData((prev) => ({ ...prev, [e.target.id]: e.target.value }));
};
return ( const TaxRatechange = async (e) => {
<div className="container"> let taxDetails = {
<div className="row"> name: e.target.value.slice(12, 16),
<div className="col-12"> rate: Number(e.target.value.slice(4, 6)),
<div
className=" 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 = () => {
if (
data.name.trim() === "" ||
data.description.trim() === "" ||
data.price === "" ||
data.image === ""
// 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({
title: "Warning",
text: "Fill all mandatory fields",
icon: "error",
button: "Close",
dangerMode: true,
});
return;
}
setLoading(true);
const formData = new FormData();
formData.append("name", data.name);
formData.append("description", data.description);
formData.append("price", data.price);
formData.append("category", data.category);
data.image.forEach((Singleimage) => {
formData.append("image", Singleimage);
});
axios
.put(`/api/product/update/${id}`, formData, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "multipart/formdata",
"Access-Control-Allow-Origin": "*",
},
})
.then((res) => {
swal({
title: "Updated",
text: "Product Updated successfully!",
icon: "success",
button: "ok",
});
setLoading(false);
navigate("/products", { replace: true });
})
.catch((err) => {
setLoading(false);
const message = err.response?.data?.message
? err.response?.data?.message
: "Something went wrong!";
swal({
title: "Warning",
text: message,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
return (
<div className="container">
<div className="row">
<div className="col-12">
<div
className="
page-title-box page-title-box
d-flex d-flex
align-items-center align-items-center
justify-content-between justify-content-between
" "
> >
<div style={{ fontSize: '22px' }} className="fw-bold"> <div style={{ fontSize: "22px" }} className="fw-bold">
Edit Product Edit Product
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<h4 className="mb-0"></h4>
</div>
<div className="page-title-right">
<Button
variant="contained"
color="primary"
style={{
fontWeight: 'bold',
marginBottom: '1rem',
textTransform: 'capitalize',
marginRight: '5px',
}}
onClick={() => handleSubmit()}
disabled={loading}
>
{loading ? 'Loading' : 'Edit'}
</Button>
<Link to="/products">
<Button
variant="contained"
color="secondary"
style={{
fontWeight: 'bold',
marginBottom: '1rem',
textTransform: 'capitalize',
}}
>
Back
</Button>
</Link>
</div>
</div>
</div>
</div> </div>
<div className="row"> <div style={{ display: "flex", gap: "1rem" }}>
<div className="col-lg-6 col-md-6 col-sm-12 my-1"> <h4 className="mb-0"></h4>
<div className="card h-100">
<div className="card-body px-5">
<div className="mb-3">
<label htmlFor="title" className="form-label">
Product Name*
</label>
<input
type="text"
className="form-control"
id="name"
value={data.name}
maxLength={25}
onChange={(e) => handleChange(e)}
/>
{data.name ? <><small className="charLeft mt-4 fst-italic">
{25 - data.name.length} characters left
</small></> : <></>
} </div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Description*
</label>
<input
type="text"
className="form-control"
id="description"
value={data.description}
maxLength="100"
onChange={(e) => handleChange(e)}
/>
{data.description ? <><small className="charLeft mt-4 fst-italic">
{100 - data.description.length} characters left
</small></> : <></>
}
</div>
<div className="mb-3">
<label htmlFor="image" className="form-label">
Product Image*
</label>
<input
type="file"
className="form-control"
id="image"
accept="image/*"
multiple
onChange={(e) => handleChange(e)}
/>
<p className="pt-1 pl-2 text-secondary">Upload jpg, jpeg and png only*</p>
</div>
<div><strong className="fs-6 fst-italic">*Please Upload maximum four images</strong></div>
{imagesPreview.length > 0 && <div id="createProductFormImage" className="w-25 d-flex">
{imagesPreview.map((image, index) => (
<img className=" w-50 p-1 " key={index} src={image} alt="Product Preview" />
))}
</div>}
</div>
</div>
</div>
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
<div className="card h-100">
<div className="card-body px-5">
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Price (optional)
</label>
<input
type="number"
className="form-control"
id="price"
value={data.price}
onChange={(e) => handleChange(e)}
/>
</div>
{allTax.length > 0 && <div className=" mb-3">
<label htmlFor="title" className="form-label">
Tax*
</label> <select className=" form-control" name="" id=""
onChange={(e) => TaxRatechange(e)}
>
<option value="" disabled>-----</option>
{allTax.map((t, i) =>
<option key={i} value={`tax:${t.tax},name:${t.name} ,taxId:${t._id}`}>{t.tax}% {t.name}</option>
)}
</select>
</div>
}
</div>
</div>
</div>
</div> </div>
<div className="page-title-right">
<Button
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
marginRight: "5px",
}}
onClick={() => handleSubmit()}
disabled={loading}
>
{loading ? "Loading" : "Edit"}
</Button>
<Link to="/products">
<Button
variant="contained"
color="secondary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
>
Back
</Button>
</Link>
</div>
</div>
</div> </div>
) </div>
} <div className="row">
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
<div className="card h-100">
<div className="card-body px-5">
<div className="mb-3">
<label htmlFor="title" className="form-label">
Product Name*
</label>
<input
type="text"
className="form-control"
id="name"
value={data.name}
maxLength={25}
onChange={(e) => handleChange(e)}
/>
{data.name ? (
<>
<small className="charLeft mt-4 fst-italic">
{25 - data.name.length} characters left
</small>
</>
) : (
<></>
)}{" "}
</div>
export default EditProduct <div className="mb-3">
<label htmlFor="title" className="form-label">
Description*
</label>
<input
type="text"
className="form-control"
id="description"
value={data.description}
maxLength="100"
onChange={(e) => handleChange(e)}
/>
{data.description ? (
<>
<small className="charLeft mt-4 fst-italic">
{100 - data.description.length} characters left
</small>
</>
) : (
<></>
)}
</div>
<div className="mb-3">
<label htmlFor="image" className="form-label">
Product Image*
</label>
<input
type="file"
className="form-control"
id="image"
accept="image/*"
multiple
onChange={(e) => handleChange(e)}
/>
<p className="pt-1 pl-2 text-secondary">
Upload jpg, jpeg and png only*
</p>
</div>
<div>
<strong className="fs-6 fst-italic">
*Please Upload maximum four images
</strong>
</div>
{imagesPreview.length > 0 && (
<div id="createProductFormImage" className="w-25 d-flex">
{imagesPreview.map((image, index) => (
<img
className=" w-50 p-1 "
key={index}
src={image}
alt="Product Preview"
/>
))}
</div>
)}
</div>
</div>
</div>
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
<div className="card h-100">
<div className="card-body px-5">
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Price (optional)
</label>
<input
type="number"
className="form-control"
id="price"
value={data.price}
onChange={(e) => handleChange(e)}
/>
</div>
<div>
<label htmlFor="categorySelect">Select a Category:</label>
<select
id="category"
style={{ width: "100%" }}
value={data.category}
onChange={handleChange}
>
<option value={""}>None</option>
{categories.map((category, index) => (
<option key={index} value={category.categoryName}>
{category.categoryName}
</option>
))}
</select>
</div>
{allTax.length > 0 && (
<div className=" mb-3">
<label htmlFor="title" className="form-label">
Tax*
</label>{" "}
<select
className=" form-control"
name=""
id=""
onChange={(e) => TaxRatechange(e)}
>
<option value="" disabled>
-----
</option>
{allTax.map((t, i) => (
<option
key={i}
value={`tax:${t.tax},name:${t.name} ,taxId:${t._id}`}
>
{t.tax}% {t.name}
</option>
))}
</select>
</div>
)}
</div>
</div>
</div>
</div>
</div>
);
};
export default EditProduct;

View File

@ -1,64 +1,60 @@
import axios from "axios"; import axios from "axios";
import React, { useEffect, useState, useCallback, useMemo } from "react"; import React, { useEffect, useState, useCallback, useMemo } from "react";
import swal from 'sweetalert'; import swal from "sweetalert";
import { Link, useParams } from "react-router-dom"; import { Link, useParams } from "react-router-dom";
import { isAutheticated } from "src/auth"; import { isAutheticated } from "src/auth";
function ViewProduct() { function ViewProduct() {
const [product, setProduct] = useState([]) const [product, setProduct] = useState([]);
const { id } = useParams(); const { id } = useParams();
const token = isAutheticated(); const token = isAutheticated();
const getProduct = useCallback(async () => { const getProduct = useCallback(async () => {
let res = await axios.get( let res = await axios.get(`/api/product/getOne/${id}`, {
`/api/product/getOne/${id}`, headers: {
{ Authorization: `Bearer ${token}`,
headers: { },
Authorization: `Bearer ${token}`, });
},
}
);
console.log(res.data.product)
setProduct(res.data.product)
setProduct(res.data.product);
}, [token]);
}, [token]); useEffect(() => {
getProduct();
}, [getProduct]);
useEffect(() => { //change time formate
getProduct(); function formatAMPM(date) {
}, [getProduct]); var hours = new Date(date).getHours();
var minutes = new Date(date).getMinutes();
var ampm = hours >= 12 ? "PM" : "AM";
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
minutes = minutes < 10 ? "0" + minutes : minutes;
var strTime = hours + ":" + minutes + " " + ampm;
return strTime;
}
return (
<div className=" main-content">
<div className=" my-3 page-content">
<div className="container-fluid">
//change time formate {/* <!-- start page title --> */}
function formatAMPM(date) { <div className="row">
var hours = new Date(date).getHours(); <div className="col-12">
var minutes = new Date(date).getMinutes(); <div className="page-title-box d-flex align-items-center justify-content-between">
var ampm = hours >= 12 ? 'PM' : 'AM'; <h4 className="mb-3">Product</h4>
hours = hours % 12; <Link to="/product/add">
hours = hours ? hours : 12; // the hour '0' should be '12' <button
minutes = minutes < 10 ? '0' + minutes : minutes; type="button"
var strTime = hours + ':' + minutes + ' ' + ampm; className="btn btn-info float-end mb-3 ml-4"
return strTime; >
} {" "}
+ Add Product
</button>
return ( </Link>
<div className=" main-content"> {/* <div className="page-title-right">
<div className=" my-3 page-content">
<div className="container-fluid">
{/* <!-- start page title --> */}
<div className="row">
<div className="col-12">
<div className="page-title-box d-flex align-items-center justify-content-between">
<h4 className="mb-3">Product</h4>
<Link to="/product/add"><button type="button" className="btn btn-info float-end mb-3 ml-4"> + Add Product</button></Link>
{/* <div className="page-title-right">
<ol className="breadcrumb m-0"> <ol className="breadcrumb m-0">
<li className="breadcrumb-item"> <li className="breadcrumb-item">
<Link to="/dashboard">CMD-App</Link> <Link to="/dashboard">CMD-App</Link>
@ -66,63 +62,99 @@ function ViewProduct() {
<li className="breadcrumb-item">CMD-Category</li> <li className="breadcrumb-item">CMD-Category</li>
</ol> </ol>
</div> */} </div> */}
</div> </div>
</div>
</div>
{/* <!-- end page title --> */}
<div className="row">
<div className="col-lg-12">
<div className="card">
<div className="card-body">
<div className="row ml-0 mr-0 mb-10">
</div>
<div className="table-responsive table-shoot">
<table className="table table-centered table-nowrap mb-0">
<thead className="thead-light">
<tr><th>Id</th> <td><h5>{product?._id}</h5></td></tr>
<tr><th>Name</th> <td>{product?.name}</td></tr>
{product.image && <tr><th>image</th><td>
{product.image.map(i =>
<img className="me-2" src={`${i?.url}`} width="70" alt="" />
)}
</td></tr>}
<tr><th>Description</th><td>{product?.description}</td></tr>
<tr><th>Base Price</th><td>{product?.price}</td></tr>
{/* <tr><th>Product Time</th><td>{product?.time}</td></tr>
<tr><th>Location</th><td>{product?.location}</td></tr> */}
<tr><th>Created On</th><td>
{new Date(`${product?.createdAt}`).toDateString()}<span> , {`${formatAMPM(product?.createdAt)}`}</span>
</td></tr>
<tr><th>Updated At</th>
<td>
{new Date(`${product?.updatedAt}`).toDateString()}<span> , {`${formatAMPM(product?.updatedAt)}`}</span>
</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
{/* <!-- end table-responsive --> */}
</div>
</div>
</div>
</div>
</div>
{/* <!-- container-fluid --> */}
</div> </div>
</div>
{/* <!-- end page title --> */}
<div className="row">
<div className="col-lg-12">
<div className="card">
<div className="card-body">
<div className="row ml-0 mr-0 mb-10"></div>
<div className="table-responsive table-shoot">
<table className="table table-centered table-nowrap mb-0">
<thead className="thead-light">
<tr>
<th>Id</th>{" "}
<td>
<h5>{product?._id}</h5>
</td>
</tr>
<tr>
<th>Name</th> <td>{product?.name}</td>
</tr>
{product.image && (
<tr>
<th>image</th>
<td>
{product.image.map((i) => (
<img
className="me-2"
src={`${i?.url}`}
width="70"
alt=""
/>
))}
</td>
</tr>
)}
<tr>
<th>Description</th>
<td>{product?.description}</td>
</tr>
<tr>
<th>Base Price</th>
<td>{product?.price}</td>
</tr>
{/* <tr><th>Product Time</th><td>{product?.time}</td></tr>
<tr><th>Location</th><td>{product?.location}</td></tr> */}
<tr>
<th>Created On</th>
<td>
{new Date(`${product?.createdAt}`).toDateString()}
<span>
{" "}
, {`${formatAMPM(product?.createdAt)}`}
</span>
</td>
</tr>
<tr>
<th>Updated At</th>
<td>
{new Date(`${product?.updatedAt}`).toDateString()}
<span>
{" "}
, {`${formatAMPM(product?.updatedAt)}`}
</span>
</td>
</tr>
<tr>
<th>Category </th>
<td>
{product.category !== ""
? product.category
: "Category not selected "}
</td>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
{/* <!-- end table-responsive --> */}
</div>
</div>
</div>
</div>
</div> </div>
); {/* <!-- container-fluid --> */}
</div>
</div>
);
} }
export default ViewProduct; export default ViewProduct;