Initial commit: Hoomat storefront with Meshkee API and static-image slots.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import type { Category, CategoryTreeNode, GuestCartLine } from "@/lib/meshkee/types";
|
||||
|
||||
export function slugifyFa(value: string | null | undefined): string {
|
||||
const raw = (value ?? "").trim().toLowerCase();
|
||||
if (!raw) return "item";
|
||||
return raw
|
||||
.replace(/\s+/g, "-")
|
||||
.replace(/[^\u0600-\u06FFa-z0-9-]+/g, "")
|
||||
.replace(/-+/g, "-")
|
||||
.replace(/^-|-$/g, "") || "item";
|
||||
}
|
||||
|
||||
export function formatPrice(value: number | null | undefined): string {
|
||||
const amount = Number(value ?? 0);
|
||||
return `${new Intl.NumberFormat("fa-IR").format(amount)} تومان`;
|
||||
}
|
||||
|
||||
export function formatDate(value: string | null | undefined): string {
|
||||
if (!value) return "";
|
||||
try {
|
||||
return new Intl.DateTimeFormat("fa-IR", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
}).format(new Date(value));
|
||||
} catch {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
export function displayName(user: {
|
||||
firstName?: string | null;
|
||||
lastName?: string | null;
|
||||
}): string {
|
||||
const first = user.firstName?.trim();
|
||||
if (first) return first;
|
||||
const last = user.lastName?.trim();
|
||||
if (last) return last;
|
||||
return "کاربر";
|
||||
}
|
||||
|
||||
export function buildCategoryTree(categories: Category[]): CategoryTreeNode[] {
|
||||
const map = new Map<string, CategoryTreeNode>();
|
||||
for (const category of categories) {
|
||||
if (category.isActive === false) continue;
|
||||
map.set(category.id, { ...category, children: [] });
|
||||
}
|
||||
|
||||
const roots: CategoryTreeNode[] = [];
|
||||
for (const node of map.values()) {
|
||||
if (node.parentId && map.has(node.parentId)) {
|
||||
map.get(node.parentId)!.children.push(node);
|
||||
} else {
|
||||
roots.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
const sortNodes = (nodes: CategoryTreeNode[]) => {
|
||||
nodes.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
|
||||
nodes.forEach((node) => sortNodes(node.children));
|
||||
};
|
||||
sortNodes(roots);
|
||||
return roots;
|
||||
}
|
||||
|
||||
export function categoryLabel(category: Category): string {
|
||||
return category.nameFa?.trim() || category.name;
|
||||
}
|
||||
|
||||
export function storeItemName(item: {
|
||||
productNameFa?: string | null;
|
||||
productTitle?: string | null;
|
||||
label?: string | null;
|
||||
}): string {
|
||||
return item.productNameFa?.trim() || item.productTitle?.trim() || "محصول";
|
||||
}
|
||||
|
||||
export function storeItemPrice(item: {
|
||||
price: number;
|
||||
discountedPrice?: number | null;
|
||||
}): number {
|
||||
return item.discountedPrice != null && item.discountedPrice > 0
|
||||
? item.discountedPrice
|
||||
: item.price;
|
||||
}
|
||||
|
||||
export function normalizeGuestLines(items: GuestCartLine[]): GuestCartLine[] {
|
||||
const result: GuestCartLine[] = [];
|
||||
for (const item of items) {
|
||||
const id = (item.id || "").trim();
|
||||
if (!id) continue;
|
||||
result.push({
|
||||
id,
|
||||
name: item.name || "محصول",
|
||||
slug: item.slug,
|
||||
price: Number(item.price) || 0,
|
||||
image: item.image ?? null,
|
||||
quantity: Math.max(1, Math.floor(item.quantity) || 1),
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user