feat(tender-details): enhance language translation handling in TenderDetails component
- Added useRef hooks to manage pending language changes and prevent retry loops during translation. - Updated the language query parameter handling to ensure translations are only triggered when the user explicitly selects a language. - Improved the useEffect logic to handle translation requests based on fetched data and user selections, enhancing user experience and performance.
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
|||||||
} from "@/hooks/queries";
|
} from "@/hooks/queries";
|
||||||
import type { TTenderDetails } from "@/lib/api/types/Tenders";
|
import type { TTenderDetails } from "@/lib/api/types/Tenders";
|
||||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||||
import { use, useCallback, useMemo } from "react";
|
import { use, useCallback, useEffect, useMemo, useRef } from "react";
|
||||||
import { TenderDetailsContent } from "./components/tender-details-content";
|
import { TenderDetailsContent } from "./components/tender-details-content";
|
||||||
import { TenderDetailsError } from "./components/tender-details-error";
|
import { TenderDetailsError } from "./components/tender-details-error";
|
||||||
import { TenderDetailsHeader } from "./components/tender-details-header";
|
import { TenderDetailsHeader } from "./components/tender-details-header";
|
||||||
@@ -31,9 +31,10 @@ const TenderDetails = ({ params }: IProps) => {
|
|||||||
const selectedLanguage = searchParams.get("lang") || "en";
|
const selectedLanguage = searchParams.get("lang") || "en";
|
||||||
const { mutate: translateTender, isPending: isTranslating } =
|
const { mutate: translateTender, isPending: isTranslating } =
|
||||||
useTranslateTenderMutation();
|
useTranslateTenderMutation();
|
||||||
const { data, isLoading, isError } = useTenderDetailQuery(details, {
|
const { data, isLoading, isError, isFetching } = useTenderDetailQuery(
|
||||||
lang: selectedLanguage,
|
details,
|
||||||
});
|
{ language: selectedLanguage },
|
||||||
|
);
|
||||||
|
|
||||||
const breadcrumbItems = [
|
const breadcrumbItems = [
|
||||||
{ name: "Dashboard", href: "/" },
|
{ name: "Dashboard", href: "/" },
|
||||||
@@ -63,6 +64,13 @@ const TenderDetails = ({ params }: IProps) => {
|
|||||||
[tenderNavItems],
|
[tenderNavItems],
|
||||||
);
|
);
|
||||||
const activeSectionId = useTenderSectionScrollSpy(sectionIds);
|
const activeSectionId = useTenderSectionScrollSpy(sectionIds);
|
||||||
|
|
||||||
|
// Only translate when the user explicitly picks a language from the dropdown.
|
||||||
|
// The ref is set inside handleLanguageChange and consumed by the effect once
|
||||||
|
// the GET refetch resolves; initial page loads never trigger a translate.
|
||||||
|
const userPendingLangRef = useRef<string | null>(null);
|
||||||
|
const attemptedRef = useRef<Set<string>>(new Set());
|
||||||
|
|
||||||
const handleLanguageChange = useCallback(
|
const handleLanguageChange = useCallback(
|
||||||
(event: React.ChangeEvent<HTMLSelectElement>) => {
|
(event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
const nextLanguage = event.target.value;
|
const nextLanguage = event.target.value;
|
||||||
@@ -71,16 +79,53 @@ const TenderDetails = ({ params }: IProps) => {
|
|||||||
const prevLanguage = searchParams.get("lang") || "en";
|
const prevLanguage = searchParams.get("lang") || "en";
|
||||||
if (nextLanguage === prevLanguage) return;
|
if (nextLanguage === prevLanguage) return;
|
||||||
|
|
||||||
|
userPendingLangRef.current = nextLanguage;
|
||||||
|
|
||||||
const nextParams = new URLSearchParams(searchParams.toString());
|
const nextParams = new URLSearchParams(searchParams.toString());
|
||||||
nextParams.set("lang", nextLanguage);
|
nextParams.set("lang", nextLanguage);
|
||||||
const queryString = nextParams.toString();
|
const queryString = nextParams.toString();
|
||||||
router.replace(queryString ? `${pathname}?${queryString}` : pathname);
|
router.replace(queryString ? `${pathname}?${queryString}` : pathname);
|
||||||
|
|
||||||
translateTender({ id: details, language: nextLanguage });
|
|
||||||
},
|
},
|
||||||
[details, pathname, router, searchParams, translateTender],
|
[pathname, router, searchParams],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ensureTranslation flow (per backend integration doc):
|
||||||
|
// 1) User picks a language → handleLanguageChange marks it as pending.
|
||||||
|
// 2) GET detail with ?language={selected} refetches.
|
||||||
|
// 3) If the refetched data.language doesn't match, POST ai-translate.
|
||||||
|
// The mutation's onSuccess invalidates the detail query → refetch binds title/description.
|
||||||
|
// attemptedRef prevents a retry loop if translation fails.
|
||||||
|
useEffect(() => {
|
||||||
|
const fetched = data?.data;
|
||||||
|
if (!fetched) return;
|
||||||
|
if (isFetching || isTranslating) return;
|
||||||
|
|
||||||
|
const pending = userPendingLangRef.current;
|
||||||
|
if (!pending || pending !== selectedLanguage) return;
|
||||||
|
|
||||||
|
if (fetched.language === selectedLanguage) {
|
||||||
|
userPendingLangRef.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = `${details}::${selectedLanguage}`;
|
||||||
|
if (attemptedRef.current.has(key)) {
|
||||||
|
userPendingLangRef.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
attemptedRef.current.add(key);
|
||||||
|
userPendingLangRef.current = null;
|
||||||
|
|
||||||
|
translateTender({ id: details, language: selectedLanguage });
|
||||||
|
}, [
|
||||||
|
data,
|
||||||
|
details,
|
||||||
|
isFetching,
|
||||||
|
isTranslating,
|
||||||
|
selectedLanguage,
|
||||||
|
translateTender,
|
||||||
|
]);
|
||||||
|
|
||||||
if (isLoading) return <Loading />;
|
if (isLoading) return <Loading />;
|
||||||
if (isError) {
|
if (isError) {
|
||||||
return <TenderDetailsError breadcrumbItems={breadcrumbItems} />;
|
return <TenderDetailsError breadcrumbItems={breadcrumbItems} />;
|
||||||
|
|||||||
Reference in New Issue
Block a user