@if($product->featuredImage?->url) @push('head') @endpush @endif @if($product->personalizable) @push('head') @php $googleFonts = collect(config('personalization.fonts'))->pluck('google')->filter()->implode('&family='); @endphp @if($googleFonts) @endif @endpush @endif {{-- Schema.org Product + BreadcrumbList --}} @php $productSchema = [ '@context' => 'https://schema.org', '@type' => 'Product', 'name' => $product->name, 'description' => strip_tags($product->short_description ?? $product->description ?? ''), 'image' => $product->featuredImage?->url ? [url($product->featuredImage->url)] : [], 'sku' => $product->sku ?: 'prod-' . $product->id, 'brand' => [ '@type' => 'Brand', 'name' => $product->brand?->name ?? 'Institut Corps à Coeur', ], 'offers' => [ '@type' => 'Offer', 'url' => url()->current(), 'priceCurrency' => 'EUR', 'price' => number_format($product->currentPrice(), 2, '.', ''), 'availability' => $product->stock_status === 'outofstock' ? 'https://schema.org/OutOfStock' : 'https://schema.org/InStock', ], ]; if ($reviews->count() > 0) { $avgRating = round($reviews->avg('rating'), 1); $productSchema['aggregateRating'] = [ '@type' => 'AggregateRating', 'ratingValue' => $avgRating, 'reviewCount' => $reviews->count(), 'bestRating' => 5, 'worstRating' => 1, ]; $productSchema['review'] = $reviews->map(fn($r) => array_filter([ '@type' => 'Review', 'name' => $r->title ?: null, 'reviewBody' => $r->body, 'datePublished' => \Carbon\Carbon::parse($r->created_at)->toDateString(), 'author' => ['@type' => 'Person', 'name' => $r->author_name], 'reviewRating' => [ '@type' => 'Rating', 'ratingValue' => $r->rating, 'bestRating' => 5, 'worstRating' => 1, ], ]))->values()->all(); } $productJsonLd = json_encode($productSchema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); $breadcrumbItems = [ ['@type' => 'ListItem', 'position' => 1, 'name' => 'Boutique', 'item' => route('shop.index')], ]; $pos = 2; if ($product->category?->parent) { $breadcrumbItems[] = ['@type' => 'ListItem', 'position' => $pos++, 'name' => $product->category->parent->name, 'item' => $product->category->parent->url()]; } if ($product->category) { $breadcrumbItems[] = ['@type' => 'ListItem', 'position' => $pos++, 'name' => $product->category->name, 'item' => $product->category->url()]; } $breadcrumbItems[] = ['@type' => 'ListItem', 'position' => $pos, 'name' => $product->name]; $breadcrumbJsonLd = json_encode([ '@context' => 'https://schema.org', '@type' => 'BreadcrumbList', 'itemListElement' => $breadcrumbItems, ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); @endphp @if(!$product->is_active && auth()->user()?->is_admin)
Ce produit est masqué — visible uniquement par les administrateurs Modifier
@endif
{{-- Fil d'ariane --}}
{{-- Galerie --}} @php $galleryImages = $product->galleryImages(); $allImages = collect(); if ($product->featuredImage) $allImages->push($product->featuredImage); $allImages = $allImages->merge($galleryImages); @endphp
{{-- Image principale --}}
@if($allImages->isNotEmpty()) @foreach($allImages as $i => $img) {{ $img->alt ?: $product->name }}width && $img->height) width="{{ $img->width }}" height="{{ $img->height }}" @endif x-show="active === {{ $i }}" @if($i === 0) fetchpriority="high" style="display: block" @else loading="lazy" @endif class="w-full h-full object-cover cursor-zoom-in" @click="lightbox = true"> @endforeach {{-- Icône zoom --}}
@else
@endif
{{-- Miniatures si plusieurs images --}} @if($allImages->count() > 1)
@foreach($allImages as $i => $img) @endforeach
@endif {{-- Lightbox --}} @if($allImages->isNotEmpty())
{{ $product->name }}
@endif
{{-- Infos produit --}}
@if($product->brand)

{{ $product->brand->name }}

@endif

{{ $product->category?->name }}

{{ $product->name }}

{{-- Etoiles + lien avis --}}
@if($reviews->isNotEmpty()) @php $avgRating = round($reviews->avg('rating'), 1); @endphp
@for($i = 1; $i <= 5; $i++) @endfor
{{ $reviews->count() }} avis @else
@for($i = 1; $i <= 5; $i++) @endfor
Donner mon avis @endif
@if($product->tags->isNotEmpty())
@foreach($product->tags as $tag) {{ $tag->name }} @endforeach
@endif {{-- Prix --}}
@if($product->sale_price) {{ number_format($product->price, 2, ',', ' ') }} € @endif
{{-- Séparateur --}}
{{-- Description courte --}} @if($product->short_description)
{!! $product->short_description !!}
@endif {{-- Recommandation équipe --}} @if($product->team_recommendation)

Notre conseil

{{ $product->team_recommendation }}

@endif {{-- Stock --}} @if($product->stock_status !== 'instock')

Produit épuisé

@if(session('stock_alert'))

{{ session('stock_alert') }}

@else

Recevez une alerte dès son retour en stock :

@csrf
@error('email')

{{ $message }}

@enderror @endif
@endif {{-- Formulaire ajout panier --}}
@csrf {{-- Addons --}} @if($product->addonAssignments->isNotEmpty())
@foreach($product->addonAssignments as $assignment) @endforeach
@endif {{-- Personnalisation --}} @if($product->personalizable) @php $persoFonts = config('personalization.fonts', []); $persoColors = config('personalization.colors', []); $firstFont = array_key_first($persoFonts); $firstColor = array_key_first($persoColors); @endphp

Personnalisation

@if($product->personalization_price > 0) +{{ number_format($product->personalization_price, 2, ',', ' ') }} € @else Gratuit @endif
{{-- Texte --}}

50 caractères maximum

{{-- Police --}}
@foreach($persoFonts as $fontKey => $fontData) @endforeach
{{-- Couleur --}}
@foreach($persoColors as $colorKey => $colorData) @endforeach
{{-- Aperçu --}}

Aperçu

@endif {{-- Quantité + bouton --}}
{{-- Informations livraison --}} @if($product->stock_status === 'instock')
Livraison en point relais offerte dès 60 € — sinon 5,00 €
Livraison à domicile Colissimo — 7,90 €
Retrait gratuit à l'institut
@endif
{{-- Description complète --}} @if($product->description)

Tout savoir

Description

{!! $product->description !!}
@endif {{-- Sections (bienfaits, utilisation, composition) --}} @php $sections = [ ['key' => 'benefits', 'label' => 'Bienfaits', 'icon' => 'M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z', 'gradient' => 'linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%)', 'border' => '#a7f3d0', 'iconBg' => '#d1fae5', 'iconColor' => '#059669'], ['key' => 'usage_instructions', 'label' => 'Comment l\'utiliser', 'icon' => 'M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01', 'gradient' => 'linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%)', 'border' => '#93c5fd', 'iconBg' => '#dbeafe', 'iconColor' => '#2563eb'], ['key' => 'composition', 'label' => 'Composition', 'icon' => 'M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2', 'gradient' => 'linear-gradient(135deg, #fdf4ff 0%, #f3e8ff 100%)', 'border' => '#d8b4fe', 'iconBg' => '#f3e8ff', 'iconColor' => '#7c3aed'], ]; $activeSections = collect($sections)->filter(fn($s) => !empty($product->{$s['key']})); @endphp @if($activeSections->isNotEmpty())

En détail

Les essentiels à retenir

@foreach($sections as $section) @if(!empty($product->{$section['key']}))

{{ $section['label'] }}

{!! $product->{$section['key']} !!}
@endif @endforeach
@endif {{-- Avis clients --}}
@php $starPath = 'M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z'; @endphp {{-- En-tête + résumé --}}

Retours d'expérience

Avis clients @if($reviews->isNotEmpty()) ({{ $reviews->count() }}) @endif

@if($reviews->isNotEmpty()) @php $avgRating = round($reviews->avg('rating'), 1); $distrib = []; for ($s = 5; $s >= 1; $s--) { $distrib[$s] = $reviews->where('rating', $s)->count(); } @endphp {{-- Bloc note + distribution --}}
{{ number_format($avgRating, 1, ',', '') }}
@for($i = 1; $i <= 5; $i++) @endfor
sur 5
@foreach($distrib as $stars => $count) @php $pct = $reviews->count() > 0 ? round($count / $reviews->count() * 100) : 0; @endphp
{{ $stars }}
{{ $pct }}%
@endforeach
@endif
{{-- Liste des avis --}} @if($reviews->isNotEmpty())
@foreach($reviews as $index => $review) @php $initial = mb_strtoupper(mb_substr($review->author_name, 0, 1)); @endphp
{{-- Avatar initiale --}}
{{ $initial }}
{{ $review->author_name }} @if($review->is_verified_buyer) Achat vérifié @endif
{{ $review->created_at->diffForHumans() }}
@for($i = 1; $i <= 5; $i++) @endfor
@if($review->title)

{{ $review->title }}

@endif

{{ $review->body }}

@endforeach
@if($reviews->count() > 6)
@endif
@else

Aucun avis pour le moment. Soyez le premier à donner votre avis !

@endif {{-- Séparateur formulaire --}}

Votre expérience

Laisser un avis

@if(session('review_success'))

{{ session('review_success') }}

@else
@csrf {{-- Note --}}
@for($i = 1; $i <= 5; $i++) @endfor
@error('rating')

{{ $message }}

@enderror
@error('author_name')

{{ $message }}

@enderror

Non affiché publiquement

@error('author_email')

{{ $message }}

@enderror
@error('title')

{{ $message }}

@enderror
@error('body')

{{ $message }}

@enderror
@endif
{{-- Produits similaires --}} @if($related->isNotEmpty())

Boutique

Vous aimerez aussi

@foreach($related as $p) @endforeach
@endif