-
{{ item.name }}
+
{{ itemName(item) }}
- @if (item.simpleDescription) {
-
{{ item.simpleDescription }}
+ @if (itemDesc(item)) {
+
{{ itemDesc(item) }}
}
diff --git a/src/app/pages/search/search.component.ts b/src/app/pages/search/search.component.ts
index c7af37e..be8acc4 100644
--- a/src/app/pages/search/search.component.ts
+++ b/src/app/pages/search/search.component.ts
@@ -6,7 +6,8 @@ import { ApiService, CartService } from '../../services';
import { Item } from '../../models';
import { Subject, Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
-import { getDiscountedPrice, getMainImage, trackByItemId, getBadgeClass } from '../../utils/item.utils';
+import { getDiscountedPrice, getMainImage, trackByItemId, getBadgeClass, getTranslatedField } from '../../utils/item.utils';
+import { LanguageService } from '../../services/language.service';
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
import { TranslatePipe } from '../../i18n/translate.pipe';
import { TranslateService } from '../../i18n/translate.service';
@@ -27,7 +28,7 @@ export class SearchComponent implements OnDestroy {
totalResults = signal(0);
private skip = 0;
- private readonly count = 20;
+ private readonly count = 50;
private isLoadingMore = false;
private searchSubject = new Subject();
private searchSubscription: Subscription;
@@ -137,4 +138,8 @@ export class SearchComponent implements OnDestroy {
readonly getMainImage = getMainImage;
readonly trackByItemId = trackByItemId;
readonly getBadgeClass = getBadgeClass;
+
+ private langService = inject(LanguageService);
+ itemName(item: Item): string { return getTranslatedField(item, 'name', this.langService.currentLanguage()); }
+ itemDesc(item: Item): string { return getTranslatedField(item, 'simpleDescription', this.langService.currentLanguage()); }
}
diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts
index a72c2a1..2b46f85 100644
--- a/src/app/services/api.service.ts
+++ b/src/app/services/api.service.ts
@@ -18,7 +18,8 @@ export class ApiService {
* legacy marketplace format and the new backOffice API format.
*/
private normalizeItem(raw: any): Item {
- const item: Item = { ...raw };
+ const { partnerID, ...rest } = raw;
+ const item: Item = { ...rest };
// Map backOffice string id → legacy numeric itemID
if (raw.id != null && raw.itemID == null) {
@@ -30,6 +31,13 @@ export class ApiService {
if (raw.imgs && (!raw.photos || raw.photos.length === 0)) {
item.photos = raw.imgs.map((url: string) => ({ url }));
}
+ // Normalize photo type: API sends type='video'|'photo', template checks .video
+ if (item.photos) {
+ item.photos = item.photos.map((p: any) => ({
+ ...p,
+ video: p.video || (p.type === 'video' ? p.url : undefined),
+ }));
+ }
item.imgs = raw.imgs || raw.photos?.map((p: any) => p.url) || [];
// Map backOffice description (key-value array) → legacy description string
@@ -40,6 +48,33 @@ export class ApiService {
item.description = raw.description || raw.simpleDescription || '';
}
+ // Map backend names[] → translations (multi-lang name support)
+ if (raw.names && Array.isArray(raw.names)) {
+ item.names = raw.names;
+ if (!item.translations) item.translations = {};
+ for (const entry of raw.names) {
+ if (!item.translations[entry.language]) item.translations[entry.language] = {};
+ item.translations[entry.language].name = entry.value;
+ }
+ }
+
+ // Map backend descriptions[] → translations (multi-lang descriptions)
+ if (raw.descriptions && Array.isArray(raw.descriptions)) {
+ item.descriptions = raw.descriptions;
+ if (!item.translations) item.translations = {};
+ for (const entry of raw.descriptions) {
+ if (!item.translations[entry.language]) item.translations[entry.language] = {};
+ item.translations[entry.language].simpleDescription = entry.value;
+ }
+ }
+
+ // Preserve attributes from backend
+ item.attributes = raw.attributes || [];
+
+ // Preserve colour & size
+ item.colour = raw.colour || '';
+ item.size = raw.size || '';
+
// Map backOffice comments → legacy callbacks
if (raw.comments && (!raw.callbacks || raw.callbacks.length === 0)) {
item.callbacks = raw.comments.map((c: any) => ({
@@ -77,7 +112,7 @@ export class ApiService {
item.badges = raw.badges || [];
item.tags = raw.tags || [];
item.simpleDescription = raw.simpleDescription || '';
- item.translations = raw.translations || {};
+ item.translations = item.translations || raw.translations || {};
item.visible = raw.visible ?? true;
item.priority = raw.priority ?? 0;
diff --git a/src/app/services/language.service.ts b/src/app/services/language.service.ts
index 12232db..612327f 100644
--- a/src/app/services/language.service.ts
+++ b/src/app/services/language.service.ts
@@ -9,11 +9,18 @@ export interface Language {
enabled: boolean;
}
+export interface Currency {
+ code: string;
+ symbol: string;
+ name: string;
+}
+
@Injectable({
providedIn: 'root'
})
export class LanguageService {
private currentLanguageSignal = signal('ru');
+ private currentCurrencySignal = signal('RUB');
languages: Language[] = [
{ code: 'ru', name: 'Русский', flag: '🇷🇺', flagSvg: '/flags/ru.svg', enabled: true },
@@ -21,7 +28,15 @@ export class LanguageService {
{ code: 'hy', name: 'Հայերեն', flag: '🇦🇲', flagSvg: '/flags/arm.svg', enabled: true }
];
+ currencies: Currency[] = [
+ { code: 'RUB', symbol: '₽', name: 'Рубль' },
+ { code: 'USD', symbol: '$', name: 'Dollar' },
+ { code: 'EUR', symbol: '€', name: 'Euro' },
+ { code: 'AMD', symbol: '֏', name: 'Դրամ' },
+ ];
+
currentLanguage = this.currentLanguageSignal.asReadonly();
+ currentCurrency = this.currentCurrencySignal.asReadonly();
constructor(private router: Router) {
// Load saved language from localStorage
@@ -29,6 +44,11 @@ export class LanguageService {
if (savedLang && this.languages.find(l => l.code === savedLang && l.enabled)) {
this.currentLanguageSignal.set(savedLang);
}
+
+ const savedCurrency = localStorage.getItem('selectedCurrency');
+ if (savedCurrency && this.currencies.find(c => c.code === savedCurrency)) {
+ this.currentCurrencySignal.set(savedCurrency);
+ }
}
setLanguage(langCode: string): void {
@@ -39,6 +59,18 @@ export class LanguageService {
}
}
+ setCurrency(code: string): void {
+ const currency = this.currencies.find(c => c.code === code);
+ if (currency) {
+ this.currentCurrencySignal.set(code);
+ localStorage.setItem('selectedCurrency', code);
+ }
+ }
+
+ getCurrentCurrency(): Currency | undefined {
+ return this.currencies.find(c => c.code === this.currentCurrencySignal());
+ }
+
/** Change language and navigate to the same page with the new prefix */
switchLanguage(langCode: string): void {
const lang = this.languages.find(l => l.code === langCode);
diff --git a/src/app/utils/item.utils.ts b/src/app/utils/item.utils.ts
index 13b2ebe..3d0eb16 100644
--- a/src/app/utils/item.utils.ts
+++ b/src/app/utils/item.utils.ts
@@ -61,17 +61,31 @@ export function getBadgeClass(badge: string): string {
/**
* Get the translated name/description for the current language.
- * Falls back to the default (base) field if no translation exists.
+ * 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 (backOffice format)
const translation = item.translations?.[lang];
if (translation && translation[field]) {
return translation[field]!;
}
+
+ // 2. Check names[]/descriptions[] arrays (backend API format)
+ if (field === 'name' && item.names?.length) {
+ const entry = item.names.find(n => n.language === lang);
+ if (entry) return entry.value;
+ }
+ if (field === 'simpleDescription' && item.descriptions?.length) {
+ const entry = item.descriptions.find(d => d.language === lang);
+ if (entry) return entry.value;
+ }
+
+ // 3. Fallback to base field
if (field === 'name') return item.name;
if (field === 'simpleDescription') return item.simpleDescription || item.description || '';
return '';
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
index f256912..a512e31 100644
--- a/src/environments/environment.ts
+++ b/src/environments/environment.ts
@@ -1,11 +1,11 @@
// Dexar Market Configuration
export const environment = {
production: false,
- useMockData: true, // Toggle to test with backOffice mock data
+ useMockData: false, // Toggle to test with backOffice mock data
brandName: 'Dexarmarket',
brandFullName: 'Dexar Market',
theme: 'dexar',
- apiUrl: 'https://api.dexarmarket.ru:445',
+ apiUrl: '/api',
logo: '/assets/images/dexar-logo.svg',
contactEmail: 'info@dexarmarket.ru',
supportEmail: 'info@dexarmarket.ru',