Fix admin review update detection and redirect cleanup
This commit is contained in:
@ -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 {
|
||||
|
||||
@ -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" };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user