fix: table agent,banner,product,promo,galery, form and dialog
This commit is contained in:
commit
f516565446
|
|
@ -16,15 +16,15 @@ import { useRouter } from "next/navigation";
|
||||||
export default function AgentPage() {
|
export default function AgentPage() {
|
||||||
const [openDialog, setOpenDialog] = useState(false);
|
const [openDialog, setOpenDialog] = useState(false);
|
||||||
|
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userlevelId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // contoh: "3"
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSubmitBanner = (data: any) => {
|
const handleSubmitBanner = (data: any) => {
|
||||||
|
|
@ -41,7 +41,7 @@ export default function AgentPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
||||||
{userLevelId !== "1" && (
|
{userRoleId !== "1" && (
|
||||||
<Link href={"/admin/agent/create"}>
|
<Link href={"/admin/agent/create"}>
|
||||||
<Button className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2">
|
<Button className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2">
|
||||||
<Plus className="h-4 w-4" />
|
<Plus className="h-4 w-4" />
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,15 @@ import Cookies from "js-cookie";
|
||||||
export default function BasicPage() {
|
export default function BasicPage() {
|
||||||
const [openDialog, setOpenDialog] = useState(false);
|
const [openDialog, setOpenDialog] = useState(false);
|
||||||
const [refreshKey, setRefreshKey] = useState(0);
|
const [refreshKey, setRefreshKey] = useState(0);
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userlevelId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const ulne = Cookies.get("urie"); // contoh: "3"
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(ulne ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSubmitBanner = async (formData: FormData) => {
|
const handleSubmitBanner = async (formData: FormData) => {
|
||||||
|
|
@ -58,7 +58,7 @@ export default function BasicPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
||||||
{userLevelId !== "1" && (
|
{userRoleId !== "1" && (
|
||||||
<Button
|
<Button
|
||||||
className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2"
|
className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2"
|
||||||
onClick={() => setOpenDialog(true)}
|
onClick={() => setOpenDialog(true)}
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,15 @@ import Cookies from "js-cookie";
|
||||||
|
|
||||||
export default function GaleryPage() {
|
export default function GaleryPage() {
|
||||||
const [openDialog, setOpenDialog] = useState(false);
|
const [openDialog, setOpenDialog] = useState(false);
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userlevelId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // contoh: "3"
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSubmitGaleri = () => {
|
const handleSubmitGaleri = () => {
|
||||||
|
|
@ -39,7 +39,7 @@ export default function GaleryPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
||||||
{userLevelId !== "1" && (
|
{userRoleId !== "1" && (
|
||||||
<Button
|
<Button
|
||||||
className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2"
|
className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2"
|
||||||
onClick={() => setOpenDialog(true)}
|
onClick={() => setOpenDialog(true)}
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,15 @@ import Cookies from "js-cookie";
|
||||||
|
|
||||||
export default function ProductPage() {
|
export default function ProductPage() {
|
||||||
const [openDialog, setOpenDialog] = useState(false);
|
const [openDialog, setOpenDialog] = useState(false);
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userlevelId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // contoh: "3"
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSubmitBanner = (data: any) => {
|
const handleSubmitBanner = (data: any) => {
|
||||||
|
|
@ -40,7 +40,7 @@ export default function ProductPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
||||||
{userLevelId !== "1" && (
|
{userRoleId !== "1" && (
|
||||||
<Link href={"/admin/product/create"}>
|
<Link href={"/admin/product/create"}>
|
||||||
<Button className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2">
|
<Button className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2">
|
||||||
<Plus className="h-4 w-4" />
|
<Plus className="h-4 w-4" />
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,15 @@ import Cookies from "js-cookie";
|
||||||
export default function PromotionPage() {
|
export default function PromotionPage() {
|
||||||
const [openDialog, setOpenDialog] = useState(false);
|
const [openDialog, setOpenDialog] = useState(false);
|
||||||
|
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userlevelId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // contoh: "3"
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSubmitBanner = (data: any) => {
|
const handleSubmitBanner = (data: any) => {
|
||||||
|
|
@ -43,7 +43,7 @@ export default function PromotionPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
<div className="dark:bg-[#18181b] rounded-xl p-3">
|
||||||
{userLevelId !== "1" && (
|
{userRoleId !== "1" && (
|
||||||
<Link href={"/admin/promotion/create"}>
|
<Link href={"/admin/promotion/create"}>
|
||||||
<Button className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2">
|
<Button className="bg-[#1F6779] text-white w-full lg:w-fit hover:bg-[#1a9bb5] flex items-center gap-2">
|
||||||
<Plus className="h-4 w-4" />
|
<Plus className="h-4 w-4" />
|
||||||
|
|
|
||||||
|
|
@ -10,24 +10,30 @@ import {
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { Check, CheckCheck, CheckCircle, Clock, X } from "lucide-react";
|
import { Check, CheckCheck, CheckCircle, Clock, X } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { approveGalery, getGaleryFileData } from "@/service/galery";
|
import {
|
||||||
|
approveGalery,
|
||||||
|
getGaleryFileData,
|
||||||
|
rejectGalery,
|
||||||
|
} from "@/service/galery";
|
||||||
import { convertDateFormat } from "@/utils/global";
|
import { convertDateFormat } from "@/utils/global";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import { error, loading, success } from "@/config/swal";
|
import { error, loading, success } from "@/config/swal";
|
||||||
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
export function DialogDetailGaleri({ open, onClose, data }: any) {
|
export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
const [images, setImages] = useState<any[]>([]);
|
const [images, setImages] = useState<any[]>([]);
|
||||||
const [openApproverHistory, setOpenApproverHistory] = useState(false);
|
const [openApproverHistory, setOpenApproverHistory] = useState(false);
|
||||||
const [userLevelId, setUserLevelId] = useState<string | null>(null);
|
const [userRoleId, setUserRoleId] = useState<string | null>(null);
|
||||||
const [openViewDialog, setOpenViewDialog] = useState(false);
|
const [openViewDialog, setOpenViewDialog] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// 🔹 Ambil userlevelId dari cookies
|
// 🔹 Ambil userlevelId dari cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ulne = Cookies.get("ulne"); // contoh: "3"
|
const urie = Cookies.get("urie"); // contoh: "3"
|
||||||
setUserLevelId(ulne ?? null);
|
setUserRoleId(urie ?? null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const [openCommentModal, setOpenCommentModal] = useState(false);
|
const [openCommentModal, setOpenCommentModal] = useState(false);
|
||||||
|
|
@ -84,6 +90,40 @@ export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
fetchImages(); // refresh table
|
fetchImages(); // refresh table
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRejectGalery = async (id: number) => {
|
||||||
|
const MySwal = withReactContent(Swal);
|
||||||
|
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");
|
||||||
|
fetchImages(); // refresh table
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dialog open={open} onOpenChange={onClose}>
|
<Dialog open={open} onOpenChange={onClose}>
|
||||||
|
|
@ -214,7 +254,7 @@ export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{openViewDialog && userLevelId !== "2" && (
|
{userRoleId !== "2" && data && (
|
||||||
<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]">
|
||||||
{data.status_id === 1 ? (
|
{data.status_id === 1 ? (
|
||||||
<>
|
<>
|
||||||
|
|
@ -232,15 +272,15 @@ export function DialogDetailGaleri({ open, onClose, data }: any) {
|
||||||
<Button
|
<Button
|
||||||
className=" w-[180]"
|
className=" w-[180]"
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
// onClick={(e) => {
|
onClick={(e) => {
|
||||||
// e.stopPropagation();
|
e.stopPropagation();
|
||||||
// handleReject();
|
handleRejectGalery(data.id);
|
||||||
// }}
|
}}
|
||||||
>
|
>
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{userLevelId === "1" && (
|
{userRoleId === "1" && (
|
||||||
<Button
|
<Button
|
||||||
// variant="ghost"
|
// variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,18 @@ import {
|
||||||
FileText,
|
FileText,
|
||||||
X,
|
X,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { approvePromotion, getPromotionById } from "@/service/promotion";
|
import {
|
||||||
|
approvePromotion,
|
||||||
|
getPromotionById,
|
||||||
|
rejectPromotion,
|
||||||
|
} from "@/service/promotion";
|
||||||
import { convertDateFormat } from "@/utils/global";
|
import { convertDateFormat } from "@/utils/global";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import { error, loading, success } from "@/config/swal";
|
import { error, loading, success } from "@/config/swal";
|
||||||
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
type PromoDetailDialogProps = {
|
type PromoDetailDialogProps = {
|
||||||
promoId: number | null;
|
promoId: number | null;
|
||||||
|
|
@ -60,6 +66,40 @@ export default function PromoDetailDialog({
|
||||||
setOpenApproverHistory(true);
|
setOpenApproverHistory(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 handleApprovePromotion = async (promoId: number) => {
|
const handleApprovePromotion = async (promoId: number) => {
|
||||||
loading();
|
loading();
|
||||||
const res = await approvePromotion(promoId);
|
const res = await approvePromotion(promoId);
|
||||||
|
|
@ -280,10 +320,10 @@ export default function PromoDetailDialog({
|
||||||
<Button
|
<Button
|
||||||
className=" w-[150]"
|
className=" w-[150]"
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
// onClick={(e) => {
|
onClick={(e) => {
|
||||||
// e.stopPropagation();
|
e.stopPropagation();
|
||||||
// handleReject();
|
handleRejectPromotion(promo.id);
|
||||||
// }}
|
}}
|
||||||
>
|
>
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -319,7 +359,7 @@ export default function PromoDetailDialog({
|
||||||
)}
|
)}
|
||||||
{openApproverHistory && (
|
{openApproverHistory && (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 z-[60] flex items-center justify-center bg-black/50 p-4"
|
className=" flex items-center justify-center bg-black/50 p-4"
|
||||||
onClick={() => setOpenApproverHistory(false)}
|
onClick={() => setOpenApproverHistory(false)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,16 @@ import dynamic from "next/dynamic";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import { getProductDataById } from "@/service/product";
|
import { getProductDataById } from "@/service/product";
|
||||||
import { approveAgent, getAgentById, updateAgent } from "@/service/agent";
|
import {
|
||||||
|
approveAgent,
|
||||||
|
getAgentById,
|
||||||
|
rejectAgent,
|
||||||
|
updateAgent,
|
||||||
|
} from "@/service/agent";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { convertDateFormat } from "@/utils/global";
|
import { convertDateFormat } from "@/utils/global";
|
||||||
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
const ViewEditor = dynamic(
|
const ViewEditor = dynamic(
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -128,25 +135,39 @@ export default function DetailAgentForm(props: { isDetail: boolean }) {
|
||||||
setOpenApproverHistory(true);
|
setOpenApproverHistory(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
// const handleRejectProduct = async (id: number) => {
|
const handleRejectAgent = async (id: number) => {
|
||||||
// loading();
|
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",
|
||||||
|
});
|
||||||
|
|
||||||
// const payload = {
|
if (message === undefined) {
|
||||||
// status_id: 3, // ✅ number
|
return; // User cancelled
|
||||||
// };
|
}
|
||||||
|
|
||||||
// const res = await updateAgent(payload, id);
|
loading();
|
||||||
|
const res = await rejectAgent(id, message || undefined);
|
||||||
|
|
||||||
// if (res?.error) {
|
if (res?.error) {
|
||||||
// error(res.message || "Gagal menolak product");
|
error(res.message || "Gagal menolak agent");
|
||||||
// close();
|
close();
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// close();
|
close();
|
||||||
// success("Product berhasil ditolak");
|
success("Agent berhasil ditolak");
|
||||||
// fetchData();
|
fetchData(); // refresh table
|
||||||
// };
|
};
|
||||||
|
|
||||||
const handleApproveAgent = async (id: number) => {
|
const handleApproveAgent = async (id: number) => {
|
||||||
loading();
|
loading();
|
||||||
|
|
@ -298,7 +319,7 @@ export default function DetailAgentForm(props: { isDetail: boolean }) {
|
||||||
<Button
|
<Button
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
className="w-[180px]"
|
className="w-[180px]"
|
||||||
// onClick={() => handleRejectProduct(detailData.id)}
|
onClick={() => handleRejectAgent(data.id)}
|
||||||
>
|
>
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,12 @@ import Cookies from "js-cookie";
|
||||||
import {
|
import {
|
||||||
approveProduct,
|
approveProduct,
|
||||||
getProductDataById,
|
getProductDataById,
|
||||||
|
rejectProduct,
|
||||||
updateProduct,
|
updateProduct,
|
||||||
} from "@/service/product";
|
} from "@/service/product";
|
||||||
import { convertDateFormat } from "@/utils/global";
|
import { convertDateFormat } from "@/utils/global";
|
||||||
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
const ViewEditor = dynamic(
|
const ViewEditor = dynamic(
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -302,13 +305,27 @@ export default function DetailProductForm(props: { isDetail: boolean }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRejectProduct = async (id: number) => {
|
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();
|
loading();
|
||||||
|
const res = await rejectProduct(id, message || undefined);
|
||||||
const payload = {
|
|
||||||
status_id: 3, // ✅ number
|
|
||||||
};
|
|
||||||
|
|
||||||
const res = await updateProduct(payload, id);
|
|
||||||
|
|
||||||
if (res?.error) {
|
if (res?.error) {
|
||||||
error(res.message || "Gagal menolak product");
|
error(res.message || "Gagal menolak product");
|
||||||
|
|
@ -318,7 +335,7 @@ export default function DetailProductForm(props: { isDetail: boolean }) {
|
||||||
|
|
||||||
close();
|
close();
|
||||||
success("Product berhasil ditolak");
|
success("Product berhasil ditolak");
|
||||||
initState();
|
initState(); // refresh table
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleApproveProduct = async (id: number) => {
|
const handleApproveProduct = async (id: number) => {
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,15 @@ import Image from "next/image";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import DashboardContainer from "../main/dashboard/dashboard-container";
|
import DashboardContainer from "../main/dashboard/dashboard-container";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname, useRouter } from "next/navigation";
|
||||||
|
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import { useTheme } from "../layout/theme-context";
|
import { useTheme } from "../layout/theme-context";
|
||||||
import Option from "./option";
|
import Option from "./option";
|
||||||
import { LogOut } from "lucide-react";
|
import { LogOut } from "lucide-react";
|
||||||
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
|
||||||
interface RetractingSidebarProps {
|
interface RetractingSidebarProps {
|
||||||
sidebarData: boolean;
|
sidebarData: boolean;
|
||||||
|
|
@ -87,6 +90,7 @@ const sidebarSections = [
|
||||||
),
|
),
|
||||||
link: "/admin/costumer-service",
|
link: "/admin/costumer-service",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: "Manajemen User",
|
title: "Manajemen User",
|
||||||
icon: () => <Icon icon="mdi:contact" width="18" height="18" />,
|
icon: () => <Icon icon="mdi:contact" width="18" height="18" />,
|
||||||
|
|
@ -206,6 +210,18 @@ const SidebarContent = ({
|
||||||
pathname: string;
|
pathname: string;
|
||||||
updateSidebarData: (newData: boolean) => void;
|
updateSidebarData: (newData: boolean) => void;
|
||||||
}) => {
|
}) => {
|
||||||
|
const roleLabel: Record<number, string> = {
|
||||||
|
1: "Admin",
|
||||||
|
2: "Operator",
|
||||||
|
};
|
||||||
|
|
||||||
|
const [userRoleId, setUserRoleId] = useState<number | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const urie = Cookies.get("urie");
|
||||||
|
setUserRoleId(urie ? Number(urie) : null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const { theme, toggleTheme } = useTheme();
|
const { theme, toggleTheme } = useTheme();
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
|
|
@ -228,7 +244,10 @@ const SidebarContent = ({
|
||||||
className="flex flex-row"
|
className="flex flex-row"
|
||||||
>
|
>
|
||||||
<p className="text-lg font-bold bg-gradient-to-r from-slate-800 to-slate-600 bg-clip-text text-white dark:text-white">
|
<p className="text-lg font-bold bg-gradient-to-r from-slate-800 to-slate-600 bg-clip-text text-white dark:text-white">
|
||||||
JAECOO <span className="text-lg font-normal">Admin</span>
|
JAECOO{" "}
|
||||||
|
<span className="text-lg font-normal">
|
||||||
|
{userRoleId != null ? roleLabel[userRoleId] : ""}
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
{/* <span className="text-xs text-slate-500">Admin Panel</span> */}
|
{/* <span className="text-xs text-slate-500">Admin Panel</span> */}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
@ -540,7 +559,7 @@ const Sidebar = () => {
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
<div className="flex flex-col gap-0.5 text-xs">
|
<div className="flex flex-col gap-0.5 text-xs">
|
||||||
<p>admin-mabes</p>
|
{/* <p>admin-mabes</p> */}
|
||||||
<p className="underline">Logout</p>
|
<p className="underline">Logout</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,14 @@ 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 +99,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 +207,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}` +
|
||||||
|
|
@ -452,7 +491,7 @@ export default function AgentTable() {
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
{/* Tombol Edit */}
|
{/* Tombol Edit */}
|
||||||
{userLevelId !== "1" && (
|
{userRoleId !== "1" && (
|
||||||
<Link href={`/admin/agent/update/${item.id}`}>
|
<Link href={`/admin/agent/update/${item.id}`}>
|
||||||
<Button
|
<Button
|
||||||
className="text-[#0F6C75] hover:bg-transparent hover:underline p-0"
|
className="text-[#0F6C75] hover:bg-transparent hover:underline p-0"
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,12 @@ import {
|
||||||
getBannerData,
|
getBannerData,
|
||||||
updateBanner,
|
updateBanner,
|
||||||
approveBanner,
|
approveBanner,
|
||||||
|
rejectBanner,
|
||||||
|
getApprovalHistory,
|
||||||
} from "@/service/banner";
|
} 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";
|
||||||
|
import page from "@/app/page";
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: "No", uid: "no" },
|
{ name: "No", uid: "no" },
|
||||||
|
|
@ -96,14 +99,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(() => {
|
||||||
|
|
@ -259,6 +262,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;
|
||||||
|
|
||||||
|
|
@ -514,7 +550,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 !== "1" && (
|
{userRoleId !== "1" && (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -525,7 +561,8 @@ export default function ArticleTable() {
|
||||||
Edit
|
Edit
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{/* {userLevelId === "1" && item.status_id === 1 && (
|
{/* {userRoleId === "1" && item.status_id === 1 && (
|
||||||
|
<>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -535,6 +572,16 @@ export default function ArticleTable() {
|
||||||
<CheckCheck className="w-4 h-4 mr-1" />
|
<CheckCheck className="w-4 h-4 mr-1" />
|
||||||
Approve
|
Approve
|
||||||
</Button>
|
</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"
|
||||||
|
|
@ -810,7 +857,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_id === 1 ? (
|
{viewBanner.status_id === 1 ? (
|
||||||
<>
|
<>
|
||||||
|
|
@ -830,13 +877,13 @@ export default function ArticleTable() {
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handleReject();
|
handleRejectBanner(viewBanner.id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Reject
|
Reject
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{userLevelId === "1" && (
|
{userRoleId === "1" && (
|
||||||
<Button
|
<Button
|
||||||
// variant="ghost"
|
// variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
Calendar,
|
Calendar,
|
||||||
MapPin,
|
MapPin,
|
||||||
CheckCheck,
|
CheckCheck,
|
||||||
|
X,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import {
|
import {
|
||||||
deleteGalery,
|
deleteGalery,
|
||||||
|
|
@ -16,6 +17,7 @@ import {
|
||||||
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";
|
||||||
|
|
@ -23,11 +25,12 @@ import { error, success, loading, close } from "@/config/swal";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
|
import { Badge } from "../ui/badge";
|
||||||
|
|
||||||
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");
|
||||||
|
|
@ -80,10 +83,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(() => {
|
||||||
|
|
@ -151,6 +154,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">
|
||||||
|
|
@ -175,13 +211,14 @@ export default function Galery() {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Status Badge */}
|
{/* Status Badge */}
|
||||||
<span
|
<Badge
|
||||||
className={`absolute top-3 left-3 text-xs px-3 py-1 rounded-full font-medium
|
className={`absolute top-3 left-3 px-3 py-1 text-xs 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"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|
@ -189,8 +226,8 @@ export default function Galery() {
|
||||||
? "Disetujui"
|
? "Disetujui"
|
||||||
: item.status_id === 1
|
: item.status_id === 1
|
||||||
? "Menunggu"
|
? "Menunggu"
|
||||||
: "Tidak Diketahui"}
|
: "Ditolak"}
|
||||||
</span>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
|
|
@ -218,7 +255,7 @@ export default function Galery() {
|
||||||
>
|
>
|
||||||
<Eye className="h-4 w-4" /> Lihat
|
<Eye className="h-4 w-4" /> Lihat
|
||||||
</button>
|
</button>
|
||||||
{userLevelId !== "1" && (
|
{userRoleId !== "1" && (
|
||||||
<button
|
<button
|
||||||
onClick={() => openEdit(item.id)}
|
onClick={() => openEdit(item.id)}
|
||||||
className="flex items-center gap-1 text-gray-700 hover:text-[#1F6779] transition"
|
className="flex items-center gap-1 text-gray-700 hover:text-[#1F6779] transition"
|
||||||
|
|
@ -226,14 +263,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
|
<button
|
||||||
className="flex items-center gap-1 text-green-600 hover:text-green-700 transition"
|
className="flex items-center gap-1 text-green-600 hover:text-green-700 transition"
|
||||||
onClick={() => handleApproveGalery(item.id)}
|
onClick={() => handleApproveGalery(item.id)}
|
||||||
>
|
>
|
||||||
<CheckCheck className="h-4 w-4" /> Approve
|
<CheckCheck className="h-4 w-4" /> Approve
|
||||||
</button>
|
</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
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,9 @@ import {
|
||||||
deleteProduct,
|
deleteProduct,
|
||||||
getProductPagination,
|
getProductPagination,
|
||||||
approveProduct,
|
approveProduct,
|
||||||
|
rejectProduct,
|
||||||
} from "@/service/product";
|
} 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 = [
|
||||||
|
|
@ -96,14 +97,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(() => {
|
||||||
|
|
@ -213,6 +214,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}` +
|
||||||
|
|
@ -476,7 +511,7 @@ export default function ProductTable() {
|
||||||
Lihat
|
Lihat
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
{userLevelId !== "1" && (
|
{userRoleId !== "1" && (
|
||||||
<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"
|
||||||
|
|
@ -487,7 +522,8 @@ export default function ProductTable() {
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{/* {userLevelId === "1" && item.status_id === 1 && (
|
{userRoleId === "1" && item.status_id === 1 && (
|
||||||
|
<>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -497,7 +533,17 @@ export default function ProductTable() {
|
||||||
<CheckCheck className="w-4 h-4 mr-1" />
|
<CheckCheck className="w-4 h-4 mr-1" />
|
||||||
Approve
|
Approve
|
||||||
</Button>
|
</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"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
|
||||||
|
|
@ -47,13 +47,14 @@ 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 {
|
import {
|
||||||
deletePromotion,
|
deletePromotion,
|
||||||
getPromotionPagination,
|
getPromotionPagination,
|
||||||
approvePromotion,
|
approvePromotion,
|
||||||
|
rejectPromotion,
|
||||||
} from "@/service/promotion";
|
} from "@/service/promotion";
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
|
|
@ -100,12 +101,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(() => {
|
||||||
|
|
@ -208,6 +209,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}` +
|
||||||
|
|
@ -412,6 +447,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"}
|
||||||
|
|
@ -436,8 +475,9 @@ 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
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -447,6 +487,16 @@ export default function PromotionTable() {
|
||||||
<CheckCheck className="w-4 h-4 mr-1" />
|
<CheckCheck className="w-4 h-4 mr-1" />
|
||||||
Approve
|
Approve
|
||||||
</Button>
|
</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
|
||||||
|
|
|
||||||
|
|
@ -46,3 +46,27 @@ export async function approveAgent(id: string | number) {
|
||||||
};
|
};
|
||||||
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 httpGet(
|
||||||
|
`/approval-histories/${moduleType}/${moduleId}`,
|
||||||
|
headers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,3 +56,27 @@ export async function approveBanner(id: string | number) {
|
||||||
};
|
};
|
||||||
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 httpGet(
|
||||||
|
`/approval-histories/${moduleType}/${moduleId}`,
|
||||||
|
headers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,3 +77,27 @@ export async function approveGalery(id: string | number) {
|
||||||
};
|
};
|
||||||
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 httpGet(
|
||||||
|
`/approval-histories/${moduleType}/${moduleId}`,
|
||||||
|
headers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,3 +49,27 @@ export async function approveProduct(id: string | number) {
|
||||||
};
|
};
|
||||||
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 httpGet(
|
||||||
|
`/approval-histories/${moduleType}/${moduleId}`,
|
||||||
|
headers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,3 +44,27 @@ export async function approvePromotion(id: string | number) {
|
||||||
};
|
};
|
||||||
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 httpGet(
|
||||||
|
`/approval-histories/${moduleType}/${moduleId}`,
|
||||||
|
headers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue