Files
marketplaces/src/app/pages/item-detail/item-detail.component.html
2026-02-26 22:23:08 +04:00

431 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@if (isnovo) {
<!-- novo VERSION - Modern Design -->
<div class="novo-item-container">
@if (loading()) {
<div class="novo-loading">
<div class="novo-spinner"></div>
<p>Загрузка...</p>
</div>
}
@if (error()) {
<div class="novo-error">
<p>{{ error() }}</p>
<a [routerLink]="'/' | langRoute" class="novo-back-link">Вернуться</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>Нет изображения</p>
</div>
}
</div>
<div class="novo-info">
<h1 class="novo-title">{{ item()!.name }}</h1>
<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">{{ item()!.price }} {{ item()!.currency }}</span>
<span class="discount-badge">-{{ item()!.discount }}%</span>
</div>
<div class="current-price">{{ getDiscountedPrice() | number:'1.2-2' }} {{ item()!.currency }}</div>
} @else {
<div class="current-price">{{ item()!.price }} {{ item()!.currency }}</div>
}
</div>
<div class="novo-stock">
<span class="stock-label">Наличие:</span>
<div class="stock-indicator" [class.high]="item()!.remainings === 'high'" [class.medium]="item()!.remainings === 'medium'" [class.low]="item()!.remainings === 'low'">
<span class="dot"></span>
{{ item()!.remainings === 'high' ? 'В наличии' : item()!.remainings === 'medium' ? 'Мало' : 'Осталось немного' }}
</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>
Добавить в корзину
</button>
<div class="novo-description">
<h3>Описание</h3>
<div [innerHTML]="getSafeHtml(item()!.description)"></div>
</div>
</div>
</div>
<div class="novo-reviews">
<h2>Отзывы ({{ item()!.callbacks?.length || 0 }})</h2>
<!-- novo Review Form -->
<div class="novo-review-form">
<h3>Ваш отзыв</h3>
<div class="novo-rating-input">
<label>Оценка:</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="Поделитесь своими впечатлениями о товаре..."
rows="4"
class="novo-textarea">
</textarea>
<div class="novo-form-actions">
<label class="novo-anonymous-toggle">
<input type="checkbox" [(ngModel)]="newReview.anonymous">
<span>Анонимно</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>
Отправка...
} @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>
Отправить
}
</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>
Спасибо за ваш отзыв!
</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>
Ошибка отправки. Попробуйте позже.
</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 || 'Пользователь' }}</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">Пока нет отзывов. Станьте первым!</p>
}
</div>
</div>
}
</div>
} @else {
<!-- DEXAR VERSION - Redesigned 2026 -->
<div class="dx-item-container">
@if (loading()) {
<div class="dx-loading">
<div class="dx-spinner"></div>
<p>Загрузка товара...</p>
</div>
}
@if (error()) {
<div class="dx-error">
<p>{{ error() }}</p>
<a [routerLink]="'/' | langRoute" class="dx-back-link">Вернуться на главную</a>
</div>
}
@if (item() && !loading()) {
<div class="dx-item-content">
<!-- Gallery: thumbnails left + main photo -->
<div class="dx-gallery">
@if (item()?.photos && item()!.photos!.length > 0) {
<div class="dx-thumbnails">
@for (photo of item()!.photos!; track $index) {
<div
class="dx-thumb"
[class.active]="selectedPhotoIndex() === $index"
(click)="selectPhoto($index)">
@if (photo.video) {
<div class="dx-video-badge"></div>
}
<img [src]="photo.url" [alt]="'Фото ' + ($index + 1)" loading="lazy" decoding="async" />
</div>
}
</div>
}
<div class="dx-main-photo">
@if (item()?.photos && item()!.photos!.length > 0) {
@if (item()!.photos![selectedPhotoIndex()]?.video) {
<video [src]="item()!.photos![selectedPhotoIndex()].url" controls></video>
} @else {
<img [src]="item()!.photos![selectedPhotoIndex()].url" [alt]="item()!.name" fetchpriority="high" decoding="async" />
}
} @else {
<div class="dx-no-image">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="#a1b4b5" 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>
<span>Нет изображения</span>
</div>
}
</div>
</div>
<!-- Item Info -->
<div class="dx-info">
<h1 class="dx-title">{{ item()!.name }}</h1>
<div class="dx-rating">
<div class="dx-stars">
@for (star of [1, 2, 3, 4, 5]; track star) {
<svg width="18" height="18" viewBox="0 0 24 24" [attr.fill]="star <= item()!.rating ? '#497671' : 'none'" [attr.stroke]="star <= item()!.rating ? '#497671' : '#a1b4b5'" stroke-width="2">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
</svg>
}
</div>
<span class="dx-rating-value">{{ item()!.rating }}</span>
<span class="dx-rating-count">({{ item()!.callbacks?.length || 0 }} отзывов)</span>
</div>
<div class="dx-price-block">
@if (item()!.discount > 0) {
<div class="dx-price-row">
<span class="dx-old-price">{{ item()!.price }} {{ item()!.currency }}</span>
<span class="dx-discount-tag">-{{ item()!.discount }}%</span>
</div>
}
<div class="dx-current-price">
{{ item()!.discount > 0 ? (getDiscountedPrice() | number:'1.2-2') : item()!.price }} {{ item()!.currency }}
</div>
</div>
<div class="dx-stock">
<span class="dx-stock-label">Наличие:</span>
<span class="dx-stock-status"
[class.high]="item()!.remainings === 'high'"
[class.medium]="item()!.remainings === 'medium'"
[class.low]="item()!.remainings === 'low'">
<span class="dx-stock-dot"></span>
{{ item()!.remainings === 'high' ? 'В наличии' : item()!.remainings === 'medium' ? 'Заканчивается' : 'Последние штуки' }}
</span>
</div>
<button class="dx-add-cart" (click)="addToCart()">
<svg width="22" height="22" 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>
Добавить в корзину
</button>
<div class="dx-description">
<h2>Описание</h2>
<div class="dx-description-text" [innerHTML]="getSafeHtml(item()!.description)"></div>
</div>
</div>
</div>
<!-- Reviews Section -->
<div class="dx-reviews-section">
<h2>Отзывы ({{ item()!.callbacks?.length || 0 }})</h2>
<div class="dx-review-form">
<h3>Оставить отзыв</h3>
<div class="dx-rating-input">
<label>Оценка:</label>
<div class="dx-star-selector">
@for (star of [1, 2, 3, 4, 5]; track star) {
<span
class="dx-star-pick"
[class.selected]="newReview.rating >= star"
(click)="setRating(star)">
</span>
}
</div>
</div>
<textarea
[(ngModel)]="newReview.comment"
placeholder="Поделитесь впечатлениями о товаре..."
rows="4"
class="dx-textarea">
</textarea>
<div class="dx-form-actions">
<label class="dx-anon-toggle">
<input type="checkbox" [(ngModel)]="newReview.anonymous">
<span>Анонимно</span>
</label>
@if (!newReview.anonymous && getUserDisplayName()) {
<span class="dx-user-preview">{{ getUserDisplayName() }}</span>
}
<button
class="dx-submit-btn"
(click)="submitReview()"
[disabled]="!newReview.rating || !newReview.comment.trim() || reviewSubmitStatus() === 'loading'"
[class.submitting]="reviewSubmitStatus() === 'loading'">
@if (reviewSubmitStatus() === 'loading') {
<span class="dx-spinner-sm"></span>
Отправка...
} @else {
Отправить
}
</button>
</div>
@if (reviewSubmitStatus() === 'success') {
<div class="dx-status success">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6L9 17l-5-5"/></svg>
Спасибо за ваш отзыв!
</div>
}
@if (reviewSubmitStatus() === 'error') {
<div class="dx-status error">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M18 6L6 18M6 6l12 12"/></svg>
Ошибка отправки. Попробуйте позже.
</div>
}
</div>
<div class="dx-reviews-list">
@if (item()?.callbacks && item()!.callbacks!.length > 0) {
@for (callback of item()!.callbacks; track $index) {
<div class="dx-review-card">
<div class="dx-review-header">
<div class="dx-reviewer">
<span class="dx-reviewer-name">{{ callback.userID || 'Аноним' }}</span>
@if (callback.timestamp) {
<span class="dx-review-date">{{ formatDate(callback.timestamp) }}</span>
}
</div>
@if (callback.rating) {
<div class="dx-review-stars">
@for (star of [1, 2, 3, 4, 5]; track star) {
<svg width="14" height="14" viewBox="0 0 24 24" [attr.fill]="star <= callback.rating ? '#497671' : 'none'" [attr.stroke]="star <= callback.rating ? '#497671' : '#d3dad9'" stroke-width="2">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
</svg>
}
</div>
}
</div>
@if (callback.content) {
<p class="dx-review-text">{{ callback.content }}</p>
}
</div>
}
} @else {
<p class="dx-no-reviews">Пока нет отзывов. Станьте первым!</p>
}
</div>
</div>
<!-- Q&A Section -->
@if (item()!.questions && item()!.questions!.length > 0) {
<div class="dx-qa-section">
<h2>Вопросы и ответы ({{ item()!.questions!.length }})</h2>
<div class="dx-qa-list">
@for (question of item()!.questions!; track $index) {
<div class="dx-qa-card">
<div class="dx-question">
<span class="dx-qa-label q">В</span>
<span>{{ question.question }}</span>
</div>
<div class="dx-answer">
<span class="dx-qa-label a">О</span>
<span>{{ question.answer }}</span>
</div>
<div class="dx-qa-votes">
<button class="dx-vote up">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3H14z"/><path d="M7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"/></svg>
{{ question.upvotes }}
</button>
<button class="dx-vote down">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3H10z"/><path d="M17 2h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"/></svg>
{{ question.downvotes }}
</button>
</div>
</div>
}
</div>
</div>
}
}
</div>
}