@extends('layouts.app') @section('title', $product->title.' — teeu') @section('meta_description', \Illuminate\Support\Str::limit(strip_tags($product->displayDescription()), 150)) @php $seoCrumbs = [['name' => 'Главная', 'url' => route('home')]]; foreach ($product->category?->ancestors()->defaultOrder()->get() ?? [] as $a) { $seoCrumbs[] = ['name' => $a->name, 'url' => route('catalog.category', $a->path)]; } if ($product->category) { $seoCrumbs[] = ['name' => $product->category->name, 'url' => route('catalog.category', $product->category->path)]; } $seoCrumbs[] = ['name' => $product->title, 'url' => $product->url()]; @endphp @section('seo') @include('partials.seo.meta', [ 'canonical' => $product->url(), 'ogType' => 'product', 'ogTitle' => $product->title, 'ogDescription' => \Illuminate\Support\Str::limit(strip_tags($product->displayDescription()), 200), 'ogImage' => \App\Support\OgImage::from($product->primaryImage()?->largeUrl()), ]) @include('partials.seo.json-ld', ['data' => \App\Support\Seo::productJsonLd($product)]) @include('partials.seo.json-ld', ['data' => \App\Support\Seo::breadcrumbJsonLd($seoCrumbs)]) @endsection @section('content') {{-- Страница товара по макету редизайна («Карточка товара»): три колонки — галерея · название, характеристики и описание · панель покупки и продавец. На телефоне и планшете — одной колонкой в порядке: фото, название, покупка, подробности (grid-areas ниже). --}} @php($onSale = $product->onSale()) @php($undeliverable = app(\App\Services\Geo\DeliveryScope::class)->blocksProduct($product)) @php($shownPrice = $onSale ? $product->salePrice() : (float) $product->price) @php($oldPrice = $onSale ? (float) $product->price : ($product->old_price ? (float) $product->old_price : null)) @php($seller = $product->seller) @php($displayDescription = $product->displayDescription()) @php($visibleChars = $product->visibleCharacteristics()) @php($shortChars = 8) @php($isPreOrder = $product->availability === \App\Enums\Availability::PreOrder)
{{-- Gallery with click-to-zoom lightbox (#18) --}}
{{-- Как и в карточке: фото целиком, без кропа по квадрату. --}}
@if ($product->images->isNotEmpty()) @foreach ($product->images as $i => $image) {{ $product->title }} @endforeach @else @endif @if ($onSale) −{{ $product->discount_percent }}% @endif
@if ($product->images->count() > 1)
@foreach ($product->images as $i => $image) @endforeach
@endif {{-- Lightbox overlay. Телепортируется в : колонка галереи липкая (sticky), а липкий элемент создаёт свой контекст наложения — внутри него fixed-оверлей с любым z-index оказывался под панелью покупки и карточками ниже. --}} @if ($product->images->isNotEmpty()) @endif
{{-- Название и строка «рейтинг · артикул · наличие». Рейтинг — продавца по отзывам на заказы; пока отзывов нет, звезды нет. --}}

{{ $product->title }}

@if ($seller->reviews_count > 0) ★ {{ number_format($seller->rating_avg, 1) }} · {{ $seller->reviews_count }} {{ \App\Support\Ru::plural($seller->reviews_count, ['отзыв', 'отзыва', 'отзывов']) }} о продавце @endif @if (filled($product->vendor_code)) арт. {{ $product->vendor_code }} @endif {{-- Цвета наличия — по UI-kit: «В наличии» синим, «Под заказ» зелёным. --}} {{ $product->availability->label() }}
{{-- Панель покупки — всё, что нужно для решения о покупке. Порядок отражает важность: цена и её свежесть, под ними одно основное действие (синяя кнопка здесь ровно одна — та, ради которой человек сюда пришёл), рядом избранное; ниже — доставка и условия продавца, затем тихие ссылки. Продавец — отдельной карточкой: это про доверие, а не про покупку. --}}
{{ number_format($shownPrice, 0, '.', ' ') }} ₽ @if ($oldPrice) {{ number_format($oldPrice, 0, '.', ' ') }} ₽ @endif
{{-- Данные из выгрузки продавца актуальны на дату последней успешной синхронизации фида (товар присутствовал в ней — source_missing_at пуст). --}} @if ($product->source_missing_at === null && $product->ymlFeed?->last_success_at)
Актуально на {{ $product->ymlFeed->last_success_at->isoFormat('D MMMM YYYY') }}
@endif @if ($onSale && $product->sale_ends_at && ! $undeliverable)
До конца акции:
@endif {{-- Город ставим отдельно, а не в предлог: склонять названия мы не умеем, и «Доставка в Уфа» бросается в глаза каждому, кто это читает. Так падеж не нужен вовсе. --}} @if ($undeliverable)

Продавец не доставляет этот товар в выбранный город ({{ $city->name }}).

@endif
@unless ($undeliverable) @endunless
@if (! $undeliverable && $deliveryDays)
Доставка · {{ $city->name }} {{ \App\Services\Delivery\DeliveryEstimator::label($deliveryDays) }}
@endif {{-- Порог продавца — здесь, а не только в корзине: узнать о нём после того, как набрал товар на 800 ₽ у оптовика «от 5 000», обиднее, чем до. --}} @if ($minimumOrder = $seller->minimumOrderAmount())
Минимальный заказ у продавца {{ \App\Services\Commerce\MinimumOrderService::money($minimumOrder) }} ₽
@endif
Оплата продавцу напрямую
{{-- Вторичные — тихими ссылками, не кнопками. Уход на чужой сайт — не шаг покупки, а выход из неё: внешняя ссылка, новая вкладка, неиндексируемая, без утечки реферера; только если фид разрешил. --}}
@unless ($undeliverable) @endunless @if ($product->ymlFeed?->showsSourceUrl() && $product->source_url) Смотреть на сайте продавца @endif
@if ($seller->logoUrl()) {{-- Лого может быть прямоугольным — object-contain вписывает целиком, не обрезая. --}} @else {{ mb_strtoupper(mb_substr($seller->public_name, 0, 1)) }} @endif {{ $seller->public_name }} @if ($seller->reviews_count > 0) ★ {{ number_format($seller->rating_avg, 1) }} · {{ $seller->reviews_count }} {{ \App\Support\Ru::plural($seller->reviews_count, ['отзыв', 'отзыва', 'отзывов']) }} · @endif на teeu с {{ $seller->created_at?->year }}
{{-- Характеристики (первые несколько) и описание. Полный список — ниже, отдельным блоком, если характеристик больше. Prefer the unique AI description when present (ТЗ §16). --}}
@if ($visibleChars->isNotEmpty())

Характеристики

@include('product.partials.characteristics', ['chars' => $visibleChars->take($shortChars)]) @if ($visibleChars->count() > $shortChars) Все характеристики ({{ $visibleChars->count() }}) ↓ @endif
@endif @if ($displayDescription)

Описание

{!! nl2br(e($displayDescription)) !!}

@endif
@if ($visibleChars->count() > $shortChars)

Все характеристики

@include('product.partials.characteristics', ['chars' => $visibleChars, 'divided' => true])
@endif {{-- Имя переменной цикла — «своё», не общеупотребительное: после @foreach она остаётся в области видимости и уезжает в layout, а оттуда в его партиалы (см. partials/auth-form). Короткий $heading там уже ломал заголовок модалки. --}} @foreach (['Другие товары продавца' => $otherProducts, 'Похожие товары' => $similar] as $blockTitle => $list) @if ($list->isNotEmpty())

{{ $blockTitle }}

{{-- 12 товаров — ровно два ряда при 2, 3, 4 и 6 колонках (5 колонок не берём). --}}
@foreach ($list as $item) @endforeach
@endif @endforeach @endsection