optimising and making it better
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Component, computed, ChangeDetectionStrategy, signal, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Component, computed, ChangeDetectionStrategy, signal, OnDestroy } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
@@ -17,7 +17,7 @@ import { getDiscountedPrice, getMainImage, trackByItemId } from '../../utils/ite
|
||||
styleUrls: ['./cart.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class CartComponent implements OnInit, OnDestroy {
|
||||
export class CartComponent implements OnDestroy {
|
||||
items;
|
||||
itemCount;
|
||||
totalPrice;
|
||||
@@ -59,10 +59,6 @@ export class CartComponent implements OnInit, OnDestroy {
|
||||
this.totalPrice = this.cartService.totalPrice;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// Component initialized
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.stopPolling();
|
||||
if (this.closeTimeout) {
|
||||
@@ -109,16 +105,16 @@ export class CartComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
|
||||
const cleanup = () => {
|
||||
document.removeEventListener('touchmove', onMove as any);
|
||||
document.removeEventListener('touchmove', onMove);
|
||||
document.removeEventListener('touchend', cleanup);
|
||||
};
|
||||
|
||||
document.addEventListener('touchmove', onMove as any);
|
||||
document.addEventListener('touchmove', onMove);
|
||||
document.addEventListener('touchend', cleanup);
|
||||
}
|
||||
|
||||
clearCart(): void {
|
||||
if (confirm('<EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?')) {
|
||||
if (confirm('Вы уверены, что хотите очистить корзину?')) {
|
||||
this.cartService.clearCart();
|
||||
}
|
||||
}
|
||||
@@ -129,7 +125,7 @@ export class CartComponent implements OnInit, OnDestroy {
|
||||
|
||||
checkout(): void {
|
||||
if (!this.termsAccepted) {
|
||||
alert('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.');
|
||||
alert('Пожалуйста, примите условия оферты, политику возврата и возврата для подтверждения оформления заказа.');
|
||||
return;
|
||||
}
|
||||
this.openPaymentPopup();
|
||||
@@ -251,7 +247,7 @@ export class CartComponent implements OnInit, OnDestroy {
|
||||
this.linkCopied.set(true);
|
||||
setTimeout(() => this.linkCopied.set(false), 2000);
|
||||
}).catch(err => {
|
||||
console.error('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:', err);
|
||||
console.error('Ошибка копирования:', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -316,7 +312,7 @@ export class CartComponent implements OnInit, OnDestroy {
|
||||
next: () => {
|
||||
this.emailSubmitting.set(false);
|
||||
// Show success message
|
||||
alert('Email <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>! <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>.');
|
||||
alert('Email успешно отправлен! Проверьте свою почту.');
|
||||
// Close popup and redirect to home page
|
||||
setTimeout(() => {
|
||||
this.closePaymentPopup();
|
||||
@@ -326,7 +322,7 @@ export class CartComponent implements OnInit, OnDestroy {
|
||||
error: (err) => {
|
||||
console.error('Error submitting email:', err);
|
||||
this.emailSubmitting.set(false);
|
||||
alert('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> email. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>.');
|
||||
alert('Произошла ошибка при отправке email. Пожалуйста, попробуйте снова.');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -387,11 +383,11 @@ export class CartComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
if (digitsOnly.length === 0) {
|
||||
this.phoneError.set('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>');
|
||||
this.phoneError.set('Номер телефона обязателен');
|
||||
} else if (digitsOnly.length < 11) {
|
||||
this.phoneError.set(`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> ${11 - digitsOnly.length} <EFBFBD><EFBFBD><EFBFBD><EFBFBD>`);
|
||||
this.phoneError.set(`Введите ещё ${11 - digitsOnly.length} цифр`);
|
||||
} else if (digitsOnly.length > 11) {
|
||||
this.phoneError.set('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>');
|
||||
this.phoneError.set('Слишком много цифр');
|
||||
} else {
|
||||
this.phoneError.set('');
|
||||
}
|
||||
@@ -419,19 +415,19 @@ export class CartComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
if (email.length === 0) {
|
||||
this.emailError.set('Email <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>');
|
||||
this.emailError.set('Email обязателен');
|
||||
} else if (email.length < 5) {
|
||||
this.emailError.set('Email <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 5 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)');
|
||||
this.emailError.set('Email слишком короткий (минимум 5 символов)');
|
||||
} else if (email.length > 100) {
|
||||
this.emailError.set('Email <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 100 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)');
|
||||
this.emailError.set('Email слишком длинный (максимум 100 символов)');
|
||||
} else if (!email.includes('@')) {
|
||||
this.emailError.set('Email <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> @');
|
||||
this.emailError.set('Email должен содержать @');
|
||||
} else if (!email.includes('.')) {
|
||||
this.emailError.set('Email <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> (.com, .ru <EFBFBD> <20>.<2E>.)');
|
||||
this.emailError.set('Email должен содержать домен (.com, .ru и т.д.)');
|
||||
} else {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
this.emailError.set('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> email');
|
||||
this.emailError.set('Некорректный формат email');
|
||||
} else {
|
||||
this.emailError.set('');
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export class CategoryComponent implements OnInit, OnDestroy {
|
||||
private readonly count = 20;
|
||||
private isLoadingMore = false;
|
||||
private routeSubscription?: Subscription;
|
||||
private scrollTimeout?: ReturnType<typeof setTimeout>;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
@@ -41,6 +42,7 @@ export class CategoryComponent implements OnInit, OnDestroy {
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.routeSubscription?.unsubscribe();
|
||||
if (this.scrollTimeout) clearTimeout(this.scrollTimeout);
|
||||
}
|
||||
|
||||
resetAndLoad(): void {
|
||||
@@ -80,8 +82,6 @@ export class CategoryComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private scrollTimeout: any;
|
||||
|
||||
@HostListener('window:scroll')
|
||||
onScroll(): void {
|
||||
if (this.scrollTimeout) clearTimeout(this.scrollTimeout);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Component, OnInit, signal, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, signal, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||
import { ApiService } from '../../services';
|
||||
import { Category } from '../../models';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-subcategories',
|
||||
@@ -10,13 +11,15 @@ import { Category } from '../../models';
|
||||
styleUrls: ['./subcategories.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class SubcategoriesComponent implements OnInit {
|
||||
export class SubcategoriesComponent implements OnInit, OnDestroy {
|
||||
categories = signal<Category[]>([]);
|
||||
subcategories = signal<Category[]>([]);
|
||||
loading = signal(true);
|
||||
error = signal<string | null>(null);
|
||||
parentName = signal<string>('');
|
||||
|
||||
private routeSubscription?: Subscription;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
@@ -24,12 +27,16 @@ export class SubcategoriesComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.params.subscribe(params => {
|
||||
this.routeSubscription = this.route.params.subscribe(params => {
|
||||
const id = parseInt(params['id'], 10);
|
||||
this.loadForParent(id);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.routeSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
private loadForParent(parentID: number): void {
|
||||
this.loading.set(true);
|
||||
this.apiService.getCategories().subscribe({
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
class="dexar-category-card"
|
||||
[class.dexar-category-card--wide]="isWideCategory(category.categoryID)">
|
||||
<div class="dexar-category-image">
|
||||
@if (isWideCategory(category.categoryID) && category.wideBanner && category.wideBanner !== true) {
|
||||
@if (isWideCategory(category.categoryID) && category.wideBanner) {
|
||||
<img [src]="category.wideBanner" [alt]="category.name" loading="lazy" decoding="async" />
|
||||
} @else if (category.icon) {
|
||||
<img [src]="category.icon" [alt]="category.name" loading="lazy" decoding="async" />
|
||||
|
||||
@@ -87,12 +87,6 @@ export class HomeComponent implements OnInit {
|
||||
topLevel.forEach(cat => {
|
||||
if (!cat.wideBanner) return;
|
||||
|
||||
// API may send wideBanner as a boolean flag instead of a URL
|
||||
if (cat.wideBanner === true) {
|
||||
this.wideCategories.update(set => { const next = new Set(set); next.add(cat.categoryID); return next; });
|
||||
return;
|
||||
}
|
||||
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
const ratio = img.naturalWidth / img.naturalHeight;
|
||||
@@ -104,7 +98,7 @@ export class HomeComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
};
|
||||
img.src = cat.wideBanner as string;
|
||||
img.src = cat.wideBanner;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-about',
|
||||
imports: [],
|
||||
templateUrl: './about.component.html',
|
||||
styleUrls: ['./about.component.scss']
|
||||
styleUrls: ['./about.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AboutComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contacts',
|
||||
imports: [],
|
||||
templateUrl: './contacts.component.html',
|
||||
styleUrls: ['./contacts.component.scss']
|
||||
styleUrls: ['./contacts.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ContactsComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-delivery',
|
||||
imports: [],
|
||||
templateUrl: './delivery.component.html',
|
||||
styleUrls: ['./delivery.component.scss']
|
||||
styleUrls: ['./delivery.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DeliveryComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-faq',
|
||||
imports: [],
|
||||
templateUrl: './faq.component.html',
|
||||
styleUrls: ['./faq.component.scss']
|
||||
styleUrls: ['./faq.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class FaqComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-guarantee',
|
||||
imports: [],
|
||||
templateUrl: './guarantee.component.html',
|
||||
styleUrls: ['./guarantee.component.scss']
|
||||
styleUrls: ['./guarantee.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class GuaranteeComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { Component, OnInit, OnDestroy, signal, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, signal, ChangeDetectionStrategy, inject } from '@angular/core';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { ApiService, CartService, TelegramService } from '../../services';
|
||||
import { ApiService, CartService, TelegramService, SeoService } from '../../services';
|
||||
import { Item } from '../../models';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { SecurityContext } from '@angular/core';
|
||||
import { getDiscountedPrice } from '../../utils/item.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-item-detail',
|
||||
@@ -31,6 +33,11 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
reviewSubmitStatus = signal<'idle' | 'loading' | 'success' | 'error'>('idle');
|
||||
|
||||
private routeSubscription?: Subscription;
|
||||
private reviewResetTimeout?: ReturnType<typeof setTimeout>;
|
||||
private reviewErrorTimeout?: ReturnType<typeof setTimeout>;
|
||||
private reloadTimeout?: ReturnType<typeof setTimeout>;
|
||||
|
||||
private seoService = inject(SeoService);
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
@@ -49,6 +56,10 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.routeSubscription?.unsubscribe();
|
||||
if (this.reviewResetTimeout) clearTimeout(this.reviewResetTimeout);
|
||||
if (this.reviewErrorTimeout) clearTimeout(this.reviewErrorTimeout);
|
||||
if (this.reloadTimeout) clearTimeout(this.reloadTimeout);
|
||||
this.seoService.resetToDefaults();
|
||||
}
|
||||
|
||||
loadItem(itemID: number): void {
|
||||
@@ -57,6 +68,7 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
this.apiService.getItem(itemID).subscribe({
|
||||
next: (item) => {
|
||||
this.item.set(item);
|
||||
this.seoService.setItemMeta(item);
|
||||
this.loading.set(false);
|
||||
},
|
||||
error: (err) => {
|
||||
@@ -81,18 +93,18 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
getDiscountedPrice(): number {
|
||||
const currentItem = this.item();
|
||||
if (!currentItem) return 0;
|
||||
return currentItem.price * (1 - currentItem.discount / 100);
|
||||
return getDiscountedPrice(currentItem);
|
||||
}
|
||||
|
||||
getSafeHtml(html: string): SafeHtml {
|
||||
return this.sanitizer.sanitize(1, html) || '';
|
||||
return this.sanitizer.sanitize(SecurityContext.HTML, html) || '';
|
||||
}
|
||||
|
||||
getRatingStars(rating: number): string {
|
||||
const fullStars = Math.floor(rating);
|
||||
const hasHalfStar = rating % 1 >= 0.5;
|
||||
let stars = '?'.repeat(fullStars);
|
||||
if (hasHalfStar) stars += '?';
|
||||
let stars = '★'.repeat(fullStars);
|
||||
if (hasHalfStar) stars += '☆';
|
||||
return stars;
|
||||
}
|
||||
|
||||
@@ -102,10 +114,10 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
const diffMs = now.getTime() - date.getTime();
|
||||
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (diffDays === 0) return '<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>';
|
||||
if (diffDays === 1) return '<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>';
|
||||
if (diffDays < 7) return `${diffDays} <EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD>`;
|
||||
if (diffDays < 30) return `${Math.floor(diffDays / 7)} <EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD>`;
|
||||
if (diffDays === 0) return 'Сегодня';
|
||||
if (diffDays === 1) return 'Вчера';
|
||||
if (diffDays < 7) return `${diffDays} дн. назад`;
|
||||
if (diffDays < 30) return `${Math.floor(diffDays / 7)} нед. назад`;
|
||||
|
||||
return date.toLocaleDateString('ru-RU', {
|
||||
day: 'numeric',
|
||||
@@ -120,7 +132,7 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
|
||||
getUserDisplayName(): string | null {
|
||||
if (!this.telegramService.isTelegramApp()) {
|
||||
return '<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>';
|
||||
return 'Пользователь';
|
||||
}
|
||||
return this.telegramService.getDisplayName();
|
||||
}
|
||||
@@ -149,13 +161,13 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
this.reviewSubmitStatus.set('success');
|
||||
this.newReview = { rating: 0, comment: '', anonymous: false };
|
||||
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> 3 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
setTimeout(() => {
|
||||
// Сброс состояния через 3 секунды
|
||||
this.reviewResetTimeout = setTimeout(() => {
|
||||
this.reviewSubmitStatus.set('idle');
|
||||
}, 3000);
|
||||
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
setTimeout(() => {
|
||||
// Перезагрузить данные товара после отправки отзыва
|
||||
this.reloadTimeout = setTimeout(() => {
|
||||
this.loadItem(currentItem.itemID);
|
||||
}, 500);
|
||||
},
|
||||
@@ -163,8 +175,8 @@ export class ItemDetailComponent implements OnInit, OnDestroy {
|
||||
console.error('Error submitting review:', err);
|
||||
this.reviewSubmitStatus.set('error');
|
||||
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> 5 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
setTimeout(() => {
|
||||
// Сброс состояния об ошибке через 5 секунд
|
||||
this.reviewErrorTimeout = setTimeout(() => {
|
||||
this.reviewSubmitStatus.set('idle');
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-company-details',
|
||||
imports: [],
|
||||
templateUrl: './company-details.component.html',
|
||||
styleUrls: ['./company-details.component.scss']
|
||||
styleUrls: ['./company-details.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class CompanyDetailsComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@@ -6,7 +6,8 @@ import { environment } from '../../../../environments/environment';
|
||||
selector: 'app-payment-terms',
|
||||
imports: [RouterLink],
|
||||
templateUrl: './payment-terms.component.html',
|
||||
styleUrls: ['./payment-terms.component.scss']
|
||||
styleUrls: ['./payment-terms.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class PaymentTermsComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-privacy-policy',
|
||||
imports: [],
|
||||
templateUrl: './privacy-policy.component.html',
|
||||
styleUrls: ['./privacy-policy.component.scss']
|
||||
styleUrls: ['./privacy-policy.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class PrivacyPolicyComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@@ -6,7 +6,8 @@ import { environment } from '../../../../environments/environment';
|
||||
selector: 'app-public-offer',
|
||||
imports: [RouterLink],
|
||||
templateUrl: './public-offer.component.html',
|
||||
styleUrls: ['./public-offer.component.scss']
|
||||
styleUrls: ['./public-offer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class PublicOfferComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-return-policy',
|
||||
imports: [],
|
||||
templateUrl: './return-policy.component.html',
|
||||
styleUrls: ['./return-policy.component.scss']
|
||||
styleUrls: ['./return-policy.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ReturnPolicyComponent {
|
||||
brandName = environment.brandName;
|
||||
|
||||
@@ -48,6 +48,7 @@ export class SearchComponent implements OnDestroy {
|
||||
ngOnDestroy(): void {
|
||||
this.searchSubscription.unsubscribe();
|
||||
this.searchSubject.complete();
|
||||
if (this.scrollTimeout) clearTimeout(this.scrollTimeout);
|
||||
}
|
||||
|
||||
onSearchInput(query: string): void {
|
||||
@@ -106,7 +107,7 @@ export class SearchComponent implements OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private scrollTimeout: any;
|
||||
private scrollTimeout?: ReturnType<typeof setTimeout>;
|
||||
|
||||
@HostListener('window:scroll')
|
||||
onScroll(): void {
|
||||
|
||||
Reference in New Issue
Block a user