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";
|
||||
import type { TTenderDetails } from "@/lib/api/types/Tenders";
|
||||
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 { TenderDetailsError } from "./components/tender-details-error";
|
||||
import { TenderDetailsHeader } from "./components/tender-details-header";
|
||||
@@ -31,9 +31,10 @@ const TenderDetails = ({ params }: IProps) => {
|
||||
const selectedLanguage = searchParams.get("lang") || "en";
|
||||
const { mutate: translateTender, isPending: isTranslating } =
|
||||
useTranslateTenderMutation();
|
||||
const { data, isLoading, isError } = useTenderDetailQuery(details, {
|
||||
lang: selectedLanguage,
|
||||
});
|
||||
const { data, isLoading, isError, isFetching } = useTenderDetailQuery(
|
||||
details,
|
||||
{ language: selectedLanguage },
|
||||
);
|
||||
|
||||
const breadcrumbItems = [
|
||||
{ name: "Dashboard", href: "/" },
|
||||
@@ -63,6 +64,13 @@ const TenderDetails = ({ params }: IProps) => {
|
||||
[tenderNavItems],
|
||||
);
|
||||
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(
|
||||
(event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const nextLanguage = event.target.value;
|
||||
@@ -71,16 +79,53 @@ const TenderDetails = ({ params }: IProps) => {
|
||||
const prevLanguage = searchParams.get("lang") || "en";
|
||||
if (nextLanguage === prevLanguage) return;
|
||||
|
||||
userPendingLangRef.current = nextLanguage;
|
||||
|
||||
const nextParams = new URLSearchParams(searchParams.toString());
|
||||
nextParams.set("lang", nextLanguage);
|
||||
const queryString = nextParams.toString();
|
||||
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 (isError) {
|
||||
return <TenderDetailsError breadcrumbItems={breadcrumbItems} />;
|
||||
|
||||
Reference in New Issue
Block a user