feat: update all approval
This commit is contained in:
parent
5579ad8c20
commit
be02fb7b0e
|
|
@ -47,9 +47,9 @@ import {
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import CustomPagination from "../layout/custom-pagination";
|
import CustomPagination from "../layout/custom-pagination";
|
||||||
import { EditBannerDialog } from "../form/banner-edit-dialog";
|
import { EditBannerDialog } from "../form/banner-edit-dialog";
|
||||||
import { Eye, CheckCheck } from "lucide-react";
|
import { Eye, CheckCheck, X } from "lucide-react";
|
||||||
import AgentDetailDialog from "../dialog/agent-dialog";
|
import AgentDetailDialog from "../dialog/agent-dialog";
|
||||||
import { deleteAgent, getAgentData, approveAgent } from "@/service/agent";
|
import { deleteAgent, getAgentData, approveAgent, rejectAgent } from "@/service/agent";
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: "No", uid: "no" },
|
{ name: "No", uid: "no" },
|
||||||
|
|
@ -94,12 +94,12 @@ export default function AgentTable() {
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
});
|
});
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userRoleId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // userRoleId dari cookies
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -202,6 +202,40 @@ export default function AgentTable() {
|
||||||
initState(); // refresh table
|
initState(); // refresh table
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRejectAgent = async (id: number) => {
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
const { value: message } = await MySwal.fire({
|
||||||
|
title: "Tolak Agent",
|
||||||
|
input: "textarea",
|
||||||
|
inputLabel: "Alasan penolakan (opsional)",
|
||||||
|
inputPlaceholder: "Masukkan alasan penolakan...",
|
||||||
|
inputAttributes: {
|
||||||
|
"aria-label": "Masukkan alasan penolakan",
|
||||||
|
},
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Tolak",
|
||||||
|
cancelButtonText: "Batal",
|
||||||
|
confirmButtonColor: "#dc2626",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (message === undefined) {
|
||||||
|
return; // User cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
loading();
|
||||||
|
const res = await rejectAgent(id, message || undefined);
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
error(res.message || "Gagal menolak agent");
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
success("Agent berhasil ditolak");
|
||||||
|
initState(); // refresh table
|
||||||
|
};
|
||||||
|
|
||||||
const copyUrlArticle = async (id: number, slug: string) => {
|
const copyUrlArticle = async (id: number, slug: string) => {
|
||||||
const url =
|
const url =
|
||||||
`${window.location.protocol}//${window.location.host}` +
|
`${window.location.protocol}//${window.location.host}` +
|
||||||
|
|
@ -416,6 +450,10 @@ export default function AgentTable() {
|
||||||
<span className="bg-green-100 text-green-700 text-xs px-3 py-1 rounded-full font-medium">
|
<span className="bg-green-100 text-green-700 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
Disetujui
|
Disetujui
|
||||||
</span>
|
</span>
|
||||||
|
) : item.status_id === 3 ? (
|
||||||
|
<span className="bg-red-100 text-red-700 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
|
Ditolak
|
||||||
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="bg-gray-100 text-gray-600 text-xs px-3 py-1 rounded-full font-medium">
|
<span className="bg-gray-100 text-gray-600 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
{item.status_id || "Tidak Diketahui"}
|
{item.status_id || "Tidak Diketahui"}
|
||||||
|
|
@ -458,17 +496,28 @@ export default function AgentTable() {
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Tombol Approve - hanya untuk admin dan status pending */}
|
{/* Tombol Approve & Reject - hanya untuk admin dan status pending */}
|
||||||
{userLevelId === "1" && item.status_id === 1 && (
|
{userRoleId === "1" && item.status_id === 1 && (
|
||||||
<Button
|
<>
|
||||||
variant="ghost"
|
<Button
|
||||||
size="sm"
|
variant="ghost"
|
||||||
onClick={() => handleApproveAgent(item.id)}
|
size="sm"
|
||||||
className="text-green-600 hover:bg-transparent hover:underline p-0"
|
onClick={() => handleApproveAgent(item.id)}
|
||||||
>
|
className="text-green-600 hover:bg-transparent hover:underline p-0"
|
||||||
<CheckCheck className="w-4 h-4 mr-1" />
|
>
|
||||||
Approve
|
<CheckCheck className="w-4 h-4 mr-1" />
|
||||||
</Button>
|
Approve
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleRejectAgent(item.id)}
|
||||||
|
className="text-red-600 hover:bg-transparent hover:underline p-0"
|
||||||
|
>
|
||||||
|
<X className="w-4 h-4 mr-1" />
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{/* Tombol Hapus */}
|
{/* Tombol Hapus */}
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ import {
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import CustomPagination from "../layout/custom-pagination";
|
import CustomPagination from "../layout/custom-pagination";
|
||||||
import { EditBannerDialog } from "../form/banner-edit-dialog";
|
import { EditBannerDialog } from "../form/banner-edit-dialog";
|
||||||
import { deleteBanner, getBannerData, updateBanner, approveBanner } from "@/service/banner";
|
import { deleteBanner, getBannerData, updateBanner, approveBanner, rejectBanner, getApprovalHistory } from "@/service/banner";
|
||||||
import { Check, CheckCheck, Clock, Eye, X } from "lucide-react";
|
import { Check, CheckCheck, Clock, Eye, X } from "lucide-react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
|
@ -91,14 +91,14 @@ export default function ArticleTable() {
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
});
|
});
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userRoleId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // userRoleId dari cookies
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -254,6 +254,39 @@ export default function ArticleTable() {
|
||||||
initState(); // refresh table
|
initState(); // refresh table
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRejectBanner = async (id: number) => {
|
||||||
|
const { value: message } = await MySwal.fire({
|
||||||
|
title: "Tolak Banner",
|
||||||
|
input: "textarea",
|
||||||
|
inputLabel: "Alasan penolakan (opsional)",
|
||||||
|
inputPlaceholder: "Masukkan alasan penolakan...",
|
||||||
|
inputAttributes: {
|
||||||
|
"aria-label": "Masukkan alasan penolakan",
|
||||||
|
},
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Tolak",
|
||||||
|
cancelButtonText: "Batal",
|
||||||
|
confirmButtonColor: "#dc2626",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (message === undefined) {
|
||||||
|
return; // User cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
loading();
|
||||||
|
const res = await rejectBanner(id, message || undefined);
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
error(res.message || "Gagal menolak banner");
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
success("Banner berhasil ditolak");
|
||||||
|
initState(); // refresh table
|
||||||
|
};
|
||||||
|
|
||||||
const handleReject = async () => {
|
const handleReject = async () => {
|
||||||
if (!viewBanner) return;
|
if (!viewBanner) return;
|
||||||
|
|
||||||
|
|
@ -486,6 +519,10 @@ export default function ArticleTable() {
|
||||||
<span className="bg-green-100 text-green-700 text-xs px-3 py-1 rounded-full font-medium">
|
<span className="bg-green-100 text-green-700 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
Disetujui
|
Disetujui
|
||||||
</span>
|
</span>
|
||||||
|
) : item.status_id === 3 ? (
|
||||||
|
<span className="bg-red-100 text-red-700 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
|
Ditolak
|
||||||
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="bg-gray-100 text-gray-600 text-xs px-3 py-1 rounded-full font-medium">
|
<span className="bg-gray-100 text-gray-600 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
{item.status_id || "Tidak Diketahui"}
|
{item.status_id || "Tidak Diketahui"}
|
||||||
|
|
@ -505,7 +542,7 @@ export default function ArticleTable() {
|
||||||
<Eye className="w-4 h-4 mr-1" />
|
<Eye className="w-4 h-4 mr-1" />
|
||||||
Lihat
|
Lihat
|
||||||
</Button>
|
</Button>
|
||||||
{userLevelId !== "3" && (
|
{userRoleId !== "3" && (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -516,16 +553,27 @@ export default function ArticleTable() {
|
||||||
Edit
|
Edit
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{userLevelId === "1" && item.status_id === 1 && (
|
{userRoleId === "1" && item.status_id === 1 && (
|
||||||
<Button
|
<>
|
||||||
variant="ghost"
|
<Button
|
||||||
size="sm"
|
variant="ghost"
|
||||||
className="text-green-600 hover:bg-transparent hover:underline p-0"
|
size="sm"
|
||||||
onClick={() => handleApproveBanner(item.id)}
|
className="text-green-600 hover:bg-transparent hover:underline p-0"
|
||||||
>
|
onClick={() => handleApproveBanner(item.id)}
|
||||||
<CheckCheck className="w-4 h-4 mr-1" />
|
>
|
||||||
Approve
|
<CheckCheck className="w-4 h-4 mr-1" />
|
||||||
</Button>
|
Approve
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="text-red-600 hover:bg-transparent hover:underline p-0"
|
||||||
|
onClick={() => handleRejectBanner(item.id)}
|
||||||
|
>
|
||||||
|
<X className="w-4 h-4 mr-1" />
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|
@ -801,7 +849,7 @@ export default function ArticleTable() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* FOOTER */}
|
{/* FOOTER */}
|
||||||
{userLevelId !== "2" && (
|
{userRoleId !== "2" && (
|
||||||
<div className="flex justify-between items-center gap-3 px-6 py-4 border-t bg-[#F2F7FA]">
|
<div className="flex justify-between items-center gap-3 px-6 py-4 border-t bg-[#F2F7FA]">
|
||||||
{viewBanner.status === "1" ? (
|
{viewBanner.status === "1" ? (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { Eye, Pencil, Trash2, Calendar, MapPin, CheckCheck } from "lucide-react";
|
import { Eye, Pencil, Trash2, Calendar, MapPin, CheckCheck, X } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
deleteGalery,
|
deleteGalery,
|
||||||
getGaleryById,
|
getGaleryById,
|
||||||
getGaleryData,
|
getGaleryData,
|
||||||
getGaleryFileData,
|
getGaleryFileData,
|
||||||
approveGalery,
|
approveGalery,
|
||||||
|
rejectGalery,
|
||||||
} from "@/service/galery";
|
} from "@/service/galery";
|
||||||
import { DialogDetailGaleri } from "../dialog/galery-detail-dialog";
|
import { DialogDetailGaleri } from "../dialog/galery-detail-dialog";
|
||||||
import { DialogUpdateGaleri } from "../dialog/galery-update-dialog";
|
import { DialogUpdateGaleri } from "../dialog/galery-update-dialog";
|
||||||
|
|
@ -20,7 +21,7 @@ import Cookies from "js-cookie";
|
||||||
export default function Galery() {
|
export default function Galery() {
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
const [data, setData] = useState<any[]>([]);
|
const [data, setData] = useState<any[]>([]);
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [showData, setShowData] = useState("10");
|
const [showData, setShowData] = useState("10");
|
||||||
|
|
@ -73,10 +74,10 @@ export default function Galery() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userRoleId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // userRoleId dari cookies
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -144,6 +145,39 @@ export default function Galery() {
|
||||||
fetchData(); // refresh table
|
fetchData(); // refresh table
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRejectGalery = async (id: number) => {
|
||||||
|
const { value: message } = await MySwal.fire({
|
||||||
|
title: "Tolak Galery",
|
||||||
|
input: "textarea",
|
||||||
|
inputLabel: "Alasan penolakan (opsional)",
|
||||||
|
inputPlaceholder: "Masukkan alasan penolakan...",
|
||||||
|
inputAttributes: {
|
||||||
|
"aria-label": "Masukkan alasan penolakan",
|
||||||
|
},
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Tolak",
|
||||||
|
cancelButtonText: "Batal",
|
||||||
|
confirmButtonColor: "#dc2626",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (message === undefined) {
|
||||||
|
return; // User cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
loading();
|
||||||
|
const res = await rejectGalery(id, message || undefined);
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
error(res.message || "Gagal menolak galery");
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
success("Galery berhasil ditolak");
|
||||||
|
fetchData(); // refresh table
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
||||||
|
|
@ -170,11 +204,13 @@ export default function Galery() {
|
||||||
{/* Status Badge */}
|
{/* Status Badge */}
|
||||||
<span
|
<span
|
||||||
className={`absolute top-3 left-3 text-xs px-3 py-1 rounded-full font-medium
|
className={`absolute top-3 left-3 text-xs px-3 py-1 rounded-full font-medium
|
||||||
${
|
$ {
|
||||||
item.status_id === 2
|
item.status_id === 2
|
||||||
? "bg-green-100 text-green-700"
|
? "bg-green-100 text-green-700"
|
||||||
: item.status_id === 1
|
: item.status_id === 1
|
||||||
? "bg-yellow-100 text-yellow-700"
|
? "bg-yellow-100 text-yellow-700"
|
||||||
|
: item.status_id === 3
|
||||||
|
? "bg-red-100 text-red-700"
|
||||||
: "bg-gray-100 text-gray-600"
|
: "bg-gray-100 text-gray-600"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|
@ -182,6 +218,8 @@ export default function Galery() {
|
||||||
? "Disetujui"
|
? "Disetujui"
|
||||||
: item.status_id === 1
|
: item.status_id === 1
|
||||||
? "Menunggu"
|
? "Menunggu"
|
||||||
|
: item.status_id === 3
|
||||||
|
? "Ditolak"
|
||||||
: "Tidak Diketahui"}
|
: "Tidak Diketahui"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -219,14 +257,22 @@ export default function Galery() {
|
||||||
<Pencil className="h-4 w-4" /> Edit
|
<Pencil className="h-4 w-4" /> Edit
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Tombol Approve - hanya untuk admin dan status pending */}
|
{/* Tombol Approve & Reject - hanya untuk admin dan status pending */}
|
||||||
{userLevelId === "1" && item.status_id === 1 && (
|
{userRoleId === "1" && item.status_id === 1 && (
|
||||||
<button
|
<>
|
||||||
className="flex items-center gap-1 text-green-600 hover:text-green-700 transition"
|
<button
|
||||||
onClick={() => handleApproveGalery(item.id)}
|
className="flex items-center gap-1 text-green-600 hover:text-green-700 transition"
|
||||||
>
|
onClick={() => handleApproveGalery(item.id)}
|
||||||
<CheckCheck className="h-4 w-4" /> Approve
|
>
|
||||||
</button>
|
<CheckCheck className="h-4 w-4" /> Approve
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="flex items-center gap-1 text-red-600 hover:text-red-700 transition"
|
||||||
|
onClick={() => handleRejectGalery(item.id)}
|
||||||
|
>
|
||||||
|
<X className="h-4 w-4" /> Reject
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ import {
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import CustomPagination from "../layout/custom-pagination";
|
import CustomPagination from "../layout/custom-pagination";
|
||||||
import { EditBannerDialog } from "../form/banner-edit-dialog";
|
import { EditBannerDialog } from "../form/banner-edit-dialog";
|
||||||
import { deleteProduct, getProductPagination, approveProduct } from "@/service/product";
|
import { deleteProduct, getProductPagination, approveProduct, rejectProduct } from "@/service/product";
|
||||||
import { CheckCheck, Eye } from "lucide-react";
|
import { CheckCheck, Eye, X } from "lucide-react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
|
|
@ -92,14 +92,14 @@ export default function ProductTable() {
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
});
|
});
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userRoleId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // userRoleId dari cookies
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -209,6 +209,40 @@ export default function ProductTable() {
|
||||||
initState(); // refresh table
|
initState(); // refresh table
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRejectProduct = async (id: number) => {
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
const { value: message } = await MySwal.fire({
|
||||||
|
title: "Tolak Product",
|
||||||
|
input: "textarea",
|
||||||
|
inputLabel: "Alasan penolakan (opsional)",
|
||||||
|
inputPlaceholder: "Masukkan alasan penolakan...",
|
||||||
|
inputAttributes: {
|
||||||
|
"aria-label": "Masukkan alasan penolakan",
|
||||||
|
},
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Tolak",
|
||||||
|
cancelButtonText: "Batal",
|
||||||
|
confirmButtonColor: "#dc2626",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (message === undefined) {
|
||||||
|
return; // User cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
loading();
|
||||||
|
const res = await rejectProduct(id, message || undefined);
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
error(res.message || "Gagal menolak product");
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
success("Product berhasil ditolak");
|
||||||
|
initState(); // refresh table
|
||||||
|
};
|
||||||
|
|
||||||
const copyUrlArticle = async (id: number, slug: string) => {
|
const copyUrlArticle = async (id: number, slug: string) => {
|
||||||
const url =
|
const url =
|
||||||
`${window.location.protocol}//${window.location.host}` +
|
`${window.location.protocol}//${window.location.host}` +
|
||||||
|
|
@ -448,6 +482,10 @@ export default function ProductTable() {
|
||||||
<span className="bg-green-100 text-green-700 text-xs px-3 py-1 rounded-full font-medium">
|
<span className="bg-green-100 text-green-700 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
Disetujui
|
Disetujui
|
||||||
</span>
|
</span>
|
||||||
|
) : item.status_id === 3 ? (
|
||||||
|
<span className="bg-red-100 text-red-700 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
|
Ditolak
|
||||||
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="bg-gray-100 text-gray-600 text-xs px-3 py-1 rounded-full font-medium">
|
<span className="bg-gray-100 text-gray-600 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
{item.status_id || "Tidak Diketahui"}
|
{item.status_id || "Tidak Diketahui"}
|
||||||
|
|
@ -468,7 +506,7 @@ export default function ProductTable() {
|
||||||
Lihat
|
Lihat
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
{userLevelId !== "3" && (
|
{userRoleId !== "3" && (
|
||||||
<Link href={"/admin/product/update"}>
|
<Link href={"/admin/product/update"}>
|
||||||
<Button
|
<Button
|
||||||
className="text-[#0F6C75] hover:bg-transparent hover:underline p-0"
|
className="text-[#0F6C75] hover:bg-transparent hover:underline p-0"
|
||||||
|
|
@ -479,16 +517,27 @@ export default function ProductTable() {
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{userLevelId === "1" && item.status_id === 1 && (
|
{userRoleId === "1" && item.status_id === 1 && (
|
||||||
<Button
|
<>
|
||||||
variant="ghost"
|
<Button
|
||||||
size="sm"
|
variant="ghost"
|
||||||
onClick={() => handleApproveProduct(item.id)}
|
size="sm"
|
||||||
className="text-green-600 hover:bg-transparent hover:underline p-0"
|
onClick={() => handleApproveProduct(item.id)}
|
||||||
>
|
className="text-green-600 hover:bg-transparent hover:underline p-0"
|
||||||
<CheckCheck className="w-4 h-4 mr-1" />
|
>
|
||||||
Approve
|
<CheckCheck className="w-4 h-4 mr-1" />
|
||||||
</Button>
|
Approve
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleRejectProduct(item.id)}
|
||||||
|
className="text-red-600 hover:bg-transparent hover:underline p-0"
|
||||||
|
>
|
||||||
|
<X className="w-4 h-4 mr-1" />
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,10 @@ import {
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import CustomPagination from "../layout/custom-pagination";
|
import CustomPagination from "../layout/custom-pagination";
|
||||||
import { EditBannerDialog } from "../form/banner-edit-dialog";
|
import { EditBannerDialog } from "../form/banner-edit-dialog";
|
||||||
import { Eye, Trash2, CheckCheck } from "lucide-react";
|
import { Eye, Trash2, CheckCheck, X } from "lucide-react";
|
||||||
import AgentDetailDialog from "../dialog/agent-dialog";
|
import AgentDetailDialog from "../dialog/agent-dialog";
|
||||||
import PromoDetailDialog from "../dialog/promo-dialog";
|
import PromoDetailDialog from "../dialog/promo-dialog";
|
||||||
import { deletePromotion, getPromotionPagination, approvePromotion } from "@/service/promotion";
|
import { deletePromotion, getPromotionPagination, approvePromotion, rejectPromotion } from "@/service/promotion";
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: "No", uid: "no" },
|
{ name: "No", uid: "no" },
|
||||||
|
|
@ -96,12 +96,12 @@ export default function PromotionTable() {
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
});
|
});
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userRoleId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // userRoleId dari cookies
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -204,6 +204,40 @@ export default function PromotionTable() {
|
||||||
initState(); // refresh table
|
initState(); // refresh table
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRejectPromotion = async (id: number) => {
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
const { value: message } = await MySwal.fire({
|
||||||
|
title: "Tolak Promotion",
|
||||||
|
input: "textarea",
|
||||||
|
inputLabel: "Alasan penolakan (opsional)",
|
||||||
|
inputPlaceholder: "Masukkan alasan penolakan...",
|
||||||
|
inputAttributes: {
|
||||||
|
"aria-label": "Masukkan alasan penolakan",
|
||||||
|
},
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Tolak",
|
||||||
|
cancelButtonText: "Batal",
|
||||||
|
confirmButtonColor: "#dc2626",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (message === undefined) {
|
||||||
|
return; // User cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
loading();
|
||||||
|
const res = await rejectPromotion(id, message || undefined);
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
error(res.message || "Gagal menolak promotion");
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
success("Promotion berhasil ditolak");
|
||||||
|
initState(); // refresh table
|
||||||
|
};
|
||||||
|
|
||||||
const copyUrlArticle = async (id: number, slug: string) => {
|
const copyUrlArticle = async (id: number, slug: string) => {
|
||||||
const url =
|
const url =
|
||||||
`${window.location.protocol}//${window.location.host}` +
|
`${window.location.protocol}//${window.location.host}` +
|
||||||
|
|
@ -408,6 +442,10 @@ export default function PromotionTable() {
|
||||||
<span className="bg-green-100 text-green-700 text-xs px-3 py-1 rounded-full font-medium">
|
<span className="bg-green-100 text-green-700 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
Disetujui
|
Disetujui
|
||||||
</span>
|
</span>
|
||||||
|
) : item.status_id === 3 ? (
|
||||||
|
<span className="bg-red-100 text-red-700 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
|
Ditolak
|
||||||
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="bg-gray-100 text-gray-600 text-xs px-3 py-1 rounded-full font-medium">
|
<span className="bg-gray-100 text-gray-600 text-xs px-3 py-1 rounded-full font-medium">
|
||||||
{item.status_id || "Tidak Diketahui"}
|
{item.status_id || "Tidak Diketahui"}
|
||||||
|
|
@ -432,17 +470,28 @@ export default function PromotionTable() {
|
||||||
</Button>
|
</Button>
|
||||||
{/* Tombol Edit */}
|
{/* Tombol Edit */}
|
||||||
|
|
||||||
{/* Tombol Approve - hanya untuk admin dan status pending */}
|
{/* Tombol Approve & Reject - hanya untuk admin dan status pending */}
|
||||||
{userLevelId === "1" && item.status_id === 1 && (
|
{userRoleId === "1" && item.status_id === 1 && (
|
||||||
<Button
|
<>
|
||||||
variant="ghost"
|
<Button
|
||||||
size="sm"
|
variant="ghost"
|
||||||
onClick={() => handleApprovePromotion(item.id)}
|
size="sm"
|
||||||
className="text-green-600 hover:bg-transparent hover:underline p-0"
|
onClick={() => handleApprovePromotion(item.id)}
|
||||||
>
|
className="text-green-600 hover:bg-transparent hover:underline p-0"
|
||||||
<CheckCheck className="w-4 h-4 mr-1" />
|
>
|
||||||
Approve
|
<CheckCheck className="w-4 h-4 mr-1" />
|
||||||
</Button>
|
Approve
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleRejectPromotion(item.id)}
|
||||||
|
className="text-red-600 hover:bg-transparent hover:underline p-0"
|
||||||
|
>
|
||||||
|
<X className="w-4 h-4 mr-1" />
|
||||||
|
Reject
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{/* Tombol Hapus */}
|
{/* Tombol Hapus */}
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -45,4 +45,18 @@ export async function approveAgent(id: string | number) {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
return await httpPutInterceptor(`/sales-agents/${id}/approve`, {}, headers);
|
return await httpPutInterceptor(`/sales-agents/${id}/approve`, {}, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function rejectAgent(id: string | number, message?: string) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpPutInterceptor(`/sales-agents/${id}/reject`, { message }, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getApprovalHistory(moduleType: string, moduleId: string | number) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpGetInterceptor(`/approval-histories/${moduleType}/${moduleId}`, headers);
|
||||||
}
|
}
|
||||||
|
|
@ -55,4 +55,18 @@ export async function approveBanner(id: string | number) {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
return await httpPutInterceptor(`/banners/${id}/approve`, {}, headers);
|
return await httpPutInterceptor(`/banners/${id}/approve`, {}, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function rejectBanner(id: string | number, message?: string) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpPutInterceptor(`/banners/${id}/reject`, { message }, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getApprovalHistory(moduleType: string, moduleId: string | number) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpGetInterceptor(`/approval-histories/${moduleType}/${moduleId}`, headers);
|
||||||
}
|
}
|
||||||
|
|
@ -76,4 +76,18 @@ export async function approveGalery(id: string | number) {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
return await httpPutInterceptor(`/galleries/${id}/approve`, {}, headers);
|
return await httpPutInterceptor(`/galleries/${id}/approve`, {}, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function rejectGalery(id: string | number, message?: string) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpPutInterceptor(`/galleries/${id}/reject`, { message }, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getApprovalHistory(moduleType: string, moduleId: string | number) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpGetInterceptor(`/approval-histories/${moduleType}/${moduleId}`, headers);
|
||||||
}
|
}
|
||||||
|
|
@ -48,4 +48,18 @@ export async function approveProduct(id: string | number) {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
return await httpPutInterceptor(`/products/${id}/approve`, {}, headers);
|
return await httpPutInterceptor(`/products/${id}/approve`, {}, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function rejectProduct(id: string | number, message?: string) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpPutInterceptor(`/products/${id}/reject`, { message }, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getApprovalHistory(moduleType: string, moduleId: string | number) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpGetInterceptor(`/approval-histories/${moduleType}/${moduleId}`, headers);
|
||||||
}
|
}
|
||||||
|
|
@ -43,4 +43,18 @@ export async function approvePromotion(id: string | number) {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
return await httpPutInterceptor(`/promotions/${id}/approve`, {}, headers);
|
return await httpPutInterceptor(`/promotions/${id}/approve`, {}, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function rejectPromotion(id: string | number, message?: string) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpPutInterceptor(`/promotions/${id}/reject`, { message }, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getApprovalHistory(moduleType: string, moduleId: string | number) {
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
};
|
||||||
|
return await httpGetInterceptor(`/approval-histories/${moduleType}/${moduleId}`, headers);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue