107 lines
3.4 KiB
TypeScript
107 lines
3.4 KiB
TypeScript
import { Item } from '../models';
|
|
import { Category } from '../models/category.model';
|
|
|
|
export function getDiscountedPrice(item: Item): number {
|
|
return item.price * (1 - (item.discount || 0) / 100);
|
|
}
|
|
|
|
export function getMainImage(item: Item): string {
|
|
// Support both backOffice format (imgs: string[]) and legacy (photos: Photo[])
|
|
if (item.imgs && item.imgs.length > 0) {
|
|
return item.imgs[0];
|
|
}
|
|
return item.photos?.[0]?.url || '/assets/images/placeholder.svg';
|
|
}
|
|
|
|
export function getAllImages(item: Item): string[] {
|
|
if (item.imgs && item.imgs.length > 0) {
|
|
return item.imgs;
|
|
}
|
|
return item.photos?.map(p => p.url) || [];
|
|
}
|
|
|
|
export function trackByItemId(index: number, item: Item): number | string {
|
|
return item.id || item.itemID;
|
|
}
|
|
|
|
/**
|
|
* Get the display description — supports both legacy HTML string
|
|
* and structured key-value pairs from backOffice API.
|
|
*/
|
|
export function hasStructuredDescription(item: Item): boolean {
|
|
return Array.isArray(item.descriptionFields) && item.descriptionFields.length > 0;
|
|
}
|
|
|
|
/**
|
|
* Compute stock status from quantity if the legacy `remainings` field is absent.
|
|
*/
|
|
export function getStockStatus(item: Item): string {
|
|
if (item.remainings) return item.remainings;
|
|
if (item.quantity == null) return 'high';
|
|
if (item.quantity <= 0) return 'out';
|
|
if (item.quantity <= 5) return 'low';
|
|
if (item.quantity <= 20) return 'medium';
|
|
return 'high';
|
|
}
|
|
|
|
/**
|
|
* Map backOffice badge names to CSS color classes.
|
|
*/
|
|
export function getBadgeClass(badge: string): string {
|
|
const map: Record<string, string> = {
|
|
'new': 'badge-new',
|
|
'sale': 'badge-sale',
|
|
'exclusive': 'badge-exclusive',
|
|
'hot': 'badge-hot',
|
|
'limited': 'badge-limited',
|
|
'bestseller': 'badge-bestseller',
|
|
'featured': 'badge-featured',
|
|
};
|
|
return map[badge.toLowerCase()] || 'badge-custom';
|
|
}
|
|
|
|
/**
|
|
* Get the translated name/description for the current language.
|
|
* Checks translations map first, then names[]/descriptions[] arrays,
|
|
* then falls back to the default (base) field.
|
|
*/
|
|
export function getTranslatedField(
|
|
item: Item,
|
|
field: 'name' | 'simpleDescription',
|
|
lang: string
|
|
): string {
|
|
// 1. Check translations map (already normalized to frontend codes)
|
|
const translation = item.translations?.[lang];
|
|
if (translation && translation[field]) {
|
|
return translation[field]!;
|
|
}
|
|
|
|
// 2. Check names[]/descriptions[] arrays (may have API codes: RU/EN/AM)
|
|
// Note: API has typo "valuue" in some responses — handle both
|
|
if (field === 'name' && item.names?.length) {
|
|
const entry = item.names.find(n => n.language === lang || n.language === lang.toUpperCase() || (lang === 'hy' && n.language === 'AM'));
|
|
const val = entry?.value || (entry as any)?.valuue || '';
|
|
if (val) return val;
|
|
}
|
|
// 3. Fallback to base field
|
|
if (field === 'name') return item.name;
|
|
if (field === 'simpleDescription') return item.simpleDescription || item.description || '';
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Get translated category name for the current language.
|
|
*/
|
|
export function getTranslatedCategoryName(cat: Category, lang: string): string {
|
|
const translation = cat.translations?.[lang];
|
|
if (translation?.name) return translation.name;
|
|
|
|
if (cat.names?.length) {
|
|
const entry = cat.names.find(n => n.language === lang || n.language === lang.toUpperCase() || (lang === 'hy' && n.language === 'AM'));
|
|
const val = entry?.value || (entry as any)?.valuue || '';
|
|
if (val) return val;
|
|
}
|
|
|
|
return cat.name || '';
|
|
}
|