Fix Persian user-product URL redirect loop.

Compare decoded/NFC slugs and stop percent-encoding path segments so detail pages no longer 307 themselves into a white screen.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-09-15 15:54:59 +03:30
co-authored by Cursor
parent 911aa79530
commit 7bd5f55b92
2 changed files with 19 additions and 4 deletions
+2 -1
View File
@@ -13,6 +13,7 @@ import {
getUserProductByIdOrNull,
getUserProductTechnicalInfoById,
listUserProducts,
normalizePathSlug,
productCategory,
productTitle,
userProductHref,
@@ -51,7 +52,7 @@ export default async function UserProductDetailPage({ params }: PageProps) {
if (!product) notFound();
const canonicalSlug = userProductPathSlug(product);
if (slug !== canonicalSlug) {
if (normalizePathSlug(slug) !== canonicalSlug) {
redirect(userProductHref(product));
}
+17 -3
View File
@@ -77,22 +77,36 @@ export function slugifyForUrl(value: string, fallback = "user-product") {
return slug || fallback;
}
/** Decode + NFC so route params and API pathSlug compare safely. */
export function normalizePathSlug(value: string) {
let decoded = value.trim();
try {
decoded = decodeURIComponent(decoded);
} catch {
/* already decoded or malformed — keep as-is */
}
return decoded.normalize("NFC").trim();
}
export function userProductPathSlug(
product: Pick<UserProductListItem, "pathSlug" | "titleFa" | "titleEn">,
) {
const fromApi = product.pathSlug?.trim();
if (fromApi) return fromApi;
if (fromApi) return normalizePathSlug(fromApi);
return slugifyForUrl(
product.titleFa?.trim() || product.titleEn?.trim() || "",
"user-product",
);
}
/** Canonical storefront path: `/user-products/{id}/{pathSlug}`. */
/**
* Canonical storefront path: `/user-products/{id}/{pathSlug}`.
* Leave Unicode unencoded — encoding + Next param decoding caused redirect loops.
*/
export function userProductHref(
product: Pick<UserProductListItem, "id" | "pathSlug" | "titleFa" | "titleEn">,
) {
return `/user-products/${encodeURIComponent(product.id)}/${encodeURIComponent(userProductPathSlug(product))}`;
return `/user-products/${product.id}/${userProductPathSlug(product)}`;
}
export async function listUserProducts(params: ListUserProductsParams = {}) {