Add Torob tags, Meshkee SEO routes, and updated static-image slots.
Product pages emit crawler-readable meta, public URLs use id plus Farsi slugs, and the homepage catalog matches the dashboard slot keys. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
f42c30a4b7
commit
c84147e765
@@ -0,0 +1,58 @@
|
||||
import type { Metadata } from "next";
|
||||
import type { ApiProduct, ApiStoreItem, ApiVariant } from "./api";
|
||||
|
||||
function sellingPrice(variant: ApiVariant): number {
|
||||
const value = variant.discountedPrice ?? variant.price;
|
||||
return typeof value === "number" && Number.isFinite(value) ? Math.trunc(value) : 0;
|
||||
}
|
||||
|
||||
function inStock(variant: ApiVariant): boolean {
|
||||
return variant.stockQuantity === null || (typeof variant.stockQuantity === "number" && variant.stockQuantity > 0);
|
||||
}
|
||||
|
||||
export function pickTorobVariant(variants: ApiVariant[]): ApiVariant | undefined {
|
||||
if (!variants.length) return undefined;
|
||||
const available = variants.filter(inStock);
|
||||
const pool = available.length ? available : variants;
|
||||
return pool.reduce((cheapest, variant) =>
|
||||
sellingPrice(variant) < sellingPrice(cheapest) ? variant : cheapest,
|
||||
);
|
||||
}
|
||||
|
||||
function toHttpsUrl(url?: string | null): string | undefined {
|
||||
if (!url) return undefined;
|
||||
const trimmed = url.trim();
|
||||
if (trimmed.startsWith("https://")) return trimmed;
|
||||
if (trimmed.startsWith("http://")) return `https://${trimmed.slice("http://".length)}`;
|
||||
if (trimmed.startsWith("//")) return `https:${trimmed}`;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function torobMetadata(product: ApiProduct, storeItem: ApiStoreItem | null): Pick<Metadata, "other" | "openGraph"> {
|
||||
const variant = storeItem ? pickTorobVariant(storeItem.variants ?? []) : undefined;
|
||||
const price = storeItem && variant ? sellingPrice(variant) : 0;
|
||||
const available = Boolean(storeItem && variant && inStock(variant));
|
||||
const name = variant?.productNameFa || variant?.productTitle || product.nameFa || product.title;
|
||||
const image =
|
||||
toHttpsUrl(variant?.productImage) ||
|
||||
toHttpsUrl(product.thumbnailUrl) ||
|
||||
toHttpsUrl(product.image) ||
|
||||
toHttpsUrl(product.thumbnail) ||
|
||||
toHttpsUrl(product.images?.[0]?.url);
|
||||
|
||||
const other: Record<string, string> = {
|
||||
product_id: product.id,
|
||||
product_name: name,
|
||||
product_price: String(price),
|
||||
availability: available ? "instock" : "outofstock",
|
||||
};
|
||||
|
||||
if (variant && variant.discountedPrice != null) {
|
||||
other.product_old_price = String(typeof variant.price === "number" ? Math.trunc(variant.price) : 0);
|
||||
}
|
||||
|
||||
return {
|
||||
other,
|
||||
...(image ? { openGraph: { images: [{ url: image }] } } : {}),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user