integration
This commit is contained in:
@@ -53,6 +53,7 @@ export const TRANSLATIONS: Record<string, Record<string, string>> = {
|
|||||||
// --- Item basic fields ---
|
// --- Item basic fields ---
|
||||||
ITEM_NAME: 'Item Name',
|
ITEM_NAME: 'Item Name',
|
||||||
PRICE: 'Price',
|
PRICE: 'Price',
|
||||||
|
DISCOUNT: 'Discount (%)',
|
||||||
QUANTITY: 'Quantity',
|
QUANTITY: 'Quantity',
|
||||||
CURRENCY: 'Currency',
|
CURRENCY: 'Currency',
|
||||||
SIMPLE_DESCRIPTION: 'Simple Description',
|
SIMPLE_DESCRIPTION: 'Simple Description',
|
||||||
@@ -169,6 +170,7 @@ export const TRANSLATIONS: Record<string, Record<string, string>> = {
|
|||||||
// --- Item basic fields ---
|
// --- Item basic fields ---
|
||||||
ITEM_NAME: 'Название товара',
|
ITEM_NAME: 'Название товара',
|
||||||
PRICE: 'Цена',
|
PRICE: 'Цена',
|
||||||
|
DISCOUNT: 'Скидка (%)',
|
||||||
QUANTITY: 'Количество',
|
QUANTITY: 'Количество',
|
||||||
CURRENCY: 'Валюта',
|
CURRENCY: 'Валюта',
|
||||||
SIMPLE_DESCRIPTION: 'Краткое описание',
|
SIMPLE_DESCRIPTION: 'Краткое описание',
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export interface Item {
|
|||||||
priority: number;
|
priority: number;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
price: number;
|
price: number;
|
||||||
|
discount: number;
|
||||||
currency: string;
|
currency: string;
|
||||||
imgs: string[];
|
imgs: string[];
|
||||||
tags: string[];
|
tags: string[];
|
||||||
|
|||||||
@@ -107,6 +107,25 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<mat-form-field appearance="outline" class="half-width">
|
||||||
|
<mat-label>{{ 'DISCOUNT' | translate }}</mat-label>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="number"
|
||||||
|
step="1"
|
||||||
|
[(ngModel)]="item()!.discount"
|
||||||
|
(blur)="onFieldChange('discount', item()!.discount)"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
placeholder="0">
|
||||||
|
<span matSuffix>%</span>
|
||||||
|
@if (item()!.discount < 0 || item()!.discount > 100) {
|
||||||
|
<mat-error>Discount must be 0–100%</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
<mat-form-field appearance="outline" class="full-width">
|
<mat-form-field appearance="outline" class="full-width">
|
||||||
<mat-label>{{ 'SIMPLE_DESCRIPTION' | translate }}</mat-label>
|
<mat-label>{{ 'SIMPLE_DESCRIPTION' | translate }}</mat-label>
|
||||||
<textarea
|
<textarea
|
||||||
|
|||||||
@@ -72,7 +72,13 @@
|
|||||||
<h1 class="item-name">{{ item.name }}</h1>
|
<h1 class="item-name">{{ item.name }}</h1>
|
||||||
|
|
||||||
<div class="price-row">
|
<div class="price-row">
|
||||||
<span class="price">{{ item.price | number:'1.2-2' }} {{ item.currency }}</span>
|
@if (item.discount > 0) {
|
||||||
|
<span class="price-old">{{ item.price | number:'1.2-2' }} {{ item.currency }}</span>
|
||||||
|
<span class="price">{{ item.price * (1 - item.discount / 100) | number:'1.2-2' }} {{ item.currency }}</span>
|
||||||
|
<span class="discount-tag">-{{ item.discount }}%</span>
|
||||||
|
} @else {
|
||||||
|
<span class="price">{{ item.price | number:'1.2-2' }} {{ item.currency }}</span>
|
||||||
|
}
|
||||||
@if (item.quantity > 0) {
|
@if (item.quantity > 0) {
|
||||||
<span class="in-stock">
|
<span class="in-stock">
|
||||||
<mat-icon>check_circle</mat-icon>
|
<mat-icon>check_circle</mat-icon>
|
||||||
|
|||||||
@@ -195,6 +195,22 @@
|
|||||||
color: #1976d2;
|
color: #1976d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.price-old {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: #999;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discount-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #e53935;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
.in-stock, .out-of-stock {
|
.in-stock, .out-of-stock {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -98,6 +98,9 @@
|
|||||||
|
|
||||||
<div class="item-details">
|
<div class="item-details">
|
||||||
<span class="price">{{ item.price }} {{ item.currency }}</span>
|
<span class="price">{{ item.price }} {{ item.currency }}</span>
|
||||||
|
@if (item.discount > 0) {
|
||||||
|
<span class="discount-chip">-{{ item.discount }}%</span>
|
||||||
|
}
|
||||||
<span class="quantity">{{ 'QTY' | translate }}: {{ item.quantity }}</span>
|
<span class="quantity">{{ 'QTY' | translate }}: {{ item.quantity }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -226,6 +226,16 @@
|
|||||||
color: #1976d2;
|
color: #1976d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.discount-chip {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 1px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #e53935;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
.quantity {
|
.quantity {
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export class MockDataService {
|
|||||||
priority: 1,
|
priority: 1,
|
||||||
quantity: 50,
|
quantity: 50,
|
||||||
price: 1299,
|
price: 1299,
|
||||||
|
discount: 0,
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
imgs: [
|
imgs: [
|
||||||
'https://via.placeholder.com/600x400?text=iPhone+Front',
|
'https://via.placeholder.com/600x400?text=iPhone+Front',
|
||||||
@@ -121,6 +122,7 @@ export class MockDataService {
|
|||||||
priority: 2,
|
priority: 2,
|
||||||
quantity: 35,
|
quantity: 35,
|
||||||
price: 1199,
|
price: 1199,
|
||||||
|
discount: 10,
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
imgs: ['https://via.placeholder.com/600x400?text=Samsung+S24'],
|
imgs: ['https://via.placeholder.com/600x400?text=Samsung+S24'],
|
||||||
tags: ['new', 'android'],
|
tags: ['new', 'android'],
|
||||||
@@ -140,6 +142,7 @@ export class MockDataService {
|
|||||||
priority: 3,
|
priority: 3,
|
||||||
quantity: 20,
|
quantity: 20,
|
||||||
price: 999,
|
price: 999,
|
||||||
|
discount: 15,
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
imgs: ['https://via.placeholder.com/600x400?text=Pixel+8'],
|
imgs: ['https://via.placeholder.com/600x400?text=Pixel+8'],
|
||||||
tags: ['sale', 'android', 'ai'],
|
tags: ['sale', 'android', 'ai'],
|
||||||
@@ -158,6 +161,7 @@ export class MockDataService {
|
|||||||
priority: 1,
|
priority: 1,
|
||||||
quantity: 15,
|
quantity: 15,
|
||||||
price: 2499,
|
price: 2499,
|
||||||
|
discount: 0,
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
imgs: ['https://via.placeholder.com/600x400?text=MacBook'],
|
imgs: ['https://via.placeholder.com/600x400?text=MacBook'],
|
||||||
tags: ['featured', 'professional'],
|
tags: ['featured', 'professional'],
|
||||||
@@ -177,6 +181,7 @@ export class MockDataService {
|
|||||||
priority: 2,
|
priority: 2,
|
||||||
quantity: 0,
|
quantity: 0,
|
||||||
price: 1799,
|
price: 1799,
|
||||||
|
discount: 5,
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
imgs: ['https://via.placeholder.com/600x400?text=Dell+XPS'],
|
imgs: ['https://via.placeholder.com/600x400?text=Dell+XPS'],
|
||||||
tags: ['out-of-stock'],
|
tags: ['out-of-stock'],
|
||||||
@@ -200,6 +205,7 @@ export class MockDataService {
|
|||||||
priority: i,
|
priority: i,
|
||||||
quantity: Math.floor(Math.random() * 100),
|
quantity: Math.floor(Math.random() * 100),
|
||||||
price: Math.floor(Math.random() * 1000) + 100,
|
price: Math.floor(Math.random() * 1000) + 100,
|
||||||
|
discount: Math.random() > 0.7 ? Math.floor(Math.random() * 30) + 5 : 0,
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
imgs: [`https://via.placeholder.com/600x400?text=Product+${i}`],
|
imgs: [`https://via.placeholder.com/600x400?text=Product+${i}`],
|
||||||
tags: ['test'],
|
tags: ['test'],
|
||||||
@@ -404,6 +410,7 @@ export class MockDataService {
|
|||||||
priority: data.priority || 99,
|
priority: data.priority || 99,
|
||||||
quantity: data.quantity || 0,
|
quantity: data.quantity || 0,
|
||||||
price: data.price || 0,
|
price: data.price || 0,
|
||||||
|
discount: data.discount || 0,
|
||||||
currency: data.currency || 'USD',
|
currency: data.currency || 'USD',
|
||||||
imgs: data.imgs || [],
|
imgs: data.imgs || [],
|
||||||
tags: data.tags || [],
|
tags: data.tags || [],
|
||||||
|
|||||||
@@ -54,6 +54,15 @@ export class ValidationService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateDiscount(value: any): string | null {
|
||||||
|
if (value === undefined || value === null || value === '') return null;
|
||||||
|
const num = Number(value);
|
||||||
|
if (isNaN(num)) return 'Discount must be a number';
|
||||||
|
if (num < 0) return 'Discount cannot be negative';
|
||||||
|
if (num > 100) return 'Discount cannot exceed 100%';
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
validateUrl(value: string): string | null {
|
validateUrl(value: string): string | null {
|
||||||
if (!value || value.trim().length === 0) {
|
if (!value || value.trim().length === 0) {
|
||||||
return null; // Optional field
|
return null; // Optional field
|
||||||
@@ -130,6 +139,11 @@ export class ValidationService {
|
|||||||
const quantityError = this.validateQuantity(item['quantity']);
|
const quantityError = this.validateQuantity(item['quantity']);
|
||||||
if (quantityError) errors['quantity'] = quantityError;
|
if (quantityError) errors['quantity'] = quantityError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item['discount'] !== undefined) {
|
||||||
|
const discountError = this.validateDiscount(item['discount']);
|
||||||
|
if (discountError) errors['discount'] = discountError;
|
||||||
|
}
|
||||||
|
|
||||||
if (item['currency'] !== undefined) {
|
if (item['currency'] !== undefined) {
|
||||||
const currencyError = this.validateCurrency(item['currency']);
|
const currencyError = this.validateCurrency(item['currency']);
|
||||||
|
|||||||
Reference in New Issue
Block a user