Affiliate&Coupon Section added

This commit is contained in:
Raj-varu 2024-03-12 16:07:39 +05:30
parent 248e0f05e0
commit de3300af02
12 changed files with 3182 additions and 6 deletions

View File

@ -47,6 +47,7 @@
"bootstrap": "^5.1.3",
"country-state-city": "^3.2.1",
"md5": "^2.3.0",
"moment": "^2.30.1",
"prop-types": "^15.7.2",
"quill": "^1.3.7",
"react": "18.0.0",

View File

@ -208,6 +208,27 @@ const _nav = [
},
],
},
//Affiliate start
{
component: CNavGroup,
name: "Affiliate & Coupons",
icon: <CIcon icon={cilCart} customClassName="nav-icon" />,
items: [
{
component: CNavItem,
name: "Coupons",
icon: <CIcon icon={cilNotes} customClassName="nav-icon" />,
to: "/affiliate/coupons",
},
{
component: CNavItem,
name: "Affiliates",
icon: <CIcon icon={cilNotes} customClassName="nav-icon" />,
to: "/affiliate/affiliates",
},
],
},
//Affiliate end
];
export default _nav;

View File

@ -100,8 +100,16 @@ import Banners from "./views/Banner/banner";
import RegisterImage from "./views/Images/RegisterImage";
import LoginImage from "./views/Images/LoginImage";
import ShopImage from "./views/Images/ShopImage";
//Affiliate
import Coupons from "./views/Affiliate/Coupons";
import Affiliates from "./views/Affiliate/Affiliates";
import CreateCoupon from "./views/Affiliate/CreateCoupon";
import CreateAffiliate from "./views/Affiliate/CreateAffiliate";
import EditAffiliate from "./views/Affiliate/EditAffiliate";
import EditCoupon from "./views/Affiliate/EditCoupon";
import PayAffiliate from "./views/Affiliate/PayAffiliate";
import AffiliateHistory from "./views/Affiliate/AffiliateHistory";
import CouponHistory from "./views/Affiliate/CouponHistory";
const routes = [
{ path: "/", exact: true, name: "Home" },
@ -391,11 +399,46 @@ const routes = [
path: "/seo/request/new",
name: "seo Request",
element: AddSeoRequest,
}
},
//
//Affiliate Dashboard
{ path: "/affiliate/coupons", name: "Coupon", element: Coupons },
{ path: "/affiliate/affiliates", name: "Affiliate", element: Affiliates },
{
path: "/affiliate/coupons/create",
name: "Create Coupon",
element: CreateCoupon,
},
{
path: "/affiliate/affiliates/create",
name: "Create Affiliate",
element: CreateAffiliate,
},
{
path: "/affiliate/affiliates/edit/:id",
name: "Edit Affiliate",
element: EditAffiliate,
},
{
path: "/affiliate/affiliates/pay/:id",
name: "Pay Affiliate",
element: PayAffiliate,
},
{
path: "/affiliate/affiliates/history/:id",
name: "Pay Affiliate",
element: AffiliateHistory,
},
{
path: "/affiliate/coupons/edit/:id",
name: "Edit Coupon",
element: EditCoupon,
},
{
path: "/affiliate/coupons/history/:id",
name: "Edit Coupon",
element: CouponHistory,
},
];
export default routes;

View File

@ -0,0 +1,225 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
import { Link, useNavigate, useParams } from "react-router-dom";
import { Button, Pagination } from "@mui/material";
import { isAutheticated } from "src/auth";
const AffiliateHistory = () => {
const id = useParams().id;
const token = isAutheticated();
//Navigation
const navigate = useNavigate();
const [apiData, setApiData] = useState([]);
const [name, setName] = useState("");
const [loading, setLoading] = useState(true);
//Date format change function
const dateFormat = (inputDate) => {
const months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
const parts = inputDate.split("-");
const rearrangedDate = `${parts[2]}-${months[parseInt(parts[1]) - 1]}-${
parts[0]
}`;
// console.log(rearrangedDate); // Output: 11-Mar-2024
return rearrangedDate;
};
//Extract time from mongodb
const extractTime = (dateTimeString) => {
const date = new Date(dateTimeString);
const hours = date.getUTCHours().toString().padStart(2, "0");
const minutes = date.getUTCMinutes().toString().padStart(2, "0");
const seconds = date.getUTCSeconds().toString().padStart(2, "0");
const time = `${hours}:${minutes}:${seconds}`;
// console.log(time);
return time;
};
//Func to get all Affiliate data
const fetchHistoryData = () => {
axios
.get(`/api/v1/affiliate/history/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((response) => {
// console.log(response.data.message.affiliate_pay_history);
setApiData(response.data.message.affiliate_pay_history);
setName(response.data.message.name);
setLoading(false);
})
.catch((error) => {
setLoading(false);
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
};
//Call api onLoad of page
useEffect(() => {
fetchHistoryData();
}, []);
//pagination related
const [itemPerPage, setItemPerPage] = useState(10); //pagination
const [page, setPage] = useState(1); //pagination
const getPageCount = () => {
return Math.max(1, Math.ceil(apiData.length / itemPerPage));
};
return (
<div className="main-content">
<div className="my-3 page-content">
<div className="container-fluid">
{/* Coupon header start */}
<div className="row">
<div className="col-12">
<div
className="
page-title-box
d-flex
align-items-center
justify-content-between
"
>
<div
style={{ fontSize: "22px", fontWeight: "bold" }}
className="fw-bold"
>
<p>Payment History :{name}</p>
</div>
<div className="page-title-right">
<Link to="/affiliate/affiliates">
<Button
variant="contained"
color="secondary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
marginRight: "1rem",
}}
>
Back
</Button>
</Link>
</div>
</div>
</div>
</div>
{/* Coupon header End */}
{/* Coupon main body Start*/}
<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>
</div>
</div>
</div>
{/* Table Start */}
<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>Transection ID</th>
<th>Amount</th>
<th>Date</th>
<th>Time</th>
</tr>
</thead>
<tbody>
{!loading && apiData.length === 0 && (
<tr className="text-center">
<td>
<h5>No Data Available</h5>
</td>
</tr>
)}
{loading ? (
<tr>
<td className="text-center">Loading...</td>
</tr>
) : (
apiData &&
apiData
.slice(
(`${page}` - 1) * itemPerPage,
`${page}` * itemPerPage
)
.map((item, i) => (
<tr key={i}>
<td>{item.transecId}</td>
<td>{item.amount}</td>
<td>{dateFormat(item.date)}</td>
<td>{item.time}</td>
</tr>
))
)}
</tbody>
</table>
</div>
{/* Table End */}
{/* Pagination div Start*/}
<div style={{ display: "flex", justifyContent: "right" }}>
<Pagination
style={{ margin: "2rem" }}
variant="outlined"
size="large"
count={getPageCount()}
color="primary"
onChange={(event, value) => setPage(value)}
/>
</div>
{/* Pagination div End*/}
{/* Coupon main body End */}
</div>
</div>
</div>
);
};
export default AffiliateHistory;

View File

@ -0,0 +1,391 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
import { Link, useNavigate } from "react-router-dom";
import { Button, Pagination } from "@mui/material";
import { isAutheticated } from "src/auth";
const Affiliates = () => {
const token = isAutheticated();
//Navigation
const navigate = useNavigate();
const [apiData, setApiData] = useState([]);
const [loading, setLoading] = useState(true);
const handelSuspend = (id, active) => {
axios
.patch(
"api/v1/affiliate/suspend",
{
id: id,
is_affiliate_active: !active,
},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
)
.then((res) => {
// Fetch data again after updating kind of updating page
fetchAffiliateData();
})
.catch((error) => {
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
};
//Func to get all Affiliate data
const fetchAffiliateData = () => {
axios
.get("/api/v1/affiliate/getall", {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((response) => {
// console.log(response.data.message);
setLoading(false);
setApiData(response.data.message);
})
.catch((error) => {
setLoading(false);
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
};
//Call api onLoad of page
useEffect(() => {
fetchAffiliateData();
}, []);
//pagination related
const [itemPerPage, setItemPerPage] = useState(10); //pagination
const [page, setPage] = useState(1); //pagination
//Create navigation
const navigCreate = () => {
navigate("/affiliate/affiliates/create");
};
const style = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
borderRadius: "0.5rem",
boxShadow: 24,
width: "500px",
padding: "1rem",
};
const InputSpace = {
marginBottom: "1rem",
};
const getPageCount = () => {
return Math.max(1, Math.ceil(apiData.length / itemPerPage));
};
return (
<div className="main-content">
<div className="my-3 page-content">
<div className="container-fluid">
{/* Coupon header start */}
<div className="row">
<div className="col-12">
<div
className="
page-title-box
d-flex
align-items-center
justify-content-between
"
>
<div
style={{ fontSize: "22px", fontWeight: "bold" }}
className="fw-bold"
>
Affiliates
</div>
<div className="page-title-right">
<Button
onClick={navigCreate}
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
>
Add New Affiliate
</Button>
</div>
</div>
</div>
</div>
{/* Coupon header End */}
{/* Coupon main body Start*/}
<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>
</div>
</div>
</div>
{/* Table Start */}
<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> Affiliate</th>
<th> Coupon Code</th>
<th>Coupon Claimed</th>
<th>Total Amount Earned</th>
<th>Amount to be Paid</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{" "}
{!loading && apiData.length === 0 && (
<tr className="text-center">
<td>
<h5>No Data Available</h5>
</td>
</tr>
)}
{loading ? (
<tr>
<td className="text-center">Loading...</td>
</tr>
) : (
apiData &&
apiData
.slice(
(`${page}` - 1) * itemPerPage,
`${page}` * itemPerPage
)
.map((item, i) => (
<tr key={i}>
<td>{item.name}</td>
{item.coupon_code ? (
<td>{item.coupon_code}</td>
) : (
<td>NONE</td>
)}
{item.coupon_claimed ? (
<td>{item.coupon_claimed}</td>
) : (
<td>0</td>
)}
{item.total_earning ? (
<td>{item.total_earning}</td>
) : (
<td>0</td>
)}
{item.total_earning ? (
<td>{item.total_earning - item.paid_amount}</td>
) : (
<td>0</td>
)}
{item.is_affiliate_active ? (
<td>
<p
style={{
backgroundColor: "green",
color: "white",
display: "inline-block",
padding: "2px",
width: "65px",
borderRadius: "8px",
textAlign: "center",
}}
>
{" "}
active
</p>
</td>
) : (
<td>
<p
style={{
backgroundColor: "red",
color: "white",
display: "inline-block",
padding: "2px",
width: "65px",
textAlign: "center",
borderRadius: "8px",
}}
>
{" "}
unactive
</p>
</td>
)}
<td>
<Link to={`/affiliate/affiliates/edit/${item._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
"
>
Edit
</button>
</Link>
<button
style={{
color: "white",
marginRight: "1rem",
background: `${
item.is_affiliate_active ? "red" : "green"
}`,
}}
onClick={() =>
handelSuspend(item._id, item.is_affiliate_active)
}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
{item.is_affiliate_active ? "Suspend" : "Activate"}
</button>
{item.total_earning - item.paid_amount != 0 ? (
<Link to={`/affiliate/affiliates/pay/${item._id}`}>
<button
style={{
color: "white",
marginRight: "1rem",
background: "green",
}}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
Pay
</button>
</Link>
) : (
<button
disabled
style={{
color: "white",
marginRight: "1rem",
background: "green",
}}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
Pay
</button>
)}
<Link
to={`/affiliate/affiliates/history/${item._id}`}
>
<button
style={{
color: "white",
marginRight: "1rem",
background: "grey",
}}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
History
</button>
</Link>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
{/* Table End */}
{/* Pagination div Start*/}
<div style={{ display: "flex", justifyContent: "right" }}>
<Pagination
style={{ margin: "2rem" }}
variant="outlined"
size="large"
count={getPageCount()}
color="primary"
onChange={(event, value) => setPage(value)}
/>
</div>
{/* Pagination div End*/}
{/* Coupon main body End */}
</div>
</div>
</div>
);
};
export default Affiliates;

View File

@ -0,0 +1,236 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
import { Link, useNavigate, useParams } from "react-router-dom";
import { Button, Pagination } from "@mui/material";
import { isAutheticated } from "src/auth";
import moment from "moment";
const CouponHistory = () => {
const id = useParams().id;
const token = isAutheticated();
//Navigation
const navigate = useNavigate();
const [apiData, setApiData] = useState([]);
const [couponName, setCouponName] = useState([]);
const [loading, setLoading] = useState(true); //only for testing
//Date format change function
const dateFormat = (inputDate) => {
// Split the date string by spaces to get individual components
const dateComponents = inputDate.split(" ");
// Extract day, month, and year from the components
const day = dateComponents[2];
const monthName = dateComponents[1];
const year = dateComponents[3];
// Map month names to their respective indexes
const monthsMap = {
Jan: "01",
Feb: "02",
Mar: "03",
Apr: "04",
May: "05",
Jun: "06",
Jul: "07",
Aug: "08",
Sep: "09",
Oct: "10",
Nov: "11",
Dec: "12",
};
// Get the numerical representation of the month
const month = monthsMap[monthName];
// Create the rearranged date string
const rearrangedDate = `${day} ${month} ${year}`;
return rearrangedDate;
};
//Extract time from mongodb
const extractTime = (dateTimeString) => {
const date = new Date(dateTimeString);
const hours = date.getUTCHours().toString().padStart(2, "0");
const minutes = date.getUTCMinutes().toString().padStart(2, "0");
const seconds = date.getUTCSeconds().toString().padStart(2, "0");
const time = `${hours}:${minutes}:${seconds}`;
return time;
};
//Func to get all Affiliate data
const fetchHistoryData = () => {
axios
.get(`/api/v1/coupon/history/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((response) => {
// console.log(response.data.message.coupon_used_history);
setLoading(false);
setApiData(response.data.message.coupon_used_history);
setCouponName(response.data.message.coupon_used_history[0].couponCode);
})
.catch((error) => {
setLoading(false);
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
};
//Call api onLoad of page
useEffect(() => {
fetchHistoryData();
}, []);
//pagination related
const [itemPerPage, setItemPerPage] = useState(10); //pagination
const [page, setPage] = useState(1); //pagination
// console.log(apiData);
const getPageCount = () => {
return Math.max(1, Math.ceil(apiData.length / itemPerPage));
};
return (
<div className="main-content">
<div className="my-3 page-content">
<div className="container-fluid">
{/* Coupon header start */}
<div className="row">
<div className="col-12">
<div
className="
page-title-box
d-flex
align-items-center
justify-content-between
"
>
<div
style={{ fontSize: "22px", fontWeight: "bold" }}
className="fw-bold"
>
Coupon History {couponName}
</div>
<div className="page-title-right">
<Link to="/affiliate/affiliates">
<Button
variant="contained"
color="secondary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
>
Back
</Button>
</Link>
</div>
</div>
</div>
</div>
{/* Coupon header End */}
{/* Coupon main body Start*/}
<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>
</div>
</div>
</div>
{/* Table Start */}
<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>Order Id</th>
<th>User Id</th>
<th>Date</th>
<th>Time</th>
</tr>
</thead>
<tbody>
{!loading && apiData.length === 0 && (
<tr className="text-center">
<td>
<h5>No Data Available</h5>
</td>
</tr>
)}
{loading ? (
<tr>
<td className="text-center">Loading...</td>
</tr>
) : (
apiData &&
apiData
?.slice(
(`${page}` - 1) * itemPerPage,
`${page}` * itemPerPage
)
?.map((item, i) => (
<tr key={i}>
<td>{item.orderId}</td>
<td>{item.userId}</td>
<td>{dateFormat(item.date)}</td>
<td>{moment(item.date).format("HH:mm:ss")}</td>
</tr>
))
)}
</tbody>
</table>
</div>
{/* Table End */}
{/* Pagination div Start*/}
<div style={{ display: "flex", justifyContent: "right" }}>
<Pagination
style={{ margin: "2rem" }}
variant="outlined"
size="large"
count={getPageCount()}
color="primary"
onChange={(event, value) => setPage(value)}
/>
</div>
{/* Pagination div End*/}
{/* Coupon main body End */}
</div>
</div>
</div>
);
};
export default CouponHistory;

View File

@ -0,0 +1,331 @@
import React, { useEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import axios from "axios";
import { Button, Pagination } from "@mui/material";
import { isAutheticated } from "src/auth";
const Coupons = () => {
const token = isAutheticated();
//Navigation
const navigate = useNavigate();
//pagination related
const [loading, setLoading] = useState(true); //only for testing
const [itemPerPage, setItemPerPage] = useState(10); //pagination
const [page, setPage] = useState(1); //pagination
const [apiData, setApiData] = useState([]);
//Handel Suspend
const handelSuspend = (id, active) => {
axios
.patch(
"api/v1/coupon/suspend",
{
id: id,
is_coupon_active: !active,
},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
)
.then((res) => {
// Fetch data again after updating
getAllCoupon();
})
.catch((error) => {
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
};
//Get all Coupons from the api
const getAllCoupon = () => {
axios
.get("/api/v1/coupon/getall", {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((response) => {
setLoading(false);
setApiData(response.data.message);
})
.catch((error) => {
setLoading(false);
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
};
//Calling api Onload of page
useEffect(() => {
getAllCoupon();
}, []);
//Create navigation
const navigCreate = () => {
navigate("/affiliate/coupons/create");
};
const style = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
borderRadius: "0.5rem",
boxShadow: 24,
width: "500px",
padding: "1rem",
};
const InputSpace = {
marginBottom: "1rem",
};
const getPageCount = () => {
return Math.max(1, Math.ceil(apiData?.length / itemPerPage));
};
return (
<div className="main-content">
<div className="my-3 page-content">
<div className="container-fluid">
{/* Coupon header start */}
<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">
Coupons
</div>
<div className="page-title-right">
<Button
onClick={navigCreate}
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
>
Add New Coupon
</Button>
</div>
</div>
</div>
</div>
{/* Coupon header End */}
{/* Coupon main body Start*/}
<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>
</div>
</div>
</div>
{/* Table Start */}
<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> Coupon Code</th>
<th> Affiliate</th>
<th>Discount</th>
<th>Affilite Discount</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{" "}
{!loading && apiData.length === 0 && (
<tr className="text-center">
<td>
<h5>No Data Available</h5>
</td>
</tr>
)}
{loading ? (
<tr>
<td className="text-center">Loading...</td>
</tr>
) : (
apiData &&
apiData
.slice(
(`${page}` - 1) * itemPerPage,
`${page}` * itemPerPage
)
.map((item, i) => (
<tr key={i}>
<td>
<p style={{ fontWeight: "bold" }}>
{item.coupon_code}
</p>
</td>
<td>
<p>{item.name}</p>
</td>
<td>
<p>{item.discount_amount}</p>
</td>
<td>
<p>{item.affiliate_discount_amount}</p>
</td>
<td>
{item.is_coupon_active ? (
<p
style={{
backgroundColor: "green",
color: "white",
display: "inline-block",
padding: "2px",
width: "65px",
borderRadius: "8px",
textAlign: "center",
}}
>
{" "}
active
</p>
) : (
<p
style={{
backgroundColor: "red",
color: "white",
display: "inline-block",
padding: "2px",
width: "65px",
textAlign: "center",
borderRadius: "8px",
}}
>
{" "}
unactive
</p>
)}
</td>
<td>
<Link to={`/affiliate/coupons/edit/${item._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
"
>
Edit
</button>
</Link>
<button
style={{
color: "white",
marginRight: "1rem",
background: `${
item.is_coupon_active ? "red" : "green"
}`,
}}
onClick={() =>
handelSuspend(item._id, item.is_coupon_active)
}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
{item.is_coupon_active ? "Suspend" : "Activate"}
</button>
<Link to={`/affiliate/coupons/history/${item._id}`}>
<button
style={{
color: "white",
marginRight: "1rem",
background: "grey",
}}
type="button"
className="
btn btn-sm
waves-effect waves-light
btn-table
mx-1
mt-1
"
>
History
</button>
</Link>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
{/* Table End */}
{/* Pagination div Start*/}
<div style={{ display: "flex", justifyContent: "right" }}>
<Pagination
style={{ margin: "2rem" }}
variant="outlined"
size="large"
count={getPageCount()}
color="primary"
onChange={(event, value) => setPage(value)}
/>
</div>
{/* Pagination div End*/}
{/* Coupon main body End */}
</div>
</div>
</div>
);
};
export default Coupons;

View File

@ -0,0 +1,433 @@
import React, { useEffect, useState } from "react";
import Button from "@material-ui/core/Button";
import { Link } from "react-router-dom";
import swal from "sweetalert";
import { Country, State, City } from "country-state-city";
import axios from "axios";
import { isAutheticated } from "src/auth";
const CreateAffiliate = () => {
const token = isAutheticated();
const [loading, setLoading] = useState(false);
//My states
const [name, setName] = useState("");
const [mobile, setMobile] = useState();
const [email, setEmail] = useState("");
const [country, setCountry] = useState("");
const [state, setState] = useState("");
const [city, setCity] = useState("");
const [address, setAddress] = useState("");
const [pincode, setPincode] = useState();
const [nameAsBank, setNameAsBank] = useState("");
const [accountNo, setAccountNo] = useState();
const [ifsc, setIfsc] = useState("");
const [bankName, setBankName] = useState("");
const [branchName, setBranchName] = useState("");
//Handeling Country State City
const [stateListData, setStateListData] = useState();
const [cityListData, setCityListData] = useState();
//Handel City State Country
const countrieList = Country.getAllCountries();
// const stateList = State.getStatesOfCountry();
// const cityList = City.getCitiesOfState("IN", "CT");
// console.log("Cityyyyyyyyyyy", cityList);
useEffect(() => {
const countryCode = countrieList.find((item) => item.name === country);
if (countryCode) {
const states = State.getStatesOfCountry(countryCode.isoCode);
setStateListData(states);
}
}, [country, countrieList]);
useEffect(() => {
if (state) {
const stateCode = stateListData.find((item) => item.name === state);
// console.log(stateCode);
if (stateCode) {
const cities = City.getCitiesOfState(
stateCode.countryCode,
stateCode.isoCode
);
// console.log(cities);
setCityListData(cities);
}
}
}, [state, stateListData]);
//Handel Mobile Number
const handelNumber = (e) => {
if (!(e.target.value.length > 10)) {
setMobile(e.target.value);
}
};
const handleCountry = async (e) => {
await setCountry(e.target.value);
if (stateListData || cityListData) {
setCity("");
setState("");
setCityListData([]);
setCountry(e.target.value);
}
};
const handleSubmit = () => {
if (
name === "" ||
mobile === 0 ||
email == "" ||
country === "" ||
address === "" ||
pincode === 0 ||
nameAsBank === "" ||
accountNo === 0 ||
ifsc === "" ||
bankName === "" ||
branchName === ""
) {
swal({
title: "Warning",
text: "Fill all mandatory fields",
icon: "error",
button: "Close",
dangerMode: true,
});
return;
}
setLoading(true);
const formDataObject = {
name: name,
mobile: mobile,
email: email,
country: country,
state: state,
city: city,
address: address,
pincode: pincode,
nameAsBank: nameAsBank,
accountNo: accountNo,
ifsc: ifsc,
bankName: bankName,
branchName: branchName,
};
axios
.post("/api/v1/affiliate/create", formDataObject, {
headers: {
Authorization: `Bearer ${token}`,
"Access-Control-Allow-Origin": "*",
},
})
.then((data) => {
// Handle the data returned by the server
setLoading(false);
setName("");
setMobile("");
setEmail("");
setCountry("");
setState("");
setCity("");
setAddress("");
setPincode("");
setNameAsBank("");
setAccountNo("");
setIfsc("");
setBankName("");
setBranchName("");
swal({
title: "Congratulations!!",
text: "The Coupon was Created successfully!",
icon: "success",
button: "OK",
});
return;
})
.catch((err) => {
// Handle errors
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
d-flex
align-items-center
justify-content-between
"
>
<div style={{ fontSize: "22px" }} className="fw-bold">
Add Affiliate
</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="/affiliate/affiliates">
<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-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">
Name
</label>
<input
type="text"
className="form-control"
id="name"
value={name}
maxLength={25}
onChange={(e) => setName(e.target.value)}
/>
{name ? (
<>
<small className="charLeft mt-4 fst-italic">
{25 - name.length} characters left
</small>
</>
) : (
<></>
)}{" "}
</div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Mobile
</label>
<input
type="number"
className="form-control"
id="mobile"
value={mobile}
onChange={handelNumber}
/>
</div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Email
</label>
<input
type="email"
className="form-control"
id="email"
value={email}
maxLength="100"
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="mb-3">
<label htmlFor="categorySelect">Select a Country</label>
<select
id="country"
className="form-control"
style={{ width: "100%" }}
value={country}
onChange={handleCountry}
>
<option value={"None"}>None</option>
{countrieList.map((country) => (
<option key={country.isoCode} value={country.name}>
{country.name}
</option>
))}
</select>
</div>
<div className="mb-3">
<label htmlFor="categorySelect">Select a State</label>
<select
id="state"
className="form-control"
style={{ width: "100%" }}
value={state}
onChange={(e) => setState(e.target.value)}
>
<option value={""}>None</option>
{stateListData?.map((states) => (
<option key={states.isoCode}>{states.name}</option>
))}
</select>
</div>
<div className="mb-3">
<label htmlFor="categorySelect">Select a City</label>
<select
id="city"
className="form-control"
style={{ width: "100%" }}
value={city}
onChange={(e) => setCity(e.target.value)}
>
<option value={""}>None</option>
{cityListData?.map((city) => (
<option value={city.isoCode}>{city.name}</option>
))}
</select>
</div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Address
</label>
<input
type="text"
className="form-control"
id="address"
value={address}
maxLength={25}
onChange={(e) => setAddress(e.target.value)}
/>
{name ? (
<>
<small className="charLeft mt-4 fst-italic">
{25 - name.length} characters left
</small>
</>
) : (
<></>
)}{" "}
</div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Pincode
</label>
<input
type="number"
className="form-control"
id="pincode"
value={pincode}
maxLength={25}
onChange={(e) => setPincode(e.target.value)}
/>
{name ? (
<>
<small className="charLeft mt-4 fst-italic">
{25 - name.length} characters left
</small>
</>
) : (
<></>
)}{" "}
</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">
Name as per Bank records
</label>
<input
type="text"
className="form-control"
id="nameasbank"
value={nameAsBank}
onChange={(e) => setNameAsBank(e.target.value)}
/>
</div>
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Account Number
</label>
<input
type="number"
className="form-control"
id="accountno"
value={accountNo}
onChange={(e) => setAccountNo(e.target.value)}
/>
</div>
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
IFSC Code
</label>
<input
type="text"
className="form-control"
id="ifsc"
value={ifsc}
onChange={(e) => setIfsc(e.target.value)}
/>
</div>
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Bank Name
</label>
<input
type="text"
className="form-control"
id="bankname"
value={bankName}
onChange={(e) => setBankName(e.target.value)}
/>
</div>
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Branch Name
</label>
<input
type="text"
className="form-control"
id="branchname"
value={branchName}
onChange={(e) => setBranchName(e.target.value)}
/>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default CreateAffiliate;

View File

@ -0,0 +1,355 @@
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import toast, { Toaster } from "react-hot-toast";
import { Button, Box, TextField, Typography } from "@mui/material";
import { isAutheticated } from "src/auth";
const CreateCoupon = () => {
const token = isAutheticated();
const navigate = useNavigate();
const [loading, setLoading] = useState(false); //only for testing
const [itemPerPage, setItemPerPage] = useState(10); //pagination
const [page, setPage] = useState(1); //pagination
//Form States
const [open, setOpen] = useState(false);
const [coupon, setCoupon] = useState("");
const [discount, setDiscount] = useState("");
const [affiliateDiscountAmt, setAffiliateDiscountAmt] = useState("");
const [valid, setValid] = useState("");
const [affiliate, setAffiliate] = useState("");
//Form error states
const [couponError, setCouponError] = useState(false);
const [discountError, setDiscountError] = useState(false);
const [validError, setValidError] = useState(false);
const [affiliateError, setAffiliateError] = useState(false);
const [affiliateDiscountAmtError, setAffiliateDiscountAmtError] =
useState(false);
const [apiData, setApiData] = useState([]);
//Discount limit
const handelDiscount = (event) => {
let value = event.target.value;
if (parseInt(value) >= 9999) {
setDiscount(9999);
setDiscountError(true);
} else if (parseInt(value) < 0) {
setDiscount(0);
} else {
setDiscountError(false);
setDiscount(value);
}
};
const handelAffilateDiscount = (event) => {
let value = event.target.value;
if (parseInt(value) >= 9999) {
setAffiliateDiscountAmt(9999);
setAffiliateDiscountAmtError(true);
} else if (parseInt(value) < 0) {
setDiscount(0);
} else {
setAffiliateDiscountAmtError(false);
setAffiliateDiscountAmt(value);
}
};
//Handel Form Submition
const handelCreate = (e) => {
e.preventDefault();
if (!(coupon.length === 8)) {
setCouponError(true);
toast.error("Code should be of 8 charecter");
return;
}
if (valid === "") {
setValidError(true);
toast.error("Valid till is required");
return;
}
if (affiliate === "") {
setAffiliateError(true);
toast.error("Affiliate is required");
return;
}
if (discount == "") {
setDiscountError(true);
toast.error("Discount amount is required");
return;
}
if (affiliateDiscountAmt == "") {
setAffiliateDiscountAmtError(true);
toast.error("Affiliate Discount Amount is required");
return;
}
//Sending api Obj--------------------
let formDataObject = {
coupon_code: coupon,
discount_amount: discount,
affiliate_discount_amount: affiliateDiscountAmt,
valid_till: valid,
is_coupon_active: true,
id: affiliate,
};
axios
.patch("/api/v1/coupon/create", formDataObject, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((data) => {
//reset Inputs
setDiscount("");
setCoupon("");
setValid("");
setAffiliate("");
fetchAffiliate();
setCouponError(false);
setDiscountError(false);
setValidError(false);
setAffiliateError(false);
setAffiliateDiscountAmtError(false);
swal({
title: "Congratulations!!",
text: "The Coupon was Created successfully!",
icon: "success",
button: "OK",
});
})
.catch((error) => {
// Handle errors
const message = error.response?.data?.message
? error.response?.data?.message
: "Something went wrong!";
toast.error(message);
console.error("There was a problem with your fetch operation:", error);
})
.finally(() => {
// Reset the affiliate and affiliateError state
setAffiliateError(false);
// Show success message
// console.log(coupon, discount, valid, affiliate);
});
};
const InputSpace = {
marginBottom: "1rem",
width: "20rem ",
height: "45px",
};
//Back to Coupons
const handelBack = () => {
navigate("/affiliate/coupons");
};
//Calling api to get Affiliates
const fetchAffiliate = () => {
axios
.get("/api/v1/coupon/getaffiliate", {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((response) => {
setApiData(response.data.message);
})
.catch((error) => {
console.log(error.message);
});
};
//Calling api
useEffect(() => {
fetchAffiliate();
}, []);
return (
<div className="container">
<div
className=" page-title-box
d-flex
align-items-center
justify-content-between
flex-direction-row"
>
<div>
<h3>Coupons</h3>
</div>
<div className="d-flex">
<div>
<Button
className="mx-2"
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
onClick={handelCreate}
>
Create
</Button>
</div>
<div>
<Button
onClick={handelBack}
variant="contained"
style={{
fontWeight: "bold",
marginBottom: "1rem",
backgroundColor: "red",
textTransform: "capitalize",
}}
>
Back
</Button>
</div>
</div>
</div>
<div className="row">
<div
style={{
padding: "2rem",
borderRadius: "0.5rem",
backgroundColor: "white",
marginBottom: "1rem",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
width: "80%",
margin: "auto",
}}
className="border"
>
<div style={{ width: "100%" }}>
<Box>
<Typography className="mb-1">
Coupon Code (Must be 8 digit)
</Typography>
<TextField
className="mb-3"
required={true}
sx={InputSpace}
value={coupon}
InputProps={{
inputProps: {
maxLength: 8,
minLength: 8,
},
}}
onChange={(e) => {
setCoupon(e.target.value);
}}
error={couponError}
style={{ width: "100%" }}
/>
{couponError ? (
<small style={{ color: "red" }}>8 characters required</small>
) : (
""
)}
<Typography className="mb-1">Discount Amount</Typography>
<div className="d-flex align-items-center">
<div
style={{
marginRight: "5px",
}}
className="d-flex justify-content-center"
>
<span style={{ fontSize: "1.7rem" }}></span>
</div>
<TextField
className="mb-3"
required={true}
error={discountError}
type="number"
value={discount}
sx={InputSpace}
onChange={handelDiscount}
style={{ flex: 1 }}
/>
</div>
<Typography className="mb-1">
Affiliate Discount Amount
</Typography>
<div className="d-flex align-items-center">
<div
style={{
marginRight: "5px",
}}
className="d-flex justify-content-center"
>
<span style={{ fontSize: "1.7rem" }}></span>
</div>
<TextField
className="mb-3"
required={true}
error={discountError}
type="number"
value={affiliateDiscountAmt}
sx={InputSpace}
onChange={handelAffilateDiscount}
style={{ flex: 1 }}
/>
</div>
{affiliateDiscountAmtError ? (
<small style={{ color: "red" }}>Max Amount Rs.9999</small>
) : (
""
)}
<Typography className="mb-1">Coupon Valid Till: </Typography>
<input
style={{
width: "100%",
height: "50px",
outline: validError ? "1px solid red" : "",
}}
className="mb-2"
value={valid}
sx={InputSpace}
onChange={(e) => {
setValid(e.target.value);
}}
type="date"
/>
{validError ? (
<small style={{ color: "red" }}>
Validity Date is Required
</small>
) : (
""
)}
<Typography className="mb-1">Select Affiliate</Typography>
<select
onChange={(e) => {
setAffiliate(e.target.value);
}}
style={{
width: "100%",
height: "50px",
outline: validError ? "1px solid red" : "",
}}
>
<option value="">None</option>
{apiData?.length > 0 &&
apiData.map((data) => {
return (
<option value={data._id} key={data._id}>
{data.name}-{data.mobile}
</option>
);
})}
</select>
{affiliateError ? (
<small style={{ color: "red" }}>Affiliation is Required</small>
) : (
""
)}
<br />
</Box>
</div>
</div>
</div>
</div>
);
};
export default CreateCoupon;

View File

@ -0,0 +1,458 @@
import React, { useEffect, useState } from "react";
import Button from "@material-ui/core/Button";
import { Link, useNavigate, useParams } from "react-router-dom";
import swal from "sweetalert";
import { Country, State, City } from "country-state-city";
import axios from "axios";
import { isAutheticated } from "src/auth";
const EditAffiliate = () => {
const token = isAutheticated();
const navigate = useNavigate();
const id = useParams().id;
const [loading, setLoading] = useState(false);
//My states
const [name, setName] = useState("");
const [mobile, setMobile] = useState();
const [email, setEmail] = useState("");
const [country, setCountry] = useState("");
const [state, setState] = useState("");
const [city, setCity] = useState("");
const [address, setAddress] = useState("");
const [pincode, setPincode] = useState();
const [nameAsBank, setNameAsBank] = useState("");
const [accountNo, setAccountNo] = useState();
const [ifsc, setIfsc] = useState("");
const [bankName, setBankName] = useState("");
const [branchName, setBranchName] = useState("");
//Handel Mobile Number
const handelNumber = (e) => {
if (!(e.target.value.length > 10)) {
setMobile(e.target.value);
}
};
//Handeling Country State City
const [stateListData, setStateListData] = useState();
const [cityListData, setCityListData] = useState();
const handleCountry = async (e) => {
await setCountry(e.target.value);
if (stateListData || cityListData) {
setCity("");
setState("");
setCityListData([]);
setCountry(e.target.value);
}
};
//Handel City State Country
const countrieList = Country.getAllCountries();
// const stateList = State.getStatesOfCountry();
// const cityList = City.getCitiesOfState("IN", "CT");
// console.log("Cityyyyyyyyyyy", cityList);
useEffect(() => {
const countryCode = countrieList.find((item) => item.name === country);
if (countryCode) {
const states = State.getStatesOfCountry(countryCode.isoCode);
setStateListData(states);
}
}, [country, countrieList]);
useEffect(() => {
if (state) {
const stateCode = stateListData?.find((item) => item.name === state);
// console.log(stateCode);
if (stateCode) {
const cities = City.getCitiesOfState(
stateCode.countryCode,
stateCode.isoCode
);
// console.log(cities);
setCityListData(cities);
}
}
}, [state, stateListData]);
//Calling to Fill form
useEffect(() => {
axios
.get(`/api/v1/affiliate/getone/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
// console.log(res.data.message);
setName(res.data.message.name);
setMobile(res.data.message.mobile);
setEmail(res.data.message.email);
setCountry(res.data.message.country);
setState(res.data.message.state);
setCity(res.data.message.city);
setAddress(res.data.message.address);
setPincode(res.data.message.pincode);
setNameAsBank(res.data.message.nameAsBank);
setAccountNo(res.data.message.accountNo);
setIfsc(res.data.message.ifsc);
setBankName(res.data.message.bankName);
setBranchName(res.data.message.branchName);
})
.catch((error) => {
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
}, []);
//On form submit
const handleSubmit = () => {
if (
name === "" ||
mobile === 0 ||
email == "" ||
country === "" ||
address === "" ||
pincode === 0 ||
nameAsBank === "" ||
accountNo === 0 ||
ifsc === "" ||
bankName === "" ||
branchName === ""
) {
swal({
title: "Warning",
text: "Fill all mandatory fields",
icon: "error",
button: "Close",
dangerMode: true,
});
return;
}
setLoading(true);
const formDataObject = {
name: name,
mobile: mobile,
email: email,
country: country,
state: state,
city: city,
address: address,
pincode: pincode,
nameAsBank: nameAsBank,
accountNo: accountNo,
ifsc: ifsc,
bankName: bankName,
branchName: branchName,
};
axios
.patch(`/api/v1/affiliate/edit/${id}`, formDataObject, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((data) => {
// Handle the data returned by the server
setLoading(false);
//Resetting Inputs
setName("");
setMobile("");
setEmail("");
setCountry("");
setState("");
setCity("");
setAddress("");
setPincode("");
setNameAsBank("");
setAccountNo("");
setIfsc("");
setBankName("");
setBranchName("");
swal({
title: "Congratulations!!",
text: "The Coupon was Created successfully!",
icon: "success",
button: "OK",
});
navigate("/affiliate/affiliates");
return;
})
.catch((error) => {
setLoading(false);
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
};
return (
<div className="container">
<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">
Edit Affiliate
</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="/affiliate/affiliates">
<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-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">
Name
</label>
<input
type="text"
className="form-control"
id="name"
value={name}
maxLength={25}
onChange={(e) => setName(e.target.value)}
/>
{name ? (
<>
<small className="charLeft mt-4 fst-italic">
{25 - name.length} characters left
</small>
</>
) : (
<></>
)}{" "}
</div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Mobile
</label>
<input
type="number"
className="form-control"
id="mobile"
value={mobile}
maxLength="100"
onChange={handelNumber}
/>
</div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Email
</label>
<input
type="email"
className="form-control"
id="email"
value={email}
maxLength="100"
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="mb-3">
<label htmlFor="categorySelect">Select a Country</label>
<select
id="country"
className="form-control"
style={{ width: "100%" }}
value={country}
onChange={handleCountry}
>
<option value={"None"}>None</option>
{countrieList.map((country) => (
<option key={country.isoCode} value={country.name}>
{country.name}
</option>
))}
</select>
</div>
<div className="mb-3">
<label htmlFor="categorySelect">Select a State</label>
<select
id="state"
className="form-control"
style={{ width: "100%" }}
value={state}
onChange={(e) => setState(e.target.value)}
>
<option value={""}>None</option>
{stateListData?.map((states, i) => (
<option key={states.isoCode}>{states.name}</option>
))}
</select>
</div>
<div className="mb-3">
<label htmlFor="categorySelect">Select a City</label>
<select
id="city"
className="form-control"
style={{ width: "100%" }}
value={city}
onChange={(e) => setCity(e.target.value)}
>
<option value={""}>None</option>
{cityListData?.map((city, i) => (
<option key={i} value={city.isoCode}>
{city.name}
</option>
))}
</select>
</div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Address
</label>
<input
type="text"
className="form-control"
id="address"
value={address}
maxLength={25}
onChange={(e) => setAddress(e.target.value)}
/>
{name ? (
<>
<small className="charLeft mt-4 fst-italic">
{25 - name.length} characters left
</small>
</>
) : (
<></>
)}{" "}
</div>
<div className="mb-3">
<label htmlFor="title" className="form-label">
Pincode
</label>
<input
type="number"
className="form-control"
id="pincode"
value={pincode}
maxLength={25}
onChange={(e) => setPincode(e.target.value)}
/>
{name ? (
<>
<small className="charLeft mt-4 fst-italic">
{25 - name.length} characters left
</small>
</>
) : (
<></>
)}{" "}
</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">
Name as per Bank records
</label>
<input
type="text"
className="form-control"
id="nameasbank"
value={nameAsBank}
onChange={(e) => setNameAsBank(e.target.value)}
/>
</div>
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Account Number
</label>
<input
type="number"
className="form-control"
id="accountno"
value={accountNo}
onChange={(e) => setAccountNo(e.target.value)}
/>
</div>
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
IFSC Code
</label>
<input
type="text"
className="form-control"
id="ifsc"
value={ifsc}
onChange={(e) => setIfsc(e.target.value)}
/>
</div>
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Bank Name
</label>
<input
type="text"
className="form-control"
id="bankname"
value={bankName}
onChange={(e) => setBankName(e.target.value)}
/>
</div>
<div className="mb-3 me-3">
<label htmlFor="title" className="form-label">
Branch Name
</label>
<input
type="text"
className="form-control"
id="branchname"
value={branchName}
onChange={(e) => setBranchName(e.target.value)}
/>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default EditAffiliate;

View File

@ -0,0 +1,373 @@
import React, { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import axios from "axios";
import toast, { Toaster } from "react-hot-toast";
import { Button, Box, TextField, Typography } from "@mui/material";
import { isAutheticated } from "src/auth";
const EditCoupon = () => {
const token = isAutheticated();
const id = useParams().id;
const navigate = useNavigate();
//Style for inputs
const InputSpace = {
marginBottom: "1rem",
width: "20rem ",
height: "45px",
};
//Pagination Related
const [loading, setLoading] = useState(false); //only for testing
const [itemPerPage, setItemPerPage] = useState(10); //pagination
const [page, setPage] = useState(1); //pagination
//Form related
const [open, setOpen] = useState(false);
const [coupon, setCoupon] = useState("");
const [discount, setDiscount] = useState();
const [affiliateDiscountAmt, setAffiliateDiscountAmt] = useState();
const [valid, setValid] = useState("");
const [affiliate, setAffiliate] = useState("");
//Form error states
const [couponError, setCouponError] = useState(false);
const [discountError, setDiscountError] = useState(false);
const [validError, setValidError] = useState(false);
const [affiliateError, setAffiliateError] = useState(false);
const [affiliateDiscountAmtError, setAffiliateDiscountAmtError] =
useState(false);
//Start of Page
const [apiData, setApiData] = useState([]);
//Discount limit
const handelDiscount = (event) => {
let value = event.target.value;
if (parseInt(value) >= 9999) {
setDiscount(9999);
setDiscountError(true);
} else if (parseInt(value) < 0) {
setDiscount(0);
} else {
setDiscountError(false);
setDiscount(value);
}
};
//Affiliate Earning Handler
const handelAffilateDiscount = (event) => {
let value = event.target.value;
if (parseInt(value) >= 9999) {
setAffiliateDiscountAmt(9999);
setAffiliateDiscountAmtError(true);
} else if (parseInt(value) < 0) {
setDiscount(0);
} else {
setAffiliateDiscountAmtError(false);
setAffiliateDiscountAmt(value);
}
};
//Handel Form Submition
const handelCreate = (e) => {
e.preventDefault();
if (!(coupon.length === 8)) {
setCouponError(true);
toast.error("Code should be of 8 charecter");
return;
}
if (valid === "") {
setValidError(true);
toast.error("Valid till is required");
return;
}
if (affiliate === "") {
setAffiliateError(true);
toast.error("Affiliate is required");
return;
}
if (discount === 0) {
setDiscountError(true);
toast.error("Discount amount is required");
return;
}
//Testing Validation for Affiliate Amount
if (!affiliateDiscountAmt) {
setAffiliateDiscountAmtError(true);
toast.error("Affiliate Discount Amount is required");
return;
}
if (affiliateDiscountAmt === 0 || affiliateDiscountAmt === "") {
setAffiliateDiscountAmtError(true);
toast.error("Affiliate Discount Amount is required");
return;
}
//Sending api --------------------
let formDataObject = {
coupon_code: coupon,
discount_amount: discount,
affiliate_discount_amount: affiliateDiscountAmt,
valid_till: valid,
is_coupon_active: true,
id: affiliate,
};
//PATCH REQUEST
axios
.patch(`/api/v1/coupon/edit/${id}`, formDataObject, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((data) => {
//Reset Inputs
// console.log("Response:", data);
setDiscount("");
setCoupon("");
setValid("");
setAffiliate("");
setAffiliateDiscountAmt("");
// fetchCoupon();
setCouponError(false);
setDiscountError(false);
setValidError(false);
setAffiliateError(false);
setAffiliateDiscountAmtError(false);
swal({
title: "Congratulations!!",
text: "The Coupon was Edited successfully!",
icon: "success",
button: "OK",
});
navigate("/affiliate/coupons");
})
.catch((error) => {
// Handle errors
const message = error.response?.data?.message
? error.response?.data?.message
: "Something went wrong!";
toast.error(message);
console.error("There was a problem with your fetch operation:", error);
})
.finally(() => {
setAffiliateError(false);
});
};
//Back to Coupons
const handelBack = () => {
navigate("/affiliate/coupons");
};
//Fetch coupon data
const fetchCoupon = () => {
axios
.get(`/api/v1/coupon/getone/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
setCoupon(res.data.message.coupon_code);
setDiscount(res.data.message.discount_amount);
setAffiliateDiscountAmt(res.data.message.affiliate_discount_amount);
setValid(res.data.message.valid_till);
setApiData({
name: res.data.message.name,
mobile: res.data.message.mobile,
});
setAffiliate(id);
})
.catch((error) => {
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
};
//Calling to fill form and Affiliate
useEffect(() => {
fetchCoupon();
}, []);
return (
<div className="container">
<div
className=" page-title-box
d-flex
align-items-center
justify-content-between
flex-direction-row"
>
<div>
<h3>Edit Coupons</h3>
</div>
<div className="d-flex">
<div>
<Button
className="mx-2"
variant="contained"
color="primary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
onClick={handelCreate}
>
Edit
</Button>
</div>
<div>
<Button
onClick={handelBack}
variant="contained"
style={{
fontWeight: "bold",
marginBottom: "1rem",
backgroundColor: "red",
textTransform: "capitalize",
}}
>
Back
</Button>
</div>
</div>
</div>
<div className="row">
<div
style={{
padding: "2rem",
borderRadius: "0.5rem",
backgroundColor: "white",
marginBottom: "1rem",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
width: "80%",
margin: "auto",
}}
className="border"
>
<div style={{ width: "100%" }}>
<Box>
<Typography className="mb-1">Coupon Code</Typography>
<TextField
className="mb-3"
required={true}
sx={InputSpace}
value={coupon}
InputProps={{
inputProps: {
maxLength: 8,
minLength: 8,
},
}}
onChange={(e) => {
setCoupon(e.target.value);
}}
error={couponError}
style={{ width: "100%" }}
/>
{couponError ? (
<small style={{ color: "red" }}>8 characters required</small>
) : (
""
)}
<Typography className="mb-1">Discount Amount</Typography>
<div className="d-flex align-items-center">
<div
style={{
marginRight: "5px",
}}
className="d-flex justify-content-center"
>
<span style={{ fontSize: "1.7rem" }}></span>
</div>
<TextField
className="mb-3"
required={true}
error={discountError}
type="number"
value={discount}
sx={InputSpace}
onChange={handelDiscount}
style={{ flex: 1 }}
/>
</div>
<Typography className="mb-1">
Affiliate Discount Amount
</Typography>
<div className="d-flex align-items-center">
<div
style={{
marginRight: "5px",
}}
className="d-flex justify-content-center"
>
<span style={{ fontSize: "1.7rem" }}></span>
</div>
<TextField
className="mb-3"
required={true}
error={discountError}
type="number"
value={affiliateDiscountAmt}
sx={InputSpace}
onChange={handelAffilateDiscount}
style={{ flex: 1 }}
/>
</div>
{affiliateDiscountAmtError ? (
<small style={{ color: "red" }}>Max Amount Rs.9999</small>
) : (
""
)}
<Typography className="mb-1">Coupon Valid Till: </Typography>
<input
style={{
width: "100%",
height: "50px",
outline: validError ? "1px solid red" : "",
}}
className="mb-2"
value={valid}
sx={InputSpace}
onChange={(e) => {
setValid(e.target.value);
}}
type="date"
/>
{validError ? (
<small style={{ color: "red" }}>
Validity Date is Required
</small>
) : (
""
)}
<Typography className="mb-1">Select Affiliate</Typography>
<select
onChange={(e) => {
setAffiliate(e.target.value);
}}
style={{
width: "100%",
height: "50px",
outline: validError ? "1px solid red" : "",
}}
>
<option
value={id}
>{`${apiData.name} - ${apiData.mobile}`}</option>
</select>
{affiliateError ? (
<small style={{ color: "red" }}>Affiliation is Required</small>
) : (
""
)}
<br />
</Box>
</div>
</div>
</div>
</div>
);
};
export default EditCoupon;

View File

@ -0,0 +1,309 @@
import React, { useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import axios from "axios";
import toast, { Toaster } from "react-hot-toast";
import { Button, Box, TextField, Typography } from "@mui/material";
import { isAutheticated } from "src/auth";
const PayAffiliate = () => {
const token = isAutheticated();
const id = useParams().id;
const navigate = useNavigate();
//Style for inputs
const InputSpace = {
marginBottom: "1rem",
width: "20rem ",
height: "45px",
};
//Set Affiliate Data
const [affiliate, setAffiliate] = useState("");
const [affiliateID, setAffiliateID] = useState("");
const [noOfCoupons, setNoOfCoupons] = useState("");
const [amountToPay, setAmountToPay] = useState("");
const [coupon, setCoupon] = useState("");
const [nameAsBank, setNameAsBank] = useState("");
const [accountNo, setAccountNo] = useState("");
const [ifsc, setIfsc] = useState("");
const [bankName, setBankName] = useState("");
const [branchName, setBranchName] = useState("");
const [affiliateDiscountAmt, setAffiliateDiscountAmt] = useState();
//Form related
const [amount, setAmount] = useState();
const [transecId, setTransecId] = useState("");
const [date, setDate] = useState("");
const [time, setTime] = useState("");
//Handel Pay
const handlePay = (e) => {
e.preventDefault();
// console.log(amount, transecId, date);
const formDataObject = {
noOfCoupons,
amountToPay,
amount,
transecId,
date,
time,
};
axios
.post(`/api/v1/affiliate/pay/${id}`, formDataObject, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((data) => {
swal({
title: "Congratulations!!",
text: "Successfully Payed!",
icon: "success",
button: "OK",
});
navigate("/affiliate/affiliates");
})
.catch((error) => {
// Handle errors
const message = error.response?.data?.message
? error.response?.data?.message
: "Something went wrong!";
toast.error(message);
console.error("Error in Payment:", error);
});
};
//Fetch coupon data
const fetchPayData = () => {
axios
.get(`/api/v1/affiliate/getpay/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((res) => {
// console.log(res.data.message);
setAffiliate(res.data.message.name);
setNoOfCoupons(
res.data.message?.coupon_claimed - res.data.message?.no_of_paid_coupon
);
setAmountToPay(
res.data.message.total_earning - res.data.message.paid_amount
);
setAmount(
res.data.message.total_earning - res.data.message.paid_amount
);
setCoupon(res.data.message.coupon_code);
setAffiliateDiscountAmt(res.data.message.affiliate_discount_amount);
setAffiliateID(id);
setNameAsBank(res.data.message.nameAsBank);
setAccountNo(res.data.message.accountNo);
setIfsc(res.data.message.ifsc);
setBankName(res.data.message.bankName);
setBranchName(res.data.message.branchName);
})
.catch((error) => {
const message =
error?.response?.data?.message || "Something went wrong!";
console.log(message);
});
};
//Calling to fill form and Affiliate
useEffect(() => {
fetchPayData();
}, []);
return (
<>
<div className="d-flex justify-content-end">
<Link to="/affiliate/affiliates">
<Button
variant="contained"
color="secondary"
style={{
fontWeight: "bold",
marginBottom: "1rem",
textTransform: "capitalize",
}}
>
Back
</Button>
</Link>
</div>
<div className="row">
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
<div
style={{
display: "flex",
justifyContent: "center",
}}
className="card"
>
<div className="card-body p-2">
<div
style={{
padding: "2rem",
borderRadius: "0.5rem",
backgroundColor: "white",
// marginBottom: "1rem",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
}}
className="border"
>
<div style={{ width: "100%" }}>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>Affiliate Name: </span>
{affiliate}
</Typography>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>Coupon Code: </span>
{coupon}
</Typography>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>
Per coupon price:{" "}
</span>
{affiliateDiscountAmt}
</Typography>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>
No of coupon paying for:{" "}
</span>
{noOfCoupons} Units
</Typography>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>
Amount to be paid:{" "}
</span>
{amountToPay}
</Typography>
</div>
</div>
</div>
</div>
</div>
<div className="col-lg-6 col-md-6 col-sm-12 my-1">
<div
style={{
display: "flex",
justifyContent: "center",
}}
className="card"
>
<div className="card-body p-2">
<div
style={{
padding: "2rem",
borderRadius: "0.5rem",
backgroundColor: "white",
// marginBottom: "1rem",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
}}
className="border"
>
<div style={{ width: "100%" }}>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>
Name as per Bank records:{" "}
</span>
{nameAsBank}
</Typography>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>Account Number: </span>
{accountNo}
</Typography>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>IFSC Code: </span>
{ifsc}
</Typography>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>Bank Name: </span>
{bankName}
</Typography>
<Typography className="mb-3">
<span style={{ fontWeight: "bold" }}>Branch Name: </span>
{branchName}
</Typography>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-12 col-md-12 col-sm-12 my-1">
<div className="card">
<div className="card-body p-5">
<form onSubmit={handlePay}>
<div className="d-lg-flex justify-content-center align-items-center">
<label htmlFor="title" className="form-label mr-2">
Transection ID
</label>
<input
onChange={(e) => setTransecId(e.target.value)}
required="true"
type="text"
className="form-control mb-3 col-lg-4 col-md-12 col-sm-12 mr-5"
id="ifsc"
/>
<label htmlFor="title" className="form-label mr-2">
Date
</label>
<input
required="true"
type="date"
onChange={(e) => setDate(e.target.value)}
className="form-control mb-3 col-lg-3 col-md-12 col-sm-12"
id="ifsc"
/>
</div>
<div>
<div className="d-lg-flex align-items-center justify-content-center">
<label htmlFor="title" className="form-label mr-2">
Time
</label>
<input
required="true"
type="time"
onChange={(e) => setTime(e.target.value)}
className="form-control mb-3 col-lg-3 col-md-12 col-sm-12 mr-5"
id="ifsc"
/>
{/* <label htmlFor="title" className="form-label mr-2">
Amount
</label> */}
<span className="mb-3" style={{ marginRight: "0.5rem" }}>
Amount Rs.
</span>
<input
required="true"
type="number"
className="form-control mb-3 col-lg-3 col-md-12 col-sm-12 mr-4 mb-4"
value={amount}
onChange={(e) => setAmount(e.target.value)}
id="amount"
/>
<Button
sx={{ marginTop: "-20px" }}
type="submit"
variant="contained"
color="success"
>
Pay
</Button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</>
);
};
export default PayAffiliate;