This commit is contained in:
pawan-dot 2023-11-29 16:05:27 +05:30
commit 9d6ce01262
6 changed files with 1289 additions and 540 deletions

3
.env
View File

@ -1,3 +1,4 @@
PORT = 3000 PORT = 3000
CHOKIDAR_USEPOLLING = true CHOKIDAR_USEPOLLING = true
XI_API_KEY="e327fdf320043677a512f1b0dade8403" XI_API_KEY="e327fdf320043677a512f1b0dade8403"
REACT_APP_BASE_URL=http://localhost:8000

View File

@ -11,6 +11,7 @@ import {
cilCommand, cilCommand,
cilCompress, cilCompress,
cilContact, cilContact,
cilImage,
cilLanguage, cilLanguage,
cilLoopCircular, cilLoopCircular,
cilMedicalCross, cilMedicalCross,
@ -102,6 +103,12 @@ const _nav = [
name: "Website Related", name: "Website Related",
icon: <CIcon icon={cilCart} customClassName="nav-icon" />, icon: <CIcon icon={cilCart} customClassName="nav-icon" />,
items: [ items: [
{
component: CNavItem,
name: "Banner",
icon: <CIcon icon={cilImage} customClassName="nav-icon" />,
to: "/banner",
},
{ {
component: CNavItem, component: CNavItem,
name: "Testimonials", name: "Testimonials",

View File

@ -92,6 +92,7 @@ import EditUserAddress from "./views/UserAddress/editUserAddress";
import AddUserAddress from "./views/UserAddress/addUserAddress"; import AddUserAddress from "./views/UserAddress/addUserAddress";
import ViewAddress from "./views/UserAddress/viewAddress"; import ViewAddress from "./views/UserAddress/viewAddress";
import Design from "./views/Design/design"; import Design from "./views/Design/design";
import Banners from "./views/Banner/banner";
const routes = [ const routes = [
{ path: "/", exact: true, name: "Home" }, { path: "/", exact: true, name: "Home" },
{ {
@ -247,6 +248,11 @@ const routes = [
//Complaints //Complaints
{ path: "/testimonials", name: "Testimonials", element: Testimonials }, { path: "/testimonials", name: "Testimonials", element: Testimonials },
{ path: "/testimonial/new", name: "AddTestimonial", element: AddTestimonial }, { path: "/testimonial/new", name: "AddTestimonial", element: AddTestimonial },
{
path: "/banner",
name: "Banners",
element: Banners,
},
{ {
path: "/testimonial/view/:id", path: "/testimonial/view/:id",
name: "ViewTestimonial", name: "ViewTestimonial",

704
src/views/Banner/banner.js Normal file
View File

@ -0,0 +1,704 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import { isAutheticated } from "src/auth";
import {
Button,
Box,
IconButton,
Modal,
Pagination,
TextField,
Typography,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { ClipLoader } from "react-spinners";
import swal from "sweetalert";
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
import DeleteSharpIcon from "@mui/icons-material/DeleteSharp";
const style = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
borderRadius: "0.5rem",
boxShadow: 24,
width: "500px",
};
const Banners = () => {
const token = isAutheticated();
const [loading, setLoading] = useState(true);
const [updating, setUpdating] = useState(true); // for loading state
// const [isUpdate, setIsUpdate] = useState(false); // for edit state
const [saveLoding, setSaveLoading] = useState(true);
const [edit, setEdit] = useState(false);
const [bannerName, setBannerName] = useState("");
const [bannerImage, setBannerImage] = useState("");
const [error, setError] = useState("");
const [bannerId, setBannerId] = useState("");
const [banner, setBanner] = useState([]);
const [itemPerPage, setItemPerPage] = useState(10);
const [page, setPage] = useState(1);
const [open, setOpen] = useState(false);
const [olderBannerName, setOlderBaannerName] = useState("");
const [olderImage, setOlderImage] = useState("");
const handleOpen = () => setOpen(true);
const handleClose = () => {
setOpen(false);
// setUpdating(false);
setEdit(false);
setBannerName("");
setBannerId("");
setOlderImage("");
setBannerImage("");
};
const getBanner = async () => {
try {
const response = await axios.get("/api/banner/getBanners", {
// headers: {
// Authorization: `Bearer ${token}`,
// },
});
if (response.status === 200) {
setBanner(response?.data?.banners);
setLoading(false);
}
} catch (error) {
swal({
title: error,
text: " please login to access the resource ",
icon: "error",
button: "Retry",
dangerMode: true,
});
}
};
useEffect(() => {
getBanner();
}, [token, banner]);
const handleEditClick = (_id, bannerName, bannerImage) => {
setOpen(true);
setOlderImage(bannerImage);
setBannerName(bannerName);
setBannerId(_id);
setOlderBaannerName(bannerName);
setEdit(true);
// setUpdating(false);
};
const bannerNamesArray = [];
const setBannerNamesArray = () => {
banner &&
banner.map((banner) => {
bannerNamesArray.push(banner.bannerName.toLowerCase());
});
};
setBannerNamesArray();
const handleUpdate = () => {
const filteredArrayNames = bannerNamesArray.filter(
(item) => item !== olderBannerName.toLowerCase()
);
console.log(filteredArrayNames, "filter");
const bannerExits = filteredArrayNames.includes(bannerName.toLowerCase());
if (bannerExits) {
swal({
title: "Warning",
text: "Banner already exists ",
icon: "error",
button: "Retry",
dangerMode: true,
});
return;
}
if (!bannerName || (!bannerImage && !olderImage)) {
swal({
title: "Warning",
text: "Please fill all the required fields!",
icon: "error",
button: "Retry",
dangerMode: true,
});
return;
}
setUpdating(false);
const formData = new FormData();
formData.append("bannerName", bannerName);
formData.append("bannerImage", bannerImage);
formData.append("olderImage", JSON.stringify(olderImage));
axios
.patch(`/api/banner/update/${bannerId}`, formData, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
// setUpdating(true);
// setIsUpdate(false);
handleClose();
setBannerId("");
setBannerName("");
setBannerImage("");
setOlderImage("");
setUpdating(true);
setEdit(false);
swal({
title: "Congratulations!!",
text: "The banner was updated successfully!",
icon: "success",
button: "OK",
});
// getCategories(); // Refresh the category list after updating
})
.catch((err) => {
swal({
title: "Sorry, please try again",
text: err,
icon: "error",
button: "Retry",
dangerMode: true,
});
setUpdating(true);
});
};
const handleDelete = (_id) => {
swal({
title: "Are you sure?",
icon: "error",
buttons: {
Yes: { text: "Yes", value: true },
Cancel: { text: "Cancel", value: "cancel" },
},
}).then((value) => {
if (value === true) {
axios
.delete(`/api/banner/delete/${_id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
swal({
title: "Congratulations!!",
text: "The banner was deleted successfully!",
icon: "success",
button: "OK",
});
// getCategories(); // Refresh the category list after deleting
})
.catch((err) => {
swal({
title: "",
text: "Something went wrong!",
icon: "error",
button: "Retry",
dangerMode: true,
});
});
}
});
};
const handleSaveBanner = async () => {
const bannerExits = bannerNamesArray.includes(bannerName.toLowerCase());
if (bannerExits) {
swal({
title: "Warning",
text: "Banner Already exits.",
icon: "error",
button: "Retry",
dangerMode: true,
});
return;
}
if (!bannerName || !bannerImage) {
swal({
title: "Warning",
text: "Please fill all the required fields!",
icon: "error",
button: "Retry",
dangerMode: true,
});
return;
}
setSaveLoading(false);
setLoading(true);
const formData = new FormData();
formData.append("bannerName", bannerName);
formData.append("bannerImage", bannerImage);
axios
.post("/api/banner/add", formData, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "multipart/formdata",
},
})
.then((response) => {
if (response.status === 201) {
setOpen(false);
setLoading(false);
setSaveLoading(true);
setBannerName("");
setBannerImage("");
setOlderImage("");
swal({
title: "Added",
text: "New Banner added successfully!",
icon: "success",
button: "OK",
});
// getCategories(); // Refresh the category list after adding
}
})
.catch((error) => {
setSaveLoading(true);
swal({
title: error,
text: "something went wrong",
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
const getPageCount = () => {
return Math.max(1, Math.ceil(banner.length / itemPerPage));
};
const handleFileChange = (e) => {
const files = e.target.files[0];
// Check file types and append to selectedFiles
const allowedTypes = ["image/jpeg", "image/png", "image/jpg"];
if (allowedTypes.includes(files.type)) {
setBannerImage(files);
}
};
const handeldeleteImage = () => {
setBannerImage("");
};
return (
<div className="main-content">
<div className="page-content">
<div className="container-fluid">
<div className="row">
<div className="col-12">
<div
className="
page-title-box
d-flex
align-items-center
justify-content-between
"
>
<div style={{ fontSize: "22px" }} className="fw-bold">
Banners
</div>
<div className="page-title-right">
<Button
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
onClick={handleOpen}
// onClick={() => {
// navigate("/testimonial/new", { replace: true });
// }}
>
Add New Banner
</Button>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<Box p={2} display={"flex"}>
<Typography
id="modal-modal-title"
variant="body"
component="h2"
flex={1}
>
Banner Name
</Typography>
<IconButton onClick={() => handleClose()}>
<CloseIcon />
</IconButton>
</Box>
<hr />
<TextField
placeholder="Banner name"
value={bannerName}
fullWidth
inputProps={{
maxLength: 25,
}}
style={{
padding: "1rem",
}}
onChange={(e) =>
setBannerName(
e.target.value.charAt(0).toUpperCase() +
e.target.value.slice(1)
)
}
/>
{bannerName ? (
<>
<small className="charLeft mt-2 ml-3 fst-italic">
{25 - bannerName.length} characters left
</small>
</>
) : (
<></>
)}
<Box
style={{
padding: "1rem",
}}
>
<label htmlFor="upload-Image">
<TextField
style={{
display: "none",
width: "350px",
height: "350px",
borderRadius: "10%",
}}
fullWidth
id="upload-Image"
type="file"
accept=".jpg , .png ,.jpeg"
label="file"
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>
{bannerImage && (
<Box>
<img
src={URL.createObjectURL(bannerImage)}
alt="bannerImage"
style={{
width: 100,
height: 100,
borderRadius: "1rem",
marginLeft: "1rem",
}}
/>
<DeleteSharpIcon
onClick={() => handeldeleteImage()}
fontSize="small"
sx={{
color: "white",
position: "absolute",
cursor: "pointer",
padding: "0.2rem",
background: "black",
borderRadius: "50%",
}}
/>
</Box>
)}
{olderImage && (
<Box>
<img
src={olderImage?.secure_url}
alt="bannerImage"
style={{
width: 100,
height: 100,
borderRadius: "1rem",
marginLeft: "1rem",
}}
/>
<DeleteSharpIcon
onClick={() => setOlderImage("")}
fontSize="small"
sx={{
color: "white",
position: "absolute",
cursor: "pointer",
padding: "0.2rem",
background: "black",
borderRadius: "50%",
}}
/>
</Box>
)}
</Box>
{error && <p style={{ color: "red" }}>{error}</p>}
<p className="pt-1 pl-2 text-secondary">
Upload jpg, jpeg and png only*
</p>
<Box
p={2}
display={"flex"}
justifyContent={"right"}
// width={"500px"}
>
{!edit && (
<button
style={{
color: "white",
marginRight: "1rem",
}}
onClick={() => handleSaveBanner()}
type="button"
className="
btn btn-primary btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
<ClipLoader loading={!saveLoding} size={18} />
{saveLoding && "Save"}
</button>
)}
{edit && (
<button
style={{
color: "white",
marginRight: "1rem",
}}
onClick={() => handleUpdate()}
type="button"
className="
btn btn-primary btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
<ClipLoader loading={!updating} size={18} />
{updating && "update"}
</button>
)}
<button
style={{
color: "black",
marginRight: "1rem",
background: "grey",
}}
onClick={() => setOpen(false)}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
Close
</button>
</Box>
</Box>
</Modal>
</div>
</div>
</div>
</div>
<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 className="col-sm-12 col-md-12">
<div className="dataTables_length">
<label className="w-100">
Show
<select
style={{ width: "10%" }}
onChange={(e) => setItemPerPage(e.target.value)}
className="
select-w
custom-select custom-select-sm
form-control form-control-sm
"
>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
entries
</label>
</div>
</div>
</div>
<div className="table-responsive table-shoot mt-3">
<table
className="table table-centered table-nowrap"
style={{ border: "1px solid" }}
>
<thead
className="thead-info"
style={{ background: "rgb(140, 213, 213)" }}
>
<tr>
<th> Image</th>
<th> Banner Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{!loading && banner.length === 0 && (
<tr className="text-center">
<td colSpan="6">
<h5>No Data Available</h5>
</td>
</tr>
)}
{loading ? (
<tr>
<td className="text-center" colSpan="6">
Loading...
</td>
</tr>
) : (
banner &&
banner
.slice(
(`${page}` - 1) * itemPerPage,
`${page}` * itemPerPage
)
.map((item, i) => (
<tr key={i}>
<td>
<img
className="me-2"
src={item?.bannerImage?.secure_url}
width="40"
alt=""
/>
<h5>{} </h5>
</td>
<td>
<h5>{item.bannerName} </h5>
</td>
<td className="text-start">
<button
style={{
color: "white",
marginRight: "1rem",
}}
type="button"
className="
btn btn-primary btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
onClick={() =>
handleEditClick(
item._id,
item.bannerName,
item.bannerImage
)
}
>
Edit
</button>
<button
style={{
color: "white",
marginRight: "1rem",
background: "red",
}}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
onClick={() => handleDelete(item._id)}
>
Delete
</button>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
<div style={{ display: "flex", justifyContent: "right" }}>
<Pagination
style={{ margin: "2rem" }}
variant="outlined"
size="large"
count={getPageCount()}
color="primary"
onChange={(event, value) => setPage(value)}
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default Banners;

View File

@ -1,227 +1,207 @@
import React, { useEffect, useState } from "react";
import Button from "@material-ui/core/Button";
import { Link, useNavigate } from "react-router-dom";
import swal from "sweetalert";
import axios from "axios";
import { isAutheticated } from "src/auth";
import React, { useEffect, useState } from 'react'
import Button from '@material-ui/core/Button'
import { Link, useNavigate } from 'react-router-dom'
import swal from 'sweetalert'
import axios from 'axios'
import { isAutheticated } from 'src/auth'
// import { WebsiteURL } from '../WebsiteURL' // import { WebsiteURL } from '../WebsiteURL'
const AddContactRequest = () => { const AddContactRequest = () => {
const token = isAutheticated() const token = isAutheticated();
const navigate = useNavigate() const navigate = useNavigate();
const [data, setData] = useState({ const [data, setData] = useState({
name: "",
EmailOrMobile: "",
message: "",
});
name: '', const [loading, setLoading] = useState(false);
EmailOrMobile: '',
message: '',
const handleChange = (e) => {
setData((prev) => ({ ...prev, [e.target.id]: e.target.value }));
};
const handleSubmit = () => {
}) if (
data.name.trim() === "" ||
data.EmailOrMobile.trim() === "" ||
const [loading, setLoading] = useState(false) data.message.trim() === ""
) {
swal({
title: "Warning",
text: "Fill all mandatory fields",
icon: "error",
button: "Close",
dangerMode: true,
const handleChange = (e) => { });
return;
setData((prev) => ({ ...prev, [e.target.id]: e.target.value }))
} }
setLoading(true);
const formData = new FormData();
formData.set("name", data.name);
formData.set("EmailOrMobile", data.EmailOrMobile);
formData.set("message", data.message);
axios
.post(`/api/contact/request/new/`, formData, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "multipart/formdata",
"Access-Control-Allow-Origin": "*",
},
})
.then((res) => {
swal({
title: "Added",
text: "Contact Requests added successfully!",
icon: "success",
button: "ok",
});
setLoading(false);
navigate("/contact/request", { replace: true });
})
.catch((err) => {
setLoading(false);
const message = err.response?.data?.message || "Something went wrong!";
swal({
title: "Warning",
text: message,
icon: "error",
button: "Retry",
dangerMode: true,
});
});
};
return (
const handleSubmit = () => { <div className="container">
if ( <div className="row">
data.name.trim() === '' || <div className="col-12">
data.EmailOrMobile.trim() === '' || <div
className="
data.message.trim() === ''
) {
swal({
title: 'Warning',
text: 'Fill all mandatory fields',
icon: 'error',
button: 'Close',
dangerMode: true,
})
return
}
setLoading(true)
const formData = new FormData()
formData.set('name', data.name)
formData.set('EmailOrMobile', data.EmailOrMobile)
formData.set('message', data.message)
axios
.post(`/api/contact/request/new/`, formData, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'multipart/formdata',
'Access-Control-Allow-Origin': '*',
},
})
.then((res) => {
swal({
title: 'Added',
text: 'Contact Requests added successfully!',
icon: 'success',
button: 'ok',
})
setLoading(false)
navigate('/contact/request', { replace: true })
})
.catch((err) => {
setLoading(false)
const 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">
New Contact Request New Contact Request
</div> </div>
<div style={{ display: 'flex', gap: '1rem' }}> <div style={{ display: "flex", gap: "1rem" }}>
<h4 className="mb-0"></h4> <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="/contact/request">
<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-12 col-md-12 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">
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="page-title-right">
<div className="mb-3"> <Button
<label htmlFor="title" className="form-label"> variant="contained"
Email/Mobile * color="primary"
</label> style={{
<input fontWeight: "bold",
type="text" marginBottom: "1rem",
className="form-control" textTransform: "capitalize",
id="EmailOrMobile" marginRight: "5px",
value={data.EmailOrMobile} }}
maxLength={25} onClick={() => handleSubmit()}
onChange={(e) => handleChange(e)} disabled={loading}
/> >
{data.EmailOrMobile ? <><small className="charLeft mt-4 fst-italic"> {loading ? "Loading" : "Save"}
{25 - data.EmailOrMobile.length} characters left </Button>
</small></> : <></> <Link to="/contact/request">
<Button
variant="contained"
color="secondary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
>
Back
</Button>
</Link>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-12 col-md-12 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">
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">
Email/Mobile *
</label>
<input
type="text"
className="form-control"
id="EmailOrMobile"
value={data.EmailOrMobile}
maxLength={25}
onChange={(e) => handleChange(e)}
/>
{data.EmailOrMobile ? (
<>
<small className="charLeft mt-4 fst-italic">
{25 - data.EmailOrMobile.length} characters left
</small>
</>
) : (
<></>
)}{" "}
</div>
} </div> <div className="mb-3">
<label htmlFor="title" className="form-label">
Message *
</label>
<textarea
type="text"
className="form-control"
id="message"
rows="10"
cols="100"
value={data.message}
placeholder="your message..."
maxLength="500"
onChange={(e) => handleChange(e)}
></textarea>
<div className="mb-3"> {data.message ? (
<label htmlFor="title" className="form-label"> <>
Message * <small className="charLeft mt-4 fst-italic">
</label> {500 - data.message.length} characters left
<textarea </small>
type="text" </>
className="form-control" ) : (
id="message" <></>
rows="10" )}
cols="100" </div>
value={data.message}
placeholder='your message...'
maxLength="500"
onChange={(e) => handleChange(e)}
>
</textarea>
{data.message ? <><small className="charLeft mt-4 fst-italic"> {/* <div className="mb-3">
{500 - data.message.length} characters left
</small></> : <></>
}
</div>
{/* <div className="mb-3">
<label htmlFor="title" className="form-label"> <label htmlFor="title" className="form-label">
message * message *
</label> </label>
@ -230,13 +210,12 @@ const AddContactRequest = () => {
At w3schools.com you will learn how to make a website. They offer free tutorials in all web development technologies. At w3schools.com you will learn how to make a website. They offer free tutorials in all web development technologies.
</textarea> </textarea>
</div> */} </div> */}
</div>
</div>
</div>
</div> </div>
</div>
</div> </div>
) </div>
} </div>
);
};
export default AddContactRequest export default AddContactRequest;

View File

@ -83,13 +83,13 @@ const Design = () => {
if (file && file.name.endsWith(".json")) { if (file && file.name.endsWith(".json")) {
// Validate the file type // Validate the file type
const reader = new FileReader(); // const reader = new FileReader();
reader.onload = async (event) => { // reader.onload = async (event) => {
const jsonData = event.target.result; // const jsonData = event.target.result;
// You can now send the `jsonData` to the backend for insertion // // You can now send the `jsonData` to the backend for insertion
setJsonSelectedFile(jsonData); // setJsonSelectedFile(jsonData);
}; // };
reader.readAsText(file); // reader.readAsText(file);
setJsonSelectedFile(file); setJsonSelectedFile(file);
} else { } else {
// Reset the selected file if it's not a valid JSON file // Reset the selected file if it's not a valid JSON file
@ -158,81 +158,87 @@ const Design = () => {
}; };
setDesignNamesArray(); setDesignNamesArray();
const handleUpdate = () => { // const handleUpdate = () => {
const filteredArrayNames = designNamesArray.filter( // const filteredArrayNames = designNamesArray.filter(
(item) => item !== olderDesignName.toLowerCase() // (item) => item !== olderDesignName.toLowerCase()
); // );
const designExits = filteredArrayNames.includes(designName.toLowerCase()); // const designExits = filteredArrayNames.includes(designName.toLowerCase());
if (designExits) { // if (designExits) {
swal({ // swal({
title: "Warning", // title: "Warning",
text: "Design already exists ", // text: "Design already exists ",
icon: "error", // icon: "error",
button: "Retry", // button: "Retry",
dangerMode: true, // dangerMode: true,
}); // });
return; // return;
} // }
if (!designName || (!designImage && !olderImage) || !jsonSelectedFile) { // if (!designName || (!designImage && !olderImage) || !jsonSelectedFile) {
swal({ // swal({
title: "Warning", // title: "Warning",
text: "Please fill all the required fields!", // text: "Please fill all the required fields!",
icon: "error", // icon: "error",
button: "Retry", // button: "Retry",
dangerMode: true, // dangerMode: true,
}); // });
return; // return;
} // }
setUpdating(false); // setUpdating(false);
const formData = new FormData(); // const formData = new FormData();
formData.append("designName", designName); // formData.append("designName", designName);
formData.append("categoryName", categoryName); // formData.append("categoryName", categoryName);
formData.append("designImage", designImage); // formData.append("designImage", designImage);
formData.append("olderImage", JSON.stringify(olderImage)); // formData.append("olderImage", JSON.stringify(olderImage));
formData.append("designImageJson", jsonSelectedFile); // formData.append("designImageJson", jsonSelectedFile);
axios // axios
.patch(`/api/design/update/${designId}`, formData, { // .patch(`/api/design/update/${designId}`, formData, {
headers: { // headers: {
Authorization: `Bearer ${token}`, // Authorization: `Bearer ${token}`,
}, // },
}) // })
.then((res) => { // .then((res) => {
// setUpdating(true); // // setUpdating(true);
// setIsUpdate(false); // // setIsUpdate(false);
handleClose(); // handleClose();
setDesignId(""); // setDesignId("");
setDesignName(""); // setDesignName("");
setDesignImage(""); // setDesignImage("");
setOlderImage(""); // setOlderImage("");
setCategoryName(""); // setCategoryName("");
setJsonSelectedFile(null); // setJsonSelectedFile(null);
setUpdating(true); // setUpdating(true);
setEdit(false); // setEdit(false);
swal({ // swal({
title: "Congratulations!!", // title: "Congratulations!!",
text: "The Design was updated successfully!", // text: "The Design was updated successfully!",
icon: "success", // icon: "success",
button: "OK", // button: "OK",
}); // });
// getCategories(); // Refresh the category list after updating // // getCategories(); // Refresh the category list after updating
}) // })
.catch((err) => { // .catch((err) => {
swal({ // swal({
title: "Sorry, please try again", // title: "Sorry, please try again",
text: err, // text: err,
icon: "error", // icon: "error",
button: "Retry", // button: "Retry",
dangerMode: true, // dangerMode: true,
}); // });
setUpdating(true); // setUpdating(true);
}); // });
}; // };
const handleDelete = (_id) => { const handleDelete = (
_id,
designImageFilename,
designImagePath,
designImageJsonFilename,
designImageJsonPath
) => {
swal({ swal({
title: "Are you sure?", title: "Are you sure?",
icon: "error", icon: "error",
@ -244,6 +250,12 @@ const Design = () => {
if (value === true) { if (value === true) {
axios axios
.delete(`/api/design/delete/${_id}`, { .delete(`/api/design/delete/${_id}`, {
data: {
designImageFilename,
designImagePath,
designImageJsonFilename,
designImageJsonPath,
},
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
}, },
@ -255,6 +267,7 @@ const Design = () => {
icon: "success", icon: "success",
button: "OK", button: "OK",
}); });
getDesigns();
// getCategories(); // Refresh the category list after deleting // getCategories(); // Refresh the category list after deleting
}) })
.catch((err) => { .catch((err) => {
@ -305,9 +318,11 @@ const Design = () => {
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,
"Content-Type": "multipart/formdata", "Content-Type": "multipart/formdata",
"Access-Control-Allow-Origin": "*",
}, },
}) })
.then((response) => { .then((response) => {
console.log(response);
if (response.status === 201) { if (response.status === 201) {
setOpen(false); setOpen(false);
setLoading(false); setLoading(false);
@ -323,24 +338,43 @@ const Design = () => {
icon: "success", icon: "success",
button: "OK", button: "OK",
}); });
getDesigns();
// getCategories(); // Refresh the category list after adding // getCategories(); // Refresh the category list after adding
} }
}) })
.catch((error) => { .catch((error) => {
setSaveLoading(true); setSaveLoading(true);
swal({ if (error == "Error: Network Error") {
title: error, setOpen(false);
text: "something went wrong", setLoading(false);
icon: "error", setSaveLoading(true);
button: "Retry", setDesignName("");
dangerMode: true, setDesignImage("");
}); setOlderImage("");
setJsonSelectedFile(null);
setCategoryName("");
swal({
title: "Added",
text: "New design added successfully!",
icon: "success",
button: "OK",
});
getDesigns();
} else {
swal({
title: error,
text: "something went wrong",
icon: "error",
button: "Retry",
dangerMode: true,
});
}
}); });
}; };
const getPageCount = () => { const getPageCount = () => {
return Math.max(1, Math.ceil(design.length / itemPerPage)); return Math.max(1, Math.ceil(design.length / itemPerPage));
}; };
console.log(process.env.REACT_APP_BASE_URL);
const handleFileChange = (e) => { const handleFileChange = (e) => {
const files = e.target.files[0]; const files = e.target.files[0];
@ -399,59 +433,64 @@ const Design = () => {
aria-labelledby="modal-modal-title" aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description" aria-describedby="modal-modal-description"
> >
<Box sx={style}> <form
<Box p={2} display={"flex"}> action="/api/design/add"
<Typography method="post"
id="modal-modal-title" encType="multipart/form-data"
variant="body" >
component="h2" <Box sx={style}>
flex={1} <Box p={2} display={"flex"}>
> <Typography
Design Name id="modal-modal-title"
</Typography> variant="body"
<IconButton onClick={() => handleClose()}> component="h2"
<CloseIcon /> flex={1}
</IconButton> >
</Box> Design Name
<hr /> </Typography>
<TextField <IconButton onClick={() => handleClose()}>
placeholder="Design name" <CloseIcon />
value={designName} </IconButton>
fullWidth </Box>
inputProps={{ <hr />
maxLength: 25, <TextField
}} placeholder="Design name"
style={{ value={designName}
padding: "1rem", fullWidth
}} inputProps={{
onChange={(e) => maxLength: 25,
setDesignName(
e.target.value.charAt(0).toUpperCase() +
e.target.value.slice(1)
)
}
/>
{designName ? (
<>
<small className="charLeft mt-2 ml-3 fst-italic">
{25 - designName.length} characters left
</small>
</>
) : (
<></>
)}
<div style={{ padding: "1rem" }}>
<label
htmlFor="categorySelect"
style={{
fontWeight: "bold",
display: "flex",
flexDirection: "row",
}} }}
> style={{
Select a Category*: padding: "1rem",
</label> }}
{/* <select onChange={(e) =>
setDesignName(
e.target.value.charAt(0).toUpperCase() +
e.target.value.slice(1)
)
}
/>
{designName ? (
<>
<small className="charLeft mt-2 ml-3 fst-italic">
{25 - designName.length} characters left
</small>
</>
) : (
<></>
)}
<div style={{ padding: "1rem" }}>
<label
htmlFor="categorySelect"
style={{
fontWeight: "bold",
display: "flex",
flexDirection: "row",
}}
>
Select a Category*:
</label>
{/* <select
id="category" id="category"
style={{ width: "100%" }} style={{ width: "100%" }}
value={categoryName} value={categoryName}
@ -464,71 +503,72 @@ const Design = () => {
</option> </option>
))} ))}
</select> */} </select> */}
<FormControl style={{ width: "50%" }}> <FormControl style={{ width: "50%" }}>
<Select <Select
labelId="demo-simple-select-label" labelId="demo-simple-select-label"
id="demo-simple-select" id="demo-simple-select"
fullWidth fullWidth
value={categoryName} value={categoryName}
onChange={(e) => setCategoryName(e.target.value)} onChange={(e) => setCategoryName(e.target.value)}
> >
{categories.map((category, i) => ( {categories.map((category, i) => (
<MenuItem <MenuItem
style={{
width: "100%",
display: "flex",
justifyContent: "left",
textAlign: "left",
padding: "0.5rem",
}}
key={i}
value={category.categoryName}
>
{category.categoryName}
</MenuItem>
))}
</Select>
</FormControl>
</div>
<Box
style={{
padding: "1rem",
}}
>
<iframe
src="https://solar-sign-app.netlify.app/"
width={"100%"}
height={"800px"}
/>
<Grid container spacing={5}>
<Grid item sm={6} md={6} lg={6}>
<Box>
<Typography
style={{
fontWeight: "bold",
marginTop: "1rem",
}}
>
Upload the downloaded template*
</Typography>
<label htmlFor="upload-Image">
<TextField
style={{ style={{
display: "none", width: "100%",
width: "350px", display: "flex",
height: "350px", justifyContent: "left",
borderRadius: "10%", textAlign: "left",
padding: "0.5rem",
}} }}
key={i}
value={category.categoryName}
>
{category.categoryName}
</MenuItem>
))}
</Select>
</FormControl>
</div>
<Box
style={{
padding: "1rem",
}}
>
<iframe
src="https://solar-sign-app.netlify.app/"
width={"100%"}
height={"800px"}
/>
<Grid container spacing={5}>
<Grid item sm={6} md={6} lg={6}>
<Box>
<Typography
style={{
fontWeight: "bold",
marginTop: "1rem",
}}
>
Upload the downloaded template*
</Typography>
<TextField
// style={{
// display: "none",
// width: "350px",
// height: "350px",
// borderRadius: "10%",
// }}
fullWidth fullWidth
id="upload-Image" id="upload-Image"
type="file" type="file"
name="designImage"
accept=".jpg , .png ,.jpeg" accept=".jpg , .png ,.jpeg"
label="file" label="file"
variant="outlined" variant="outlined"
onChange={(e) => handleFileChange(e)} onChange={(e) => handleFileChange(e)}
/> />
<Box {/* <Box
style={{ borderRadius: "10%" }} style={{ borderRadius: "10%" }}
sx={{ sx={{
margin: "1rem 0rem", margin: "1rem 0rem",
@ -551,158 +591,162 @@ const Design = () => {
}} }}
fontSize="large" fontSize="large"
/> />
</Box> </Box> */}
</label>
{designImage && (
<Box>
<img
src={URL.createObjectURL(designImage)}
alt="designImage"
style={{
width: 100,
height: 100,
borderRadius: "1rem",
marginLeft: "1rem",
}}
/>
<DeleteSharpIcon
onClick={() => handeldeleteImage()}
fontSize="small"
sx={{
color: "white",
position: "absolute",
cursor: "pointer",
padding: "0.2rem",
background: "black",
borderRadius: "50%",
}}
/>
</Box>
)}
{olderImage && (
<Box>
<img
src={olderImage?.secure_url}
alt="categoryImage"
style={{
width: 100,
height: 100,
borderRadius: "1rem",
marginLeft: "1rem",
}}
/>
<DeleteSharpIcon
onClick={() => handelDeleteOlderImage()}
fontSize="small"
sx={{
color: "white",
position: "absolute",
cursor: "pointer",
padding: "0.2rem",
background: "black",
borderRadius: "50%",
}}
/>
</Box>
)}
</Box>
{error && <p style={{ color: "red" }}>{error}</p>}
<p className="text-secondary">
Upload jpg, jpeg and png only*
</p>
</Grid>
<Grid item sm={6} md={6} lg={6}>
<Typography
marginTop={2}
marginBottom={2}
fontWeight={"bold"}
>
Upload the downloaded json file only*
</Typography>
<TextField
type="file"
onChange={handleJsonFileChange}
inputProps={{ accept: ".json" }}
/>
{jsonSelectedFile ? (
<p style={{ fontWeight: "bold", color: "green" }}>
File is selected
</p>
) : (
<p style={{ fontWeight: "bold", color: "red" }}>
Select the json file
</p>
)}
</Grid>
</Grid>
</Box>
<Box {designImage && (
p={2} <Box>
display={"flex"} <img
justifyContent={"right"} src={URL.createObjectURL(designImage)}
// width={"500px"} alt="designImage"
> style={{
{!edit && ( width: 100,
<button height: 100,
style={{ borderRadius: "1rem",
color: "white", marginLeft: "1rem",
marginRight: "1rem", }}
}} />
onClick={() => handleSaveCategory()} <DeleteSharpIcon
type="button" onClick={() => handeldeleteImage()}
className=" fontSize="small"
sx={{
color: "white",
position: "absolute",
cursor: "pointer",
padding: "0.2rem",
background: "black",
borderRadius: "50%",
}}
/>
</Box>
)}
{olderImage && (
<Box>
<img
src={olderImage?.secure_url}
alt="categoryImage"
style={{
width: 100,
height: 100,
borderRadius: "1rem",
marginLeft: "1rem",
}}
/>
<DeleteSharpIcon
onClick={() => handelDeleteOlderImage()}
fontSize="small"
sx={{
color: "white",
position: "absolute",
cursor: "pointer",
padding: "0.2rem",
background: "black",
borderRadius: "50%",
}}
/>
</Box>
)}
</Box>
{error && <p style={{ color: "red" }}>{error}</p>}
<p className="text-secondary">
Upload jpg, jpeg and png only*
</p>
</Grid>
<Grid item sm={6} md={6} lg={6}>
<Typography
marginTop={2}
marginBottom={2}
fontWeight={"bold"}
>
Upload the downloaded json file only*
</Typography>
<TextField
type="file"
name="designImageJson"
onChange={handleJsonFileChange}
inputProps={{ accept: ".json" }}
/>
{jsonSelectedFile ? (
<p
style={{ fontWeight: "bold", color: "green" }}
>
File is selected
</p>
) : (
<p style={{ fontWeight: "bold", color: "red" }}>
Select the json file
</p>
)}
</Grid>
</Grid>
</Box>
<Box
p={2}
display={"flex"}
justifyContent={"right"}
// width={"500px"}
>
{!edit && (
<button
style={{
color: "white",
marginRight: "1rem",
}}
onClick={() => handleSaveCategory()}
type="button"
className="
btn btn-primary btn-sm btn btn-primary btn-sm
waves-effect waves-light waves-effect waves-light
btn-table btn-table
mx-1 mx-1
mt-1 mt-1
" "
> >
<ClipLoader loading={!saveLoding} size={18} /> <ClipLoader loading={!saveLoding} size={18} />
{saveLoding && "Save"} {saveLoding && "Save"}
</button> </button>
)} )}
{edit && ( {/* {edit && (
<button <button
style={{ style={{
color: "white", color: "white",
marginRight: "1rem", marginRight: "1rem",
}} }}
onClick={() => handleUpdate()} onClick={() => handleUpdate()}
type="button" type="button"
className=" className="
btn btn-primary btn-sm btn btn-primary btn-sm
waves-effect waves-light waves-effect waves-light
btn-table btn-table
mx-1 mx-1
mt-1 mt-1
" "
> >
<ClipLoader loading={!updating} size={18} /> <ClipLoader loading={!updating} size={18} />
{updating && "update"} {updating && "update"}
</button> </button>
)} )} */}
<button <button
style={{ style={{
color: "black", color: "black",
marginRight: "1rem", marginRight: "1rem",
background: "grey", background: "grey",
}} }}
onClick={() => setOpen(false)} onClick={() => setOpen(false)}
type="button" type="button"
className=" className="
btn btn-sm btn btn-sm
waves-effect waves-light waves-effect waves-light
btn-table btn-table
mx-1 mx-1
mt-1 mt-1
" "
> >
Close Close
</button> </button>
</Box>
</Box> </Box>
</Box> </form>
</Modal> </Modal>
</div> </div>
</div> </div>
@ -782,7 +826,7 @@ const Design = () => {
<td> <td>
<img <img
className="me-2" className="me-2"
src={item?.designImage?.secure_url} src={`http://localhost:8000/uploades/${item.designImage.filename}`}
width="40" width="40"
alt="" alt=""
/> />
@ -795,7 +839,7 @@ const Design = () => {
<h5>{item.categoryName} </h5> <h5>{item.categoryName} </h5>
</td> </td>
<td className="text-start"> <td className="text-start">
<button {/* <button
style={{ style={{
color: "white", color: "white",
marginRight: "1rem", marginRight: "1rem",
@ -819,7 +863,7 @@ const Design = () => {
} }
> >
Edit Edit
</button> </button> */}
<button <button
style={{ style={{
color: "white", color: "white",
@ -834,7 +878,15 @@ const Design = () => {
mx-1 mx-1
mt-1 mt-1
" "
onClick={() => handleDelete(item._id)} onClick={() =>
handleDelete(
item._id,
item.designImage.filename,
item.designImage.path,
item.designImageJson.filename,
item.designImageJson.path
)
}
> >
Delete Delete
</button> </button>