cleanup: remove tenant variant logic and enforce config-driven UI

This commit is contained in:
sdarbinyan
2026-07-05 04:07:25 +04:00
parent 79a12c0ec2
commit 6550250d13
19 changed files with 153 additions and 1102 deletions

View File

@@ -1,319 +1,3 @@
@if (isMarketplaceNovo) {
<!-- novo VERSION - Modern Design -->
<div class="novo-item-container">
@if (loading()) {
<div class="novo-loading">
<div class="novo-spinner"></div>
<p>{{ 'itemDetail.loading' | translate }}</p>
</div>
}
@if (error()) {
<div class="novo-error">
<p>{{ error() }}</p>
<a [routerLink]="'/' | langRoute" class="novo-back-link">{{ 'itemDetail.back' | translate }}</a>
</div>
}
@if (item() && !loading()) {
<div class="novo-item-content">
<div class="novo-gallery">
@if (item()?.photos && item()!.photos!.length > 0) {
<div class="novo-main-photo">
@if (item()!.photos![selectedPhotoIndex()]?.video) {
<video [src]="item()!.photos![selectedPhotoIndex()].url" controls></video>
} @else {
<img [src]="item()!.photos![selectedPhotoIndex()].url" [alt]="item()!.name" />
}
</div>
@if (item()!.photos!.length > 1) {
<div class="novo-thumbnails">
@for (photo of item()!.photos!; track $index) {
<div
class="novo-thumb"
[class.active]="selectedPhotoIndex() === $index"
(click)="selectPhoto($index)">
@if (photo.video) {
<div class="video-indicator"></div>
}
<img [src]="photo.url" [alt]="'Photo ' + ($index + 1)" loading="lazy" />
</div>
}
</div>
}
} @else {
<div class="novo-main-photo novo-no-image">
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<rect x="3" y="3" width="18" height="18" rx="2"></rect>
<circle cx="8.5" cy="8.5" r="1.5"></circle>
<path d="M21 15l-5-5L5 21"></path>
</svg>
<p>{{ 'itemDetail.noImage' | translate }}</p>
</div>
}
</div>
<div class="novo-info">
<h1 class="novo-title">{{ getItemName() }}</h1>
@if (item()!.badges && item()!.badges!.length > 0) {
<div class="novo-badges">
@for (badge of item()!.badges!; track badge) {
<span class="item-badge" [class]="getBadgeClass(badge)">{{ badge }}</span>
}
</div>
}
@if (item()!.tags && item()!.tags!.length > 0) {
<div class="novo-tags">
@for (tag of item()!.tags!; track tag) {
<span class="item-tag">#{{ tag }}</span>
}
</div>
}
<div class="novo-rating">
<span class="stars">{{ getRatingStars(item()!.rating) }}</span>
<span class="value">{{ item()!.rating }}</span>
<span class="reviews">({{ item()!.callbacks?.length || 0 }})</span>
</div>
<div class="novo-price-block">
@if (item()!.discount > 0) {
<div class="price-row">
<span class="old-price">{{ effectivePrice() }} {{ effectiveCurrency() }}</span>
<span class="discount-badge">-{{ item()!.discount }}%</span>
</div>
<div class="current-price">{{ getDiscountedPrice() | number:'1.2-2' }} {{ effectiveCurrency() }}</div>
} @else {
<div class="current-price">{{ effectivePrice() }} {{ effectiveCurrency() }}</div>
}
</div>
<div class="novo-stock">
<span class="stock-label">{{ 'itemDetail.stock' | translate }}</span>
<div class="stock-indicator" [class]="getStockClass()">
<span class="dot"></span>
{{ getStockLabel() }}
</div>
@if (effectiveRemaining() != null) {
<span class="stock-qty">({{ effectiveRemaining() }} шт.)</span>
}
</div>
@if (availableColours().length || availableSizes().length || item()!.colour || (item()!.size && item()!.size!.toLowerCase() !== 'default')) {
<div class="novo-variants">
@if (availableColours().length) {
<div class="variant-group">
<span class="variant-label">{{ 'itemDetail.colour' | translate }}:</span>
@for (c of availableColours(); track c) {
<span class="colour-swatch" [class.active]="selectedColour() === c" [style.background-color]="c" [title]="c" (click)="selectColour(c)"></span>
}
</div>
} @else if (item()!.colour) {
<div class="variant-group">
<span class="variant-label">{{ 'itemDetail.colour' | translate }}:</span>
<span class="colour-swatch active" [style.background-color]="item()!.colour" [title]="item()!.colour"></span>
</div>
}
@if (availableSizes().length) {
<div class="variant-group">
<span class="variant-label">{{ 'itemDetail.size' | translate }}:</span>
@for (s of availableSizes(); track s) {
<span class="variant-chip size-chip" [class.active]="selectedSize() === s" (click)="selectSize(s)">{{ s }}</span>
}
</div>
} @else if (item()!.size && item()!.size!.toLowerCase() !== 'default') {
<div class="variant-group">
<span class="variant-label">{{ 'itemDetail.size' | translate }}:</span>
<span class="variant-chip size-chip active">{{ item()!.size }}</span>
</div>
}
</div>
}
@if (item()!.attributes && item()!.attributes!.length > 0) {
<div class="novo-attributes">
@for (attr of item()!.attributes!; track attr.key) {
<div class="attribute-row">
<span class="attribute-key">{{ attr.key }}</span>
<span class="attribute-value">{{ attr.value }}</span>
</div>
}
</div>
}
@if (hasDeliveryInfo()) {
<div class="novo-delivery">
<h3 class="novo-delivery-title">{{ 'cart.deliveryLabel' | translate }}</h3>
@if (isDigitalDelivery()) {
<div class="novo-delivery-chip">{{ 'cart.digitalDelivery' | translate }}</div>
} @else {
<div class="novo-delivery-list">
@for (option of deliveryOptions(); track trackByDeliveryOption($index, option)) {
<div class="novo-delivery-option">
<div class="novo-delivery-option-main">
@if (option.deliveryPlace) {
<span>{{ 'cart.deliveryPlace' | translate }}: {{ option.deliveryPlace }}</span>
}
@if (option.deliveryTime) {
<span>{{ 'cart.deliveryTime' | translate }}: {{ option.deliveryTime }}</span>
}
</div>
<span class="novo-delivery-price">{{ option.deliveryPrice | number:'1.2-2' }} {{ getDeliveryCurrency() }}</span>
</div>
}
</div>
}
</div>
}
<button class="novo-add-cart" (click)="addToCart()">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
{{ 'itemDetail.addToCart' | translate }}
</button>
<div class="novo-description">
@if (getSimpleDescription()) {
<p class="novo-simple-desc">{{ getSimpleDescription() }}</p>
}
@if (hasDescriptionFields()) {
<h3>{{ 'itemDetail.specifications' | translate }}</h3>
<table class="novo-specs-table">
<tbody>
@for (field of getTranslatedDescriptionFields(); track field.key) {
<tr>
<td class="spec-key">{{ field.key }}</td>
<td class="spec-value">{{ field.value }}</td>
</tr>
}
</tbody>
</table>
} @else {
<h3>{{ 'itemDetail.description' | translate }}</h3>
<div [innerHTML]="getSafeHtml(item()!.description)"></div>
}
</div>
</div>
</div>
<div class="novo-reviews">
<h2>{{ 'itemDetail.reviews' | translate }} ({{ item()!.callbacks?.length || 0 }})</h2>
<!-- novo Review Form -->
<div class="novo-review-form">
<h3>{{ 'itemDetail.yourReview' | translate }}</h3>
<div class="novo-rating-input">
<label>{{ 'itemDetail.rating' | translate }}</label>
<div class="novo-star-selector">
@for (star of [1, 2, 3, 4, 5]; track star) {
<span
class="novo-star"
[class.selected]="newReview.rating >= star"
(click)="setRating(star)">
</span>
}
</div>
</div>
<textarea
[(ngModel)]="newReview.comment"
[placeholder]="'itemDetail.reviewPlaceholder' | translate"
rows="4"
class="novo-textarea">
</textarea>
<div class="novo-form-actions">
<label class="novo-anonymous-toggle">
<input type="checkbox" [(ngModel)]="newReview.anonymous">
<span>{{ 'itemDetail.anonymous' | translate }}</span>
</label>
@if (!newReview.anonymous && getUserDisplayName()) {
<span class="novo-username-preview">{{ getUserDisplayName() }}</span>
}
<button
class="novo-submit-review-btn"
(click)="submitReview()"
[disabled]="!newReview.rating || !newReview.comment.trim() || reviewSubmitStatus() === 'loading'"
[class.submitting]="reviewSubmitStatus() === 'loading'">
@if (reviewSubmitStatus() === 'loading') {
<span class="novo-spinner-small"></span>
{{ 'itemDetail.submitting' | translate }}
} @else {
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z"/>
</svg>
{{ 'itemDetail.submit' | translate }}
}
</button>
</div>
@if (reviewSubmitStatus() === 'success') {
<div class="novo-status-message success">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<path d="M20 6L9 17l-5-5"/>
</svg>
{{ 'itemDetail.reviewSuccess' | translate }}
</div>
}
@if (reviewSubmitStatus() === 'error') {
<div class="novo-status-message error">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<path d="M18 6L6 18M6 6l12 12"/>
</svg>
{{ 'itemDetail.reviewError' | translate }}
</div>
}
</div>
<div class="novo-reviews-list">
@if (item()!.callbacks && item()!.callbacks!.length > 0) {
@for (review of item()!.callbacks!; track review.userID) {
<div class="novo-review-card">
<div class="review-header">
<div class="reviewer-info">
<span class="reviewer-name">{{ review.userID ? review.userID : ('itemDetail.defaultUser' | translate) }}</span>
@if (review.timestamp) {
<span class="review-date">{{ formatDate(review.timestamp) }}</span>
}
</div>
<span class="review-stars">{{ getRatingStars(review.rating || 0) }}</span>
</div>
<p class="review-text">{{ review.content }}</p>
</div>
}
} @else {
<p class="novo-no-reviews">{{ 'itemDetail.noReviews' | translate }}</p>
}
</div>
</div>
@if (relatedProducts().length > 0) {
<section class="related-products" aria-labelledby="novo-related-products-title">
<h2 id="novo-related-products-title">{{ 'itemDetail.relatedProducts' | translate }}</h2>
<div class="related-products-grid">
@for (related of relatedProducts(); track related.itemID) {
<app-product-card
[item]="related"
[title]="relatedItemName(related)"
[addToCartLabel]="'itemDetail.addToCart' | translate"
appearance="compact"
(addToCart)="addRelatedToCart($event.itemID, $event.event)"
/>
}
</div>
</section>
}
}
</div>
} @else {
<!-- DEXAR VERSION - Redesigned 2026 -->
<div class="dx-item-container">
@if (loading()) {
@@ -342,7 +26,7 @@
[class.active]="selectedPhotoIndex() === $index"
(click)="selectPhoto($index)">
@if (photo.video) {
<div class="dx-video-badge"></div>
<div class="dx-video-badge">?</div>
}
<img [src]="photo.url" [alt]="('itemDetail.photo' | translate) + ' ' + ($index + 1)" loading="lazy" decoding="async" />
</div>
@@ -420,7 +104,7 @@
{{ getStockLabel() }}
</span>
@if (effectiveRemaining() != null) {
<span class="dx-stock-qty">({{ effectiveRemaining() }} шт.)</span>
<span class="dx-stock-qty">({{ effectiveRemaining() }} øò.)</span>
}
</div>
@@ -541,7 +225,7 @@
class="dx-star-pick"
[class.selected]="newReview.rating >= star"
(click)="setRating(star)">
?
</span>
}
</div>
@@ -629,11 +313,11 @@
@for (question of item()!.questions!; track $index) {
<div class="dx-qa-card">
<div class="dx-question">
<span class="dx-qa-label q">В</span>
<span class="dx-qa-label q">Â</span>
<span>{{ question.question }}</span>
</div>
<div class="dx-answer">
<span class="dx-qa-label a">О</span>
<span class="dx-qa-label a">Î</span>
<span>{{ question.answer }}</span>
</div>
<div class="dx-qa-votes">
@@ -670,4 +354,3 @@
}
}
</div>
}