Fix admin review update detection and redirect cleanup

This commit is contained in:
2026-05-11 01:53:42 +07:00
parent e13725b9a0
commit c3aa2e78d2
2 changed files with 51 additions and 12 deletions

View File

@ -1,7 +1,7 @@
"use client";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { Suspense, useEffect, useState } from "react";
import { Suspense, useEffect, useRef, useState } from "react";
const API_BASE = process.env.NEXT_PUBLIC_API_URL || "https://be.inatrading.co.id";
@ -61,6 +61,26 @@ function extractIdChange(payload: unknown) {
| undefined;
}
function isProductUpdateFromCompare(
change:
| {
oldValue?: string;
newValue?: string;
isUpdate?: boolean;
}
| undefined
) {
if (!change) return false;
const hasDifferentIds =
typeof change.oldValue === "string" &&
typeof change.newValue === "string" &&
change.oldValue !== "" &&
change.newValue !== "" &&
change.oldValue !== change.newValue;
return change.isUpdate === true || hasDifferentIds;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function ProductColumn({ product, label, accent }: { product: any; label: string; accent?: boolean }) {
if (!product) return (
@ -208,6 +228,7 @@ function AdminReviewDetailPageInner() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [oldProduct, setOldProduct] = useState<any>(null); // original (compare)
const [isComparison, setIsComparison] = useState(false);
const [isUpdateProduct, setIsUpdateProduct] = useState(false);
const [loading, setLoading] = useState(true);
const [loadError, setLoadError] = useState("");
@ -216,6 +237,7 @@ function AdminReviewDetailPageInner() {
const [actionSuccess, setActionSuccess] = useState("");
const [showRejectModal, setShowRejectModal] = useState(false);
const [rejectReason, setRejectReason] = useState("");
const redirectTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
if (!params.productId) return;
@ -223,6 +245,7 @@ function AdminReviewDetailPageInner() {
setLoadError("");
setOldProduct(null);
setIsComparison(false);
setIsUpdateProduct(false);
const reviewFetch = fetch(`/api/admin/review/${params.productId}`, {
headers: { "x-auth-token": getToken() },
@ -254,7 +277,10 @@ function AdminReviewDetailPageInner() {
setProduct(updated);
const shouldCompare = idChange?.isUpdate === true && Boolean(idChange.oldValue) && Boolean(idChange.newValue);
const isUpdate = isProductUpdateFromCompare(idChange);
setIsUpdateProduct(isUpdate);
const shouldCompare = isUpdate && Boolean(idChange?.oldValue) && Boolean(idChange?.newValue);
setIsComparison(shouldCompare);
if (shouldCompare) {
@ -272,6 +298,14 @@ function AdminReviewDetailPageInner() {
.finally(() => setLoading(false));
}, [params.productId]);
useEffect(() => {
return () => {
if (redirectTimeoutRef.current) {
clearTimeout(redirectTimeoutRef.current);
}
};
}, []);
async function submitReview(action: "accept" | "reject", reason?: string) {
setActing(true);
setActionError("");
@ -279,7 +313,7 @@ function AdminReviewDetailPageInner() {
const res = await fetch(`/api/admin/review/${params.productId}`, {
method: "POST",
headers: { "Content-Type": "application/json", "x-auth-token": getToken() },
body: JSON.stringify({ action, isNew: product?.isNew ?? true, reason }),
body: JSON.stringify({ action, isUpdate: isUpdateProduct, reason }),
});
const data = await res.json();
if (!res.ok) {
@ -287,7 +321,12 @@ function AdminReviewDetailPageInner() {
return;
}
setActionSuccess(action === "accept" ? "Update produk berhasil disetujui!" : "Update produk berhasil ditolak!");
setTimeout(() => router.push("/admin/review"), 1800);
if (redirectTimeoutRef.current) {
clearTimeout(redirectTimeoutRef.current);
}
redirectTimeoutRef.current = setTimeout(() => {
router.push("/admin/review");
}, 1800);
} catch {
setActionError("Gagal terhubung ke server");
} finally {

View File

@ -17,7 +17,7 @@ export async function GET(
}
// action: "accept" | "reject"
// isNew: boolean — determines which backend endpoint to call
// isUpdate: boolean — true for product update review, false for new product review
// body for reject: { reason: string }
export async function POST(
req: NextRequest,
@ -25,23 +25,23 @@ export async function POST(
) {
const token = req.headers.get("x-auth-token") || "";
const { productId } = await context.params;
const { action, isNew, reason } = await req.json();
const { action, isUpdate, reason } = await req.json();
let url: string;
let method = "POST";
let body: Record<string, string> | undefined;
if (action === "accept") {
// isNew=true: POST /product/accept/{id}
// isNew=false: PUT /product/accept/{id}
// new product review: POST /product/accept/{id}
// product update review: PUT /product/accept/{id}
url = `${API_URL}/api/v1.0/product/accept/${productId}`;
method = isNew ? "POST" : "PUT";
method = isUpdate ? "PUT" : "POST";
body = { state: "PUBLISHED" };
} else {
// isNew=true: POST /product/reject/{id}
// isNew=false: PUT /product/reject/{id}
// new product review: POST /product/reject/{id}
// product update review: PUT /product/reject/{id}
url = `${API_URL}/api/v1.0/product/reject/${productId}`;
method = isNew ? "POST" : "PUT";
method = isUpdate ? "PUT" : "POST";
body = reason ? { reason, state: "REJECTED" } : { state: "REJECTED" };
}