Commit 7cfa96fa authored by Phạm Quang Bảo's avatar Phạm Quang Bảo

[tag]0.1-vcci

parents eb79d2ed 1094de1d
Pipeline #53836 passed with stages
in 2 minutes and 10 seconds
...@@ -321,6 +321,7 @@ export default function DynamicPageClient() { ...@@ -321,6 +321,7 @@ export default function DynamicPageClient() {
if (resolvedCategory?.type === "news") { if (resolvedCategory?.type === "news") {
return ( return (
<NewsPage <NewsPage
key={resolvedCategory.id}
category={resolvedCategory} category={resolvedCategory}
allCategories={allCategories} allCategories={allCategories}
/> />
......
...@@ -32,22 +32,15 @@ export default function AnPham({ category, allCategories }: AnPhamProps) { ...@@ -32,22 +32,15 @@ export default function AnPham({ category, allCategories }: AnPhamProps) {
const pathname = usePathname(); const pathname = usePathname();
const searchParamsString = searchParams.toString(); const searchParamsString = searchParams.toString();
const initialPage = Number(searchParams.get("page") ?? "1"); const pageParam = Number(searchParams.get("page") ?? "1");
const [searchInput, setSearchInput] = useState(""); const initialPage = Number.isFinite(pageParam) && pageParam > 0 ? Math.floor(pageParam) : 1;
const [submitSearch, setSubmitSearch] = useState(""); const initialQuery = searchParams.get("q") ?? "";
const [searchInput, setSearchInput] = useState(initialQuery);
const [submitSearch, setSubmitSearch] = useState(initialQuery);
const [page, setPage] = useState(initialPage); const [page, setPage] = useState(initialPage);
const pageSize = 8; const pageSize = 8;
const keyword = submitSearch.trim(); const keyword = submitSearch.trim();
// Auto-search with debounce
useEffect(() => {
const timer = setTimeout(() => {
setSubmitSearch(searchInput);
setPage(1);
}, 500);
return () => clearTimeout(timer);
}, [searchInput]);
useEffect(() => { useEffect(() => {
const params = new URLSearchParams(searchParamsString); const params = new URLSearchParams(searchParamsString);
if (page > 1) { if (page > 1) {
...@@ -56,6 +49,12 @@ export default function AnPham({ category, allCategories }: AnPhamProps) { ...@@ -56,6 +49,12 @@ export default function AnPham({ category, allCategories }: AnPhamProps) {
params.delete("page"); params.delete("page");
} }
if (keyword) {
params.set("q", keyword);
} else {
params.delete("q");
}
const qs = params.toString(); const qs = params.toString();
const nextUrl = qs ? `${pathname}?${qs}` : pathname; const nextUrl = qs ? `${pathname}?${qs}` : pathname;
const currentUrl = searchParamsString ? `${pathname}?${searchParamsString}` : pathname; const currentUrl = searchParamsString ? `${pathname}?${searchParamsString}` : pathname;
...@@ -63,7 +62,7 @@ export default function AnPham({ category, allCategories }: AnPhamProps) { ...@@ -63,7 +62,7 @@ export default function AnPham({ category, allCategories }: AnPhamProps) {
if (nextUrl !== currentUrl) { if (nextUrl !== currentUrl) {
router.replace(nextUrl, { scroll: false }); router.replace(nextUrl, { scroll: false });
} }
}, [page, pathname, router, searchParamsString]); }, [page, keyword, pathname, router, searchParamsString]);
const filters = [ const filters = [
category?.id ? `category.id==${category.id}` : null, category?.id ? `category.id==${category.id}` : null,
......
...@@ -32,22 +32,15 @@ export default function ThuVienTaiLieu({ category, allCategories }: ThuVienTaiLi ...@@ -32,22 +32,15 @@ export default function ThuVienTaiLieu({ category, allCategories }: ThuVienTaiLi
const pathname = usePathname(); const pathname = usePathname();
const searchParamsString = searchParams.toString(); const searchParamsString = searchParams.toString();
const initialPage = Number(searchParams.get("page") ?? "1"); const pageParam = Number(searchParams.get("page") ?? "1");
const [searchInput, setSearchInput] = useState(""); const initialPage = Number.isFinite(pageParam) && pageParam > 0 ? Math.floor(pageParam) : 1;
const [submitSearch, setSubmitSearch] = useState(""); const initialQuery = searchParams.get("q") ?? "";
const [searchInput, setSearchInput] = useState(initialQuery);
const [submitSearch, setSubmitSearch] = useState(initialQuery);
const [page, setPage] = useState(initialPage); const [page, setPage] = useState(initialPage);
const pageSize = 8; const pageSize = 8;
const keyword = submitSearch.trim(); const keyword = submitSearch.trim();
// Auto-search with debounce
useEffect(() => {
const timer = setTimeout(() => {
setSubmitSearch(searchInput);
setPage(1);
}, 500);
return () => clearTimeout(timer);
}, [searchInput]);
useEffect(() => { useEffect(() => {
const params = new URLSearchParams(searchParamsString); const params = new URLSearchParams(searchParamsString);
if (page > 1) { if (page > 1) {
...@@ -56,6 +49,12 @@ export default function ThuVienTaiLieu({ category, allCategories }: ThuVienTaiLi ...@@ -56,6 +49,12 @@ export default function ThuVienTaiLieu({ category, allCategories }: ThuVienTaiLi
params.delete("page"); params.delete("page");
} }
if (keyword) {
params.set("q", keyword);
} else {
params.delete("q");
}
const qs = params.toString(); const qs = params.toString();
const nextUrl = qs ? `${pathname}?${qs}` : pathname; const nextUrl = qs ? `${pathname}?${qs}` : pathname;
const currentUrl = searchParamsString ? `${pathname}?${searchParamsString}` : pathname; const currentUrl = searchParamsString ? `${pathname}?${searchParamsString}` : pathname;
...@@ -63,7 +62,7 @@ export default function ThuVienTaiLieu({ category, allCategories }: ThuVienTaiLi ...@@ -63,7 +62,7 @@ export default function ThuVienTaiLieu({ category, allCategories }: ThuVienTaiLi
if (nextUrl !== currentUrl) { if (nextUrl !== currentUrl) {
router.replace(nextUrl, { scroll: false }); router.replace(nextUrl, { scroll: false });
} }
}, [page, pathname, router, searchParamsString]); }, [page, keyword, pathname, router, searchParamsString]);
const filters = [ const filters = [
category?.id ? `category.id==${category.id}` : null, category?.id ? `category.id==${category.id}` : null,
......
...@@ -57,22 +57,15 @@ export default function NewsPage({ category, allCategories }: NewsPageProps) { ...@@ -57,22 +57,15 @@ export default function NewsPage({ category, allCategories }: NewsPageProps) {
const pathname = usePathname(); const pathname = usePathname();
const searchParamsString = searchParams.toString(); const searchParamsString = searchParams.toString();
const initialPage = Number(searchParams.get("page") ?? "1"); const pageParam = Number(searchParams.get("page") ?? "1");
const [searchInput, setSearchInput] = useState(""); const initialPage = Number.isFinite(pageParam) && pageParam > 0 ? Math.floor(pageParam) : 1;
const [submitSearch, setSubmitSearch] = useState(""); const initialQuery = searchParams.get("q") ?? "";
const [searchInput, setSearchInput] = useState(initialQuery);
const [submitSearch, setSubmitSearch] = useState(initialQuery);
const [page, setPage] = useState(initialPage); const [page, setPage] = useState(initialPage);
const pageSize = 10; const pageSize = 10;
const keyword = submitSearch.trim(); const keyword = submitSearch.trim();
// Auto-search with debounce
useEffect(() => {
const timer = setTimeout(() => {
setSubmitSearch(searchInput);
setPage(1);
}, 500);
return () => clearTimeout(timer);
}, [searchInput]);
useEffect(() => { useEffect(() => {
const params = new URLSearchParams(searchParamsString); const params = new URLSearchParams(searchParamsString);
if (page > 1) { if (page > 1) {
...@@ -81,6 +74,12 @@ export default function NewsPage({ category, allCategories }: NewsPageProps) { ...@@ -81,6 +74,12 @@ export default function NewsPage({ category, allCategories }: NewsPageProps) {
params.delete("page"); params.delete("page");
} }
if (keyword) {
params.set("q", keyword);
} else {
params.delete("q");
}
const qs = params.toString(); const qs = params.toString();
const nextUrl = qs ? `${pathname}?${qs}` : pathname; const nextUrl = qs ? `${pathname}?${qs}` : pathname;
const currentUrl = searchParamsString ? `${pathname}?${searchParamsString}` : pathname; const currentUrl = searchParamsString ? `${pathname}?${searchParamsString}` : pathname;
...@@ -88,7 +87,7 @@ export default function NewsPage({ category, allCategories }: NewsPageProps) { ...@@ -88,7 +87,7 @@ export default function NewsPage({ category, allCategories }: NewsPageProps) {
if (nextUrl !== currentUrl) { if (nextUrl !== currentUrl) {
router.replace(nextUrl, { scroll: false }); router.replace(nextUrl, { scroll: false });
} }
}, [page, pathname, router, searchParamsString]); }, [page, keyword, pathname, router, searchParamsString]);
const filters = `category.id==${category.id}${keyword ? `,title@=${keyword}` : ""},is_hidden==false,is_active==true,type==news`; const filters = `category.id==${category.id}${keyword ? `,title@=${keyword}` : ""},is_hidden==false,is_active==true,type==news`;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
import { NextRequest, NextResponse } from "next/server";
import { LEGACY_ID_MAP, LEGACY_SLUG_MAP } from "@/lib/legacy-redirect-map";
/**
* Redirect cac link cu cua site WordPress ve slug hien tai trong CMS moi:
* - ?p=<id> (link kieu ?p=11051)
* - .../ten-bai.html (permalink cu co duoi .html)
* - /ten-bai (slug cu bi doi)
* Map tu dong tao boi migration/scripts/build-redirect-map.mjs.
*
* Next.js 16: middleware.ts -> proxy.ts (cu), ham export 'proxy'.
*/
export default function proxy(req: NextRequest) {
// 1. ?p=<id>
const p = req.nextUrl.searchParams.get("p");
if (p) {
const slug = LEGACY_ID_MAP[p];
if (slug) {
return NextResponse.redirect(new URL("/" + slug, req.nextUrl.origin), 308);
}
}
// 2. duoi .html
const pathname = req.nextUrl.pathname;
if (pathname.toLowerCase().endsWith(".html")) {
const trimmed = pathname.slice(0, -5);
const last = trimmed.split("/").filter(Boolean).pop();
if (last) {
const target = LEGACY_SLUG_MAP[last] ?? last;
return NextResponse.redirect(new URL("/" + target + req.nextUrl.search, req.nextUrl.origin), 308);
}
}
// 3. slug cu bi doi
const clean = pathname.replace(/\/+$/, "").replace(/^\//, "");
const mapped = LEGACY_SLUG_MAP[clean];
if (mapped) {
return NextResponse.redirect(new URL("/" + mapped + req.nextUrl.search, req.nextUrl.origin), 308);
}
return NextResponse.next();
}
export const config = {
matcher: [
"/((?!api|admin|uploads|_next/static|_next/image|images/|public/|favicon.ico|thumbnail.png|robots.txt|sitemap.xml|ads.txt).*)",
],
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment