Merge remote-tracking branch 'origin' into back-office-integration

This commit is contained in:
sdarbinyan
2026-02-28 16:13:14 +04:00
217 changed files with 10170 additions and 5789 deletions

View File

@@ -1,29 +1,34 @@
import { Component, computed, ChangeDetectionStrategy, signal, OnDestroy, OnInit } from '@angular/core';
import { Component, computed, ChangeDetectionStrategy, signal, OnDestroy, inject } from '@angular/core';
import { DecimalPipe } from '@angular/common';
import { Router, RouterLink } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { CartService, ApiService } from '../../services';
import { CartService, ApiService, LanguageService } from '../../services';
import { Item, CartItem } from '../../models';
import { interval, Subscription } from 'rxjs';
import { switchMap, take } from 'rxjs/operators';
import { EmptyCartIconComponent } from '../../components/empty-cart-icon/empty-cart-icon.component';
import { environment } from '../../../environments/environment';
import { getDiscountedPrice, getMainImage, trackByItemId, getBadgeClass } from '../../utils/item.utils';
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
import { TranslatePipe } from '../../i18n/translate.pipe';
import { TranslateService } from '../../i18n/translate.service';
@Component({
selector: 'app-cart',
imports: [DecimalPipe, RouterLink, FormsModule, EmptyCartIconComponent],
imports: [DecimalPipe, RouterLink, FormsModule, EmptyCartIconComponent, LangRoutePipe, TranslatePipe],
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CartComponent implements OnInit, OnDestroy {
export class CartComponent implements OnDestroy {
items;
itemCount;
totalPrice;
termsAccepted = false;
isnovo = environment.theme === 'novo';
private i18n = inject(TranslateService);
// Swipe state
swipedItemId = signal<number | null>(null);
@@ -52,17 +57,14 @@ export class CartComponent implements OnInit, OnDestroy {
constructor(
private cartService: CartService,
private apiService: ApiService,
private router: Router
private router: Router,
private langService: LanguageService
) {
this.items = this.cartService.items;
this.itemCount = this.cartService.itemCount;
this.totalPrice = this.cartService.totalPrice;
}
ngOnInit(): void {
// Component initialized
}
ngOnDestroy(): void {
this.stopPolling();
if (this.closeTimeout) {
@@ -109,16 +111,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('<27><> <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.i18n.t('cart.confirmClear'))) {
this.cartService.clearCart();
}
}
@@ -130,7 +132,7 @@ export class CartComponent implements OnInit, OnDestroy {
checkout(): void {
if (!this.termsAccepted) {
alert('<27><><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(this.i18n.t('cart.acceptTerms'));
return;
}
this.openPaymentPopup();
@@ -252,7 +254,7 @@ export class CartComponent implements OnInit, OnDestroy {
this.linkCopied.set(true);
setTimeout(() => this.linkCopied.set(false), 2000);
}).catch(err => {
console.error('<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:', err);
console.error(this.i18n.t('cart.copyError'), err);
});
}
}
@@ -317,17 +319,18 @@ export class CartComponent implements OnInit, OnDestroy {
next: () => {
this.emailSubmitting.set(false);
// Show success message
alert('Email <20><><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(this.i18n.t('cart.emailSuccess'));
// Close popup and redirect to home page
setTimeout(() => {
this.closePaymentPopup();
this.router.navigate(['/']);
const lang = this.langService.currentLanguage();
this.router.navigate([`/${lang}`]);
}, 500);
},
error: (err) => {
console.error('Error submitting email:', err);
this.emailSubmitting.set(false);
alert('<27><><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(this.i18n.t('cart.emailError'));
}
});
}
@@ -388,11 +391,11 @@ export class CartComponent implements OnInit, OnDestroy {
}
if (digitsOnly.length === 0) {
this.phoneError.set('<27><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>');
this.phoneError.set(this.i18n.t('cart.phoneRequired'));
} else if (digitsOnly.length < 11) {
this.phoneError.set(`<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> ${11 - digitsOnly.length} <20><><EFBFBD><EFBFBD>`);
this.phoneError.set(this.i18n.t('cart.phoneMoreDigits', { count: 11 - digitsOnly.length }));
} else if (digitsOnly.length > 11) {
this.phoneError.set('<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>');
this.phoneError.set(this.i18n.t('cart.phoneTooMany'));
} else {
this.phoneError.set('');
}
@@ -420,19 +423,19 @@ export class CartComponent implements OnInit, OnDestroy {
}
if (email.length === 0) {
this.emailError.set('Email <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>');
this.emailError.set(this.i18n.t('cart.emailRequired'));
} else if (email.length < 5) {
this.emailError.set('Email <20><><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(this.i18n.t('cart.emailTooShort'));
} else if (email.length > 100) {
this.emailError.set('Email <20><><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(this.i18n.t('cart.emailTooLong'));
} else if (!email.includes('@')) {
this.emailError.set('Email <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> @');
this.emailError.set(this.i18n.t('cart.emailNeedsAt'));
} else if (!email.includes('.')) {
this.emailError.set('Email <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> (.com, .ru <20> <20>.<2E>.)');
this.emailError.set(this.i18n.t('cart.emailNeedsDomain'));
} else {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
this.emailError.set('<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> email');
this.emailError.set(this.i18n.t('cart.emailInvalid'));
} else {
this.emailError.set('');
}