first commit
This commit is contained in:
154
src/pages/Coupons/CouponDetails.jsx
Normal file
154
src/pages/Coupons/CouponDetails.jsx
Normal file
@@ -0,0 +1,154 @@
|
||||
import { useParams, Link, useNavigate } from "react-router-dom";
|
||||
import {
|
||||
useGetCouponByIdQuery,
|
||||
useToggleCouponStatusMutation,
|
||||
} from "../../features/coupons/couponAPI";
|
||||
import { ArrowLeft, Percent, Calendar, Activity } from "lucide-react";
|
||||
import { formatDate } from "../../utils/formatDate";
|
||||
|
||||
/* ---------- Status Badge ---------- */
|
||||
const StatusBadge = ({ isActive }) => (
|
||||
<span
|
||||
className={`px-3 py-1 rounded-full text-xs font-semibold
|
||||
${isActive ? "bg-green-100 text-green-700" : "bg-red-100 text-red-700"}`}
|
||||
>
|
||||
{isActive ? "ACTIVE" : "INACTIVE"}
|
||||
</span>
|
||||
);
|
||||
|
||||
/* ---------- Main Component ---------- */
|
||||
const CouponDetails = () => {
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const {
|
||||
data: coupon,
|
||||
isLoading,
|
||||
isError,
|
||||
} = useGetCouponByIdQuery(id, { skip: !id });
|
||||
|
||||
const [toggleCouponStatus, { isLoading: toggling }] =
|
||||
useToggleCouponStatusMutation();
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center h-64 text-gray-600">
|
||||
Loading coupon details...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isError || !coupon) {
|
||||
return (
|
||||
<div className="text-center py-10 text-red-500">
|
||||
Failed to load coupon details
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto p-6 space-y-6">
|
||||
{/* Back Button */}
|
||||
<div className="flex items-center gap-2 text-blue-600 hover:text-blue-800">
|
||||
<ArrowLeft size={18} />
|
||||
<button onClick={() => navigate(-1)} className="font-medium">
|
||||
Back to Coupons
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Header Card */}
|
||||
<div className="bg-white shadow-lg rounded-2xl p-6 flex flex-col md:flex-row justify-between items-start md:items-center gap-6">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-gray-800">{coupon.code}</h2>
|
||||
<p className="text-gray-500">{coupon.description}</p>
|
||||
<div className="mt-2">
|
||||
<StatusBadge isActive={coupon.isActive} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-right space-y-2">
|
||||
<p className="text-2xl font-extrabold text-green-600">
|
||||
{coupon.type === "PERCENTAGE"
|
||||
? `${coupon.value}% OFF`
|
||||
: `₹${coupon.value} OFF`}
|
||||
</p>
|
||||
|
||||
<button
|
||||
onClick={() => toggleCouponStatus(coupon.id)}
|
||||
disabled={toggling}
|
||||
className={`px-4 py-2 rounded-lg text-sm font-semibold transition
|
||||
${
|
||||
coupon.isActive
|
||||
? "bg-red-100 text-red-700 hover:bg-red-200"
|
||||
: "bg-green-100 text-green-700 hover:bg-green-200"
|
||||
}`}
|
||||
>
|
||||
{coupon.isActive ? "Deactivate Coupon" : "Activate Coupon"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Info Cards */}
|
||||
<div className="grid md:grid-cols-3 gap-6">
|
||||
{/* Discount */}
|
||||
<div className="bg-gradient-to-r from-purple-50 to-purple-100 p-6 rounded-2xl shadow hover:shadow-lg transition">
|
||||
<h3 className="text-gray-700 font-semibold mb-2 flex items-center gap-2">
|
||||
<Percent size={16} /> Discount
|
||||
</h3>
|
||||
<p className="text-xl font-bold text-purple-700">
|
||||
{coupon.type === "PERCENTAGE"
|
||||
? `${coupon.value}%`
|
||||
: `₹${coupon.value}`}
|
||||
</p>
|
||||
<p className="text-gray-600 text-sm">
|
||||
Min Order: ₹{coupon.minOrderAmount}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Validity */}
|
||||
<div className="bg-gradient-to-r from-blue-50 to-blue-100 p-6 rounded-2xl shadow hover:shadow-lg transition">
|
||||
<h3 className="text-gray-700 font-semibold mb-2 flex items-center gap-2">
|
||||
<Calendar size={16} /> Validity
|
||||
</h3>
|
||||
<p className="text-gray-800 text-sm">
|
||||
From: {formatDate(coupon.validFrom)}
|
||||
</p>
|
||||
<p className="text-gray-800 text-sm">
|
||||
Till: {formatDate(coupon.validUntil)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Usage */}
|
||||
<div className="bg-gradient-to-r from-green-50 to-green-100 p-6 rounded-2xl shadow hover:shadow-lg transition">
|
||||
<h3 className="text-gray-700 font-semibold mb-2 flex items-center gap-2">
|
||||
<Activity size={16} /> Usage
|
||||
</h3>
|
||||
<p className="text-xl font-bold text-green-700">
|
||||
{coupon.usedCount}/{coupon.maxUses}
|
||||
</p>
|
||||
<p className="text-gray-600 text-sm">
|
||||
Remaining: {coupon.remainingUses}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Extra Info */}
|
||||
<div className="bg-white shadow-lg rounded-2xl p-6 text-sm text-gray-600 grid md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<b>Created At:</b> {formatDate(coupon.createdAt)}
|
||||
</div>
|
||||
<div>
|
||||
<b>Last Updated:</b> {formatDate(coupon.updatedAt)}
|
||||
</div>
|
||||
<div>
|
||||
<b>Expired:</b> {coupon.isExpired ? "Yes ❌" : "No ✅"}
|
||||
</div>
|
||||
<div>
|
||||
<b>Not Started:</b> {coupon.isNotStarted ? "Yes ⏳" : "No"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CouponDetails;
|
||||
Reference in New Issue
Block a user