This commit is contained in:
sdarbinyan
2026-03-24 02:47:31 +04:00
parent 5c6cb051ac
commit 09e8465577
5 changed files with 175 additions and 6 deletions

View File

@@ -3,6 +3,7 @@ import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable, Subject, throwError } from 'rxjs';
import { debounceTime, retry, catchError, map, groupBy, mergeMap } from 'rxjs/operators';
import { Project, Category, Subcategory, Item, ItemsListResponse } from '../models';
import { ItemName } from '../models/item.model';
import { MockDataService } from './mock-data.service';
import { ToastService } from './toast.service';
import { environment } from '../../environments/environment';
@@ -34,6 +35,108 @@ export class ApiService {
});
}
// ─── Normalizers ──────────────────────────────────────────
/** Get text from an ItemName entry, handling the backend 'valuue' typo */
private nameValue(entry: ItemName): string {
return entry.value || entry.valuue || '';
}
/** Normalize an item from the backend — extracts itemDetails, names, photos */
private normalizeItem(raw: any): Item {
const item: Item = { ...raw };
// Extract price/currency/remaining from itemDetails[0] if present
const details = raw.itemDetails || raw.itemdetails;
if (details && Array.isArray(details) && details.length > 0) {
const d = details[0];
item.itemDetails = details;
if (item.price == null || item.price === 0) item.price = d.price ?? 0;
if (!item.currency) item.currency = d.currency || 'RUB';
if (!item.colour) item.colour = d.colour || d.color || '';
if (!item.size) item.size = d.size || '';
if (item.quantity == null && d.remaining != null) item.quantity = d.remaining;
}
// Build translations from names[]/descriptions[] if translations map is empty
if (raw.names && Array.isArray(raw.names)) {
item.translations = item.translations || {};
for (const n of raw.names) {
const lang = n.language?.toLowerCase();
const val = this.nameValue(n);
if (lang && val) {
item.translations[lang] = item.translations[lang] || {};
item.translations[lang].name = val;
}
}
}
if (raw.descriptions && Array.isArray(raw.descriptions)) {
item.translations = item.translations || {};
for (const d of raw.descriptions) {
const lang = d.language?.toLowerCase();
const val = d.value || d.valuue || '';
if (lang && val) {
item.translations[lang] = item.translations[lang] || {};
item.translations[lang].simpleDescription = val;
}
}
}
// Build imgs[] from photos[] if imgs is empty
if ((!item.imgs || item.imgs.length === 0) && raw.photos && Array.isArray(raw.photos)) {
item.imgs = raw.photos.map((p: any) => p.url);
}
// Map callbacks → comments if comments is missing
if ((!item.comments || item.comments.length === 0) && raw.callbacks && Array.isArray(raw.callbacks)) {
item.comments = raw.callbacks.map((c: any) => ({
id: c.userID || '',
text: c.content || '',
author: c.userID || '',
stars: c.rating,
createdAt: c.timestamp,
}));
}
// Defaults
item.name = item.name || '';
item.price = item.price ?? 0;
item.discount = item.discount ?? 0;
item.quantity = item.quantity ?? 0;
item.currency = item.currency || 'RUB';
item.imgs = item.imgs || [];
item.tags = item.tags || [];
item.description = item.description || [];
item.simpleDescription = item.simpleDescription || '';
return item;
}
/** Normalize a category — merges names[] into translations, maps Go struct fields */
private normalizeCategory(raw: any): Category {
const cat: Category = { ...raw };
if (raw.names && Array.isArray(raw.names)) {
cat.translations = cat.translations || {};
for (const n of raw.names) {
const lang = n.language?.toLowerCase();
const val = this.nameValue(n);
if (lang && val) {
cat.translations[lang] = cat.translations[lang] || {};
cat.translations[lang].name = val;
}
}
}
// Map Go struct fields
if (raw.icon && !cat.img) cat.img = raw.icon;
if (raw.wideicon) cat.wideBanner = raw.wideicon;
if (raw.ItemsCount != null) cat.itemCount = raw.ItemsCount;
if (raw.CategoriesCount != null) cat.categoriesCount = raw.CategoriesCount;
return cat;
}
// Projects
getProjects(): Observable<Project[]> {
if (environment.useMockData) return this.mockService.getProjects();
@@ -46,16 +149,18 @@ export class ApiService {
// Categories
getCategories(projectId: string): Observable<Category[]> {
if (environment.useMockData) return this.mockService.getCategories(projectId);
return this.http.get<Category[]>(`${this.API_BASE}/projects/${projectId}/categories`).pipe(
return this.http.get<any[]>(`${this.API_BASE}/projects/${projectId}/categories`).pipe(
retry(2),
map(cats => cats.map(c => this.normalizeCategory(c))),
catchError(this.handleError)
);
}
getCategory(categoryId: string): Observable<Category> {
if (environment.useMockData) return this.mockService.getCategory(categoryId);
return this.http.get<Category>(`${this.API_BASE}/categories/${categoryId}`).pipe(
return this.http.get<any>(`${this.API_BASE}/categories/${categoryId}`).pipe(
retry(2),
map(c => this.normalizeCategory(c)),
catchError(this.handleError)
);
}
@@ -148,16 +253,21 @@ export class ApiService {
params = params.set('tags', filters.tags.join(','));
}
return this.http.get<ItemsListResponse>(`${this.API_BASE}/subcategories/${subcategoryId}/items`, { params }).pipe(
return this.http.get<any>(`${this.API_BASE}/subcategories/${subcategoryId}/items`, { params }).pipe(
retry(2),
map(resp => ({
...resp,
items: (resp.items || []).map((i: any) => this.normalizeItem(i))
})),
catchError(this.handleError)
);
}
getItem(itemId: string): Observable<Item> {
if (environment.useMockData) return this.mockService.getItem(itemId);
return this.http.get<Item>(`${this.API_BASE}/items/${itemId}`).pipe(
return this.http.get<any>(`${this.API_BASE}/items/${itemId}`).pipe(
retry(2),
map(raw => this.normalizeItem(raw)),
catchError(this.handleError)
);
}