import { HttpInterceptorFn, HttpResponse } from '@angular/common/http'; import { of, delay } from 'rxjs'; import { environment } from '../../environments/environment'; // ─── Mock Categories (backOffice format: string IDs, img, subcategories, visible) ─── const MOCK_CATEGORIES = [ { id: 'electronics', categoryID: 1, name: 'Электроника', parentID: 0, visible: true, priority: 1, img: 'https://images.unsplash.com/photo-1498049794561-7780e7231661?w=400&h=300&fit=crop', icon: 'https://images.unsplash.com/photo-1498049794561-7780e7231661?w=400&h=300&fit=crop', projectId: 'dexar', itemCount: 15, subcategories: [ { id: 'smartphones', name: 'Смартфоны', visible: true, priority: 1, img: 'https://images.unsplash.com/photo-1511707171634-5f897ff02aa9?w=400&h=300&fit=crop', categoryId: 'electronics', parentId: 'electronics', itemCount: 8, hasItems: true, subcategories: [] }, { id: 'laptops', name: 'Ноутбуки', visible: true, priority: 2, img: 'https://images.unsplash.com/photo-1496181133206-80ce9b88a853?w=400&h=300&fit=crop', categoryId: 'electronics', parentId: 'electronics', itemCount: 6, hasItems: true, subcategories: [] } ] }, { id: 'clothing', categoryID: 2, name: 'Одежда', parentID: 0, visible: true, priority: 2, img: 'https://images.unsplash.com/photo-1441986300917-64674bd600d8?w=400&h=300&fit=crop', icon: 'https://images.unsplash.com/photo-1441986300917-64674bd600d8?w=400&h=300&fit=crop', projectId: 'dexar', itemCount: 25, subcategories: [ { id: 'mens', name: 'Мужская', visible: true, priority: 1, img: 'https://images.unsplash.com/photo-1490578474895-699cd4e2cf59?w=400&h=300&fit=crop', categoryId: 'clothing', parentId: 'clothing', itemCount: 12, hasItems: true, subcategories: [] }, { id: 'womens', name: 'Женская', visible: true, priority: 2, img: 'https://images.unsplash.com/photo-1487222477894-8943e31ef7b2?w=400&h=300&fit=crop', categoryId: 'clothing', parentId: 'clothing', itemCount: 13, hasItems: true, subcategories: [] } ] }, { id: 'home', categoryID: 3, name: 'Дом и сад', parentID: 0, visible: true, priority: 3, img: 'https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=400&h=300&fit=crop', icon: 'https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=400&h=300&fit=crop', projectId: 'dexar', itemCount: 8, subcategories: [] }, // Subcategories as flat entries (for the legacy flat category list) { id: 'smartphones', categoryID: 11, name: 'Смартфоны', parentID: 1, visible: true, priority: 1, img: 'https://images.unsplash.com/photo-1511707171634-5f897ff02aa9?w=400&h=300&fit=crop', icon: 'https://images.unsplash.com/photo-1511707171634-5f897ff02aa9?w=400&h=300&fit=crop', itemCount: 8 }, { id: 'laptops', categoryID: 12, name: 'Ноутбуки', parentID: 1, visible: true, priority: 2, img: 'https://images.unsplash.com/photo-1496181133206-80ce9b88a853?w=400&h=300&fit=crop', icon: 'https://images.unsplash.com/photo-1496181133206-80ce9b88a853?w=400&h=300&fit=crop', itemCount: 6 }, { id: 'mens', categoryID: 21, name: 'Мужская одежда', parentID: 2, visible: true, priority: 1, img: 'https://images.unsplash.com/photo-1490578474895-699cd4e2cf59?w=400&h=300&fit=crop', icon: 'https://images.unsplash.com/photo-1490578474895-699cd4e2cf59?w=400&h=300&fit=crop', itemCount: 12 }, { id: 'womens', categoryID: 22, name: 'Женская одежда', parentID: 2, visible: true, priority: 2, img: 'https://images.unsplash.com/photo-1487222477894-8943e31ef7b2?w=400&h=300&fit=crop', icon: 'https://images.unsplash.com/photo-1487222477894-8943e31ef7b2?w=400&h=300&fit=crop', itemCount: 13 } ]; // ─── Mock Items (backOffice format with ALL fields) ─── const MOCK_ITEMS: any[] = [ { id: 'iphone15', itemID: 101, name: 'iPhone 15 Pro Max', visible: true, priority: 1, quantity: 50, price: 149990, discount: 0, currency: 'RUB', rating: 4.8, remainings: 'high', categoryID: 11, imgs: [ 'https://images.unsplash.com/photo-1695048133142-1a20484d2569?w=600&h=400&fit=crop', 'https://images.unsplash.com/photo-1592750475338-74b7b21085ab?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1695048133142-1a20484d2569?w=600&h=400&fit=crop' }, { url: 'https://images.unsplash.com/photo-1592750475338-74b7b21085ab?w=600&h=400&fit=crop' } ], tags: ['new', 'featured', 'apple'], badges: ['new', 'bestseller'], colour: 'Натуральный титан', size: '', names: [ { language: 'ru', value: 'iPhone 15 Pro Max' }, { language: 'en', value: 'iPhone 15 Pro Max' }, { language: 'hy', value: 'iPhone 15 Pro Max' } ], descriptions: [ { language: 'ru', value: 'Новейший iPhone с титановым корпусом и чипом A17 Pro' }, { language: 'en', value: 'Latest iPhone with titanium body and A17 Pro chip' } ], attributes: [ { key: 'Цвет', value: 'Натуральный титан' }, { key: 'Память', value: '256 ГБ' }, { key: 'Процессор', value: 'A17 Pro' } ], simpleDescription: 'Новейший iPhone с титановым корпусом и чипом A17 Pro', description: [ { key: 'Цвет', value: 'Натуральный титан' }, { key: 'Память', value: '256 ГБ' }, { key: 'Дисплей', value: '6.7" Super Retina XDR' }, { key: 'Процессор', value: 'A17 Pro' }, { key: 'Камера', value: '48 Мп основная' }, { key: 'Аккумулятор', value: '4441 мАч' } ], descriptionFields: [ { key: 'Цвет', value: 'Натуральный титан' }, { key: 'Память', value: '256 ГБ' }, { key: 'Дисплей', value: '6.7" Super Retina XDR' }, { key: 'Процессор', value: 'A17 Pro' }, { key: 'Камера', value: '48 Мп основная' }, { key: 'Аккумулятор', value: '4441 мАч' } ], subcategoryId: 'smartphones', translations: { en: { name: 'iPhone 15 Pro Max', simpleDescription: 'Latest iPhone with titanium body and A17 Pro chip', description: [ { key: 'Color', value: 'Natural Titanium' }, { key: 'Storage', value: '256GB' }, { key: 'Display', value: '6.7" Super Retina XDR' }, { key: 'Chip', value: 'A17 Pro' }, { key: 'Camera', value: '48MP main' }, { key: 'Battery', value: '4441 mAh' } ] } }, comments: [ { id: 'c1', text: 'Отличный телефон! Камера просто огонь 🔥', author: 'Иван Петров', stars: 5, createdAt: '2025-12-15T10:30:00Z' }, { id: 'c2', text: 'Батарея держит весь день, очень доволен.', author: 'Мария Козлова', stars: 4, createdAt: '2026-01-05T14:20:00Z' } ], callbacks: [ { rating: 5, content: 'Отличный телефон! Камера просто огонь 🔥', userID: 'Иван Петров', timestamp: '2025-12-15T10:30:00Z' }, { rating: 4, content: 'Батарея держит весь день, очень доволен.', userID: 'Мария Козлова', timestamp: '2026-01-05T14:20:00Z' } ], questions: [] }, { id: 'samsung-s24', itemID: 102, name: 'Samsung Galaxy S24 Ultra', visible: true, priority: 2, quantity: 35, price: 129990, discount: 10, currency: 'RUB', rating: 4.6, remainings: 'high', categoryID: 11, imgs: [ 'https://images.unsplash.com/photo-1610945415295-d9bbf067e59c?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1610945415295-d9bbf067e59c?w=600&h=400&fit=crop' } ], tags: ['new', 'android', 'samsung'], badges: ['new', 'sale'], colour: 'Титановый серый', size: '', names: [ { language: 'ru', value: 'Samsung Galaxy S24 Ultra' }, { language: 'en', value: 'Samsung Galaxy S24 Ultra' } ], descriptions: [ { language: 'ru', value: 'Премиальный флагман Samsung с S Pen' }, { language: 'en', value: 'Premium Samsung flagship with S Pen' } ], attributes: [ { key: 'Память', value: '512 ГБ' }, { key: 'ОЗУ', value: '12 ГБ' } ], simpleDescription: 'Премиальный флагман Samsung с S Pen', description: [ { key: 'Цвет', value: 'Титановый серый' }, { key: 'Память', value: '512 ГБ' }, { key: 'ОЗУ', value: '12 ГБ' }, { key: 'Дисплей', value: '6.8" Dynamic AMOLED 2X' } ], descriptionFields: [ { key: 'Цвет', value: 'Титановый серый' }, { key: 'Память', value: '512 ГБ' }, { key: 'ОЗУ', value: '12 ГБ' }, { key: 'Дисплей', value: '6.8" Dynamic AMOLED 2X' } ], subcategoryId: 'smartphones', translations: { en: { name: 'Samsung Galaxy S24 Ultra', simpleDescription: 'Premium Samsung flagship with S Pen', description: [ { key: 'Color', value: 'Titanium Gray' }, { key: 'Storage', value: '512GB' }, { key: 'RAM', value: '12GB' }, { key: 'Display', value: '6.8" Dynamic AMOLED 2X' } ] } }, comments: [ { id: 'c3', text: 'S Pen — топ, использую каждый день.', author: 'Алексей', stars: 5, createdAt: '2026-01-20T08:10:00Z' } ], callbacks: [ { rating: 5, content: 'S Pen — топ, использую каждый день.', userID: 'Алексей', timestamp: '2026-01-20T08:10:00Z' } ], questions: [] }, { id: 'pixel-8', itemID: 103, name: 'Google Pixel 8 Pro', visible: true, priority: 3, quantity: 20, price: 89990, discount: 15, currency: 'RUB', rating: 4.5, remainings: 'medium', categoryID: 11, imgs: [ 'https://images.unsplash.com/photo-1598327105666-5b89351aff97?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1598327105666-5b89351aff97?w=600&h=400&fit=crop' } ], tags: ['sale', 'android', 'ai', 'google'], badges: ['sale', 'hot'], simpleDescription: 'Лучший смартфон для ИИ-фотографии', description: [ { key: 'Цвет', value: 'Bay Blue' }, { key: 'Память', value: '256 ГБ' }, { key: 'Процессор', value: 'Tensor G3' } ], descriptionFields: [ { key: 'Цвет', value: 'Bay Blue' }, { key: 'Память', value: '256 ГБ' }, { key: 'Процессор', value: 'Tensor G3' } ], subcategoryId: 'smartphones', translations: {}, comments: [], callbacks: [], questions: [ { question: 'Поддерживает eSIM?', answer: 'Да, поддерживает dual eSIM.', upvotes: 12, downvotes: 0 } ] }, { id: 'macbook-pro', itemID: 104, name: 'MacBook Pro 16" M3 Max', visible: true, priority: 1, quantity: 15, price: 299990, discount: 0, currency: 'RUB', rating: 4.9, remainings: 'low', categoryID: 12, imgs: [ 'https://images.unsplash.com/photo-1517336714731-489689fd1ca8?w=600&h=400&fit=crop', 'https://images.unsplash.com/photo-1541807084-5c52b6b3adef?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1517336714731-489689fd1ca8?w=600&h=400&fit=crop' }, { url: 'https://images.unsplash.com/photo-1541807084-5c52b6b3adef?w=600&h=400&fit=crop' } ], tags: ['featured', 'professional', 'apple'], badges: ['exclusive', 'limited'], simpleDescription: 'Мощный ноутбук для профессионалов', description: [ { key: 'Процессор', value: 'Apple M3 Max' }, { key: 'ОЗУ', value: '36 ГБ' }, { key: 'Память', value: '1 ТБ SSD' }, { key: 'Дисплей', value: '16.2" Liquid Retina XDR' }, { key: 'Батарея', value: 'До 22 ч' } ], descriptionFields: [ { key: 'Процессор', value: 'Apple M3 Max' }, { key: 'ОЗУ', value: '36 ГБ' }, { key: 'Память', value: '1 ТБ SSD' }, { key: 'Дисплей', value: '16.2" Liquid Retina XDR' }, { key: 'Батарея', value: 'До 22 ч' } ], subcategoryId: 'laptops', translations: { en: { name: 'MacBook Pro 16" M3 Max', simpleDescription: 'Powerful laptop for professionals', description: [ { key: 'Chip', value: 'Apple M3 Max' }, { key: 'RAM', value: '36GB' }, { key: 'Storage', value: '1TB SSD' }, { key: 'Display', value: '16.2" Liquid Retina XDR' }, { key: 'Battery', value: 'Up to 22h' } ] } }, comments: [ { id: 'c4', text: 'Невероятная производительность. Рендер в 3 раза быстрее.', author: 'Дизайнер Про', stars: 5, createdAt: '2025-11-15T12:00:00Z' }, { id: 'c5', text: 'Стоит каждого рубля. Экран — сказка.', author: 'Видеоредактор', stars: 5, createdAt: '2026-02-01T09:00:00Z' } ], callbacks: [ { rating: 5, content: 'Невероятная производительность. Рендер в 3 раза быстрее.', userID: 'Дизайнер Про', timestamp: '2025-11-15T12:00:00Z' }, { rating: 5, content: 'Стоит каждого рубля. Экран — сказка.', userID: 'Видеоредактор', timestamp: '2026-02-01T09:00:00Z' } ], questions: [] }, { id: 'dell-xps', itemID: 105, name: 'Dell XPS 15', visible: true, priority: 2, quantity: 3, price: 179990, discount: 5, currency: 'RUB', rating: 4.3, remainings: 'low', categoryID: 12, imgs: [ 'https://images.unsplash.com/photo-1593642702749-b7d2a804c22e?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1593642702749-b7d2a804c22e?w=600&h=400&fit=crop' } ], tags: ['windows', 'professional'], badges: ['limited'], simpleDescription: 'Тонкий и мощный Windows ноутбук', description: [ { key: 'Процессор', value: 'Intel Core i9-13900H' }, { key: 'ОЗУ', value: '32 ГБ' }, { key: 'Дисплей', value: '15.6" OLED 3.5K' } ], descriptionFields: [ { key: 'Процессор', value: 'Intel Core i9-13900H' }, { key: 'ОЗУ', value: '32 ГБ' }, { key: 'Дисплей', value: '15.6" OLED 3.5K' } ], subcategoryId: 'laptops', translations: {}, comments: [], callbacks: [], questions: [] }, { id: 'jacket-leather', itemID: 201, name: 'Кожаная куртка Premium', visible: true, priority: 1, quantity: 8, price: 34990, discount: 20, currency: 'RUB', rating: 4.7, remainings: 'medium', categoryID: 21, imgs: [ 'https://images.unsplash.com/photo-1551028719-00167b16eac5?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1551028719-00167b16eac5?w=600&h=400&fit=crop' } ], tags: ['leather', 'premium', 'winter'], badges: ['sale', 'bestseller'], simpleDescription: 'Стильная мужская кожаная куртка из натуральной кожи', description: [ { key: 'Материал', value: 'Натуральная кожа' }, { key: 'Размеры', value: 'S, M, L, XL, XXL' }, { key: 'Цвет', value: 'Чёрный' }, { key: 'Подкладка', value: 'Полиэстер 100%' } ], descriptionFields: [ { key: 'Материал', value: 'Натуральная кожа' }, { key: 'Размеры', value: 'S, M, L, XL, XXL' }, { key: 'Цвет', value: 'Чёрный' }, { key: 'Подкладка', value: 'Полиэстер 100%' } ], subcategoryId: 'mens', translations: { en: { name: 'Premium Leather Jacket', simpleDescription: 'Stylish men\'s genuine leather jacket', description: [ { key: 'Material', value: 'Genuine Leather' }, { key: 'Sizes', value: 'S, M, L, XL, XXL' }, { key: 'Color', value: 'Black' }, { key: 'Lining', value: '100% Polyester' } ] } }, comments: [ { id: 'c6', text: 'Качество кожи отличное, сидит идеально.', author: 'Антон', stars: 5, createdAt: '2026-01-10T16:30:00Z' } ], callbacks: [ { rating: 5, content: 'Качество кожи отличное, сидит идеально.', userID: 'Антон', timestamp: '2026-01-10T16:30:00Z' } ], questions: [] }, { id: 'dress-silk', itemID: 202, name: 'Шёлковое платье Elegance', visible: true, priority: 1, quantity: 12, price: 18990, discount: 0, currency: 'RUB', rating: 4.9, remainings: 'high', categoryID: 22, imgs: [ 'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=600&h=400&fit=crop' } ], tags: ['silk', 'elegant', 'new'], badges: ['new', 'featured'], simpleDescription: 'Элегантное шёлковое платье для особых случаев', description: [ { key: 'Материал', value: '100% Шёлк' }, { key: 'Размеры', value: 'XS, S, M, L' }, { key: 'Цвет', value: 'Бордовый' }, { key: 'Длина', value: 'Миди' } ], descriptionFields: [ { key: 'Материал', value: '100% Шёлк' }, { key: 'Размеры', value: 'XS, S, M, L' }, { key: 'Цвет', value: 'Бордовый' }, { key: 'Длина', value: 'Миди' } ], subcategoryId: 'womens', translations: {}, comments: [ { id: 'c7', text: 'Восхитительное платье! Ткань потрясающая.', author: 'Елена', stars: 5, createdAt: '2026-02-14T20:00:00Z' }, { id: 'c8', text: 'Идеально на вечер. Рекомендую!', author: 'Наталья', stars: 5, createdAt: '2026-02-10T11:00:00Z' } ], callbacks: [ { rating: 5, content: 'Восхитительное платье! Ткань потрясающая.', userID: 'Елена', timestamp: '2026-02-14T20:00:00Z' }, { rating: 5, content: 'Идеально на вечер. Рекомендую!', userID: 'Наталья', timestamp: '2026-02-10T11:00:00Z' } ], questions: [] }, { id: 'hoodie-basic', itemID: 203, name: 'Худи Oversize Basic', visible: true, priority: 3, quantity: 45, price: 5990, discount: 0, currency: 'RUB', rating: 4.2, remainings: 'high', categoryID: 21, imgs: [ 'https://images.unsplash.com/photo-1556821840-3a63f95609a7?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1556821840-3a63f95609a7?w=600&h=400&fit=crop' } ], tags: ['casual', 'basic'], badges: [], simpleDescription: 'Удобное худи свободного кроя на каждый день', description: [ { key: 'Материал', value: 'Хлопок 80%, Полиэстер 20%' }, { key: 'Размеры', value: 'S, M, L, XL' }, { key: 'Цвет', value: 'Серый меланж' } ], descriptionFields: [ { key: 'Материал', value: 'Хлопок 80%, Полиэстер 20%' }, { key: 'Размеры', value: 'S, M, L, XL' }, { key: 'Цвет', value: 'Серый меланж' } ], subcategoryId: 'mens', translations: {}, comments: [], callbacks: [], questions: [] }, { id: 'sneakers-run', itemID: 204, name: 'Кроссовки AirPulse Run', visible: true, priority: 2, quantity: 0, price: 12990, discount: 30, currency: 'RUB', rating: 4.4, remainings: 'out', categoryID: 21, imgs: [ 'https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=600&h=400&fit=crop' } ], tags: ['sport', 'running'], badges: ['sale', 'hot'], simpleDescription: 'Лёгкие беговые кроссовки с пенной амортизацией', description: [ { key: 'Верх', value: 'Текстильная сетка' }, { key: 'Подошва', value: 'Пена EVA' }, { key: 'Вес', value: '260 г' } ], descriptionFields: [ { key: 'Верх', value: 'Текстильная сетка' }, { key: 'Подошва', value: 'Пена EVA' }, { key: 'Вес', value: '260 г' } ], subcategoryId: 'mens', translations: {}, comments: [ { id: 'c9', text: 'Нет в наличии уже месяц... Верните!', author: 'Бегун42', stars: 3, createdAt: '2026-02-05T07:00:00Z' } ], callbacks: [ { rating: 3, content: 'Нет в наличии уже месяц... Верните!', userID: 'Бегун42', timestamp: '2026-02-05T07:00:00Z' } ], questions: [] }, { id: 'lamp-smart', itemID: 301, name: 'Умная лампа Homelight Pro', visible: true, priority: 1, quantity: 100, price: 3990, discount: 0, currency: 'RUB', rating: 4.1, remainings: 'high', categoryID: 3, imgs: [ 'https://images.unsplash.com/photo-1507473885765-e6ed057ab6fe?w=600&h=400&fit=crop' ], photos: [ { url: 'https://images.unsplash.com/photo-1507473885765-e6ed057ab6fe?w=600&h=400&fit=crop' } ], tags: ['smart-home', 'lighting'], badges: ['featured'], simpleDescription: 'Wi-Fi лампа с управлением через приложение и голосом', description: [ { key: 'Яркость', value: '1100 лм' }, { key: 'Цветовая t°', value: '2700K–6500K' }, { key: 'Совместимость', value: 'Алиса, Google Home, Alexa' } ], descriptionFields: [ { key: 'Яркость', value: '1100 лм' }, { key: 'Цветовая t°', value: '2700K–6500K' }, { key: 'Совместимость', value: 'Алиса, Google Home, Alexa' } ], subcategoryId: 'home', translations: {}, comments: [], callbacks: [], questions: [] } ]; // ─── Helper ─── function getAllVisibleItems(): any[] { return MOCK_ITEMS.filter(i => i.visible !== false); } function getItemsByCategoryId(categoryID: number | string): any[] { return getAllVisibleItems().filter(i => i.categoryID === categoryID || i.subcategoryId === categoryID ); } function respond(body: T, delayMs = 150) { return of(new HttpResponse({ status: 200, body })).pipe(delay(delayMs)); } // ─── Mock Auth State ─── let mockQrPollCount = 0; // ─── The Interceptor ─── export const mockDataInterceptor: HttpInterceptorFn = (req, next) => { if (!(environment as any).useMockData) { return next(req); } const url = req.url; // ── GET /ping if (url.endsWith('/ping') && req.method === 'GET') { return respond({ message: 'pong (mock)' }); } // ── GET /auth/session if (url.includes('/auth/session') && req.method === 'GET') { return respond({ active: false }, 100); } // ── POST /auth/qr/create if (url.includes('/auth/qr/create') && req.method === 'POST') { const token = 'mock-qr-token-' + Date.now(); const botUsername = (environment as Record)['telegramBot'] as string || 'DexarSupport_bot'; mockQrPollCount = 0; return respond({ token, url: `https://t.me/${botUsername}?start=qr_${token}` }, 200); } // ── GET /auth/qr/poll if (url.includes('/auth/qr/poll') && req.method === 'GET') { mockQrPollCount++; // Simulate confirmed after 3 polls (~9 seconds) if (mockQrPollCount >= 3) { return respond({ status: 'confirmed', session: { sessionId: 'mock-session-' + Date.now(), active: true, displayName: 'Telegram User', expiresAt: new Date(Date.now() + 3600000).toISOString() } }, 200); } return respond({ status: 'pending' }, 200); } // ── GET /category (all categories flat list) if (url.endsWith('/category') && req.method === 'GET') { return respond(MOCK_CATEGORIES); } // ── GET /category/:id (items for a category) const catItemsMatch = url.match(/\/category\/([^/?]+)$/); if (catItemsMatch && req.method === 'GET') { const raw = catItemsMatch[1]; const num = Number(raw); const catId = Number.isFinite(num) ? num : raw; const items = getItemsByCategoryId(catId); return respond(items); } // ── GET /item/:id const itemMatch = url.match(/\/item\/([^/?]+)$/); if (itemMatch && req.method === 'GET') { const raw = itemMatch[1]; const num = Number(raw); const item = MOCK_ITEMS.find(i => Number.isFinite(num) ? i.itemID === num : i.id === raw ); if (item) { return respond(item); } return of(new HttpResponse({ status: 404, body: { error: 'Item not found' } })).pipe(delay(100)); } // ── GET /searchitems?search=... if (url.includes('/searchitems') && req.method === 'GET') { const search = req.params.get('search')?.toLowerCase() || ''; const items = getAllVisibleItems().filter(i => i.name.toLowerCase().includes(search) || i.simpleDescription?.toLowerCase().includes(search) || i.tags?.some((t: string) => t.toLowerCase().includes(search)) ); return respond({ items, total: items.length, count: items.length, skip: 0 }); } // ── GET /randomitems if (url.includes('/randomitems') && req.method === 'GET') { const count = parseInt(req.params.get('count') || '5', 10); const shuffled = [...getAllVisibleItems()].sort(() => Math.random() - 0.5); return respond(shuffled.slice(0, count)); } // ── GET /cart (return empty) if (url.endsWith('/cart') && req.method === 'GET') { return respond([]); } // ── POST /websession/:id (add to cart) if (url.match(/\/websession\/[^/]+$/) && req.method === 'POST') { return respond({ sessionId: 'mock-session', Status: true, cart: req.body }); } // ── POST /websession/:id/qr (create payment QR) if (url.match(/\/websession\/[^/]+\/qr$/) && req.method === 'POST') { return respond({ qrId: 'mock-qr-' + Date.now(), qrStatus: 'NEW', qrExpirationDate: new Date(Date.now() + 180000).toISOString(), Payload: 'https://example.com/pay/mock', qrUrl: 'https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=mock-payment' }, 300); } // ── POST /items/:id/callback (review) if (url.match(/\/items\/\d+\/callback$/) && req.method === 'POST') { return respond({ message: 'Review submitted (mock)' }, 200); } // ── POST /purchase-email if (url.endsWith('/purchase-email') && req.method === 'POST') { return respond({ message: 'Email sent (mock)' }, 200); } // ── GET /websession/:id/:qrId (check QR payment status) if (url.match(/\/websession\/[^/]+\/[^/]+$/) && !url.match(/\/websession\/[^/]+\/qr$/) && req.method === 'GET') { return respond({ paymentStatus: 'SUCCESS', code: 'SUCCESS', amount: 0, currency: 'RUB', qrId: 'mock', transactionId: 999, transactionDate: new Date().toISOString(), additionalInfo: '', paymentPurpose: '', createDate: new Date().toISOString(), order: 'mock-order', qrExpirationDate: new Date().toISOString() }, 500); } // Fallback — pass through return next(req); };