{% extends 'base_home.html.twig' %}
{% block title %}
{{ shop.name }}
| MaketOu
{% endblock %}
{% block stylesheets %}
<style>
/* Design eBay-like intégré avec Karma - Pleine largeur */
.shop-header {
background: #f7f7f7;
border-bottom: 1px solid #e1e1e1;
padding: 0;
margin-bottom: 0;
width: 100%;
position: relative;
}
.shop-banner {
width: 100%;
height: 350px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
/* Carrousel eBay-style - même largeur que shop-header-content */
.shop-carousel-ebay {
width: 100%;
height: 400px;
position: relative;
overflow: hidden;
background: #f8f9fa;
margin: 0 20px 0 20px;
border-radius: 8px;
box-sizing: border-box;
}
.carousel-container {
position: relative;
width: 100%;
height: 100%;
}
.carousel-slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
opacity: 0;
transition: opacity 0.5s ease-in-out;
}
.carousel-slide.active {
opacity: 1;
}
.carousel-controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
z-index: 10;
}
.carousel-btn {
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.9);
color: #333;
font-size: 16px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.carousel-btn:hover {
background: white;
transform: scale(1.1);
}
.carousel-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
.carousel-pause {
background: #dc3545;
color: white;
}
.carousel-pause:hover {
background: #c82333;
}
.carousel-indicators {
position: absolute;
bottom: 70px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
z-index: 10;
}
.carousel-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
.carousel-indicator.active {
background: white;
transform: scale(1.2);
}
/* Contrôles eBay-style intégrés */
.carousel-controls-ebay {
position: absolute;
top: 50%;
left: 0;
right: 0;
transform: translateY(-50%);
display: flex;
justify-content: space-between;
padding: 0 20px;
z-index: 10;
}
.carousel-btn-ebay {
width: 50px;
height: 50px;
border: none;
border-radius: 50%;
background: rgba(0, 0, 0, 0.7);
color: white;
font-size: 18px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
opacity: 0;
}
.shop-carousel-ebay:hover .carousel-btn-ebay {
opacity: 1;
}
.carousel-btn-ebay:hover {
background: rgba(0, 0, 0, 0.9);
transform: scale(1.1);
}
.carousel-btn-ebay:disabled {
opacity: 0.3;
cursor: not-allowed;
transform: none;
}
.carousel-btn-ebay.pause-btn {
background: rgba(220, 53, 69, 0.8);
}
.carousel-btn-ebay.pause-btn:hover {
background: rgba(220, 53, 69, 1);
}
/* Indicateurs eBay-style */
.carousel-indicators-ebay {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
z-index: 10;
}
.carousel-indicator-ebay {
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
border: 2px solid rgba(255, 255, 255, 0.8);
cursor: pointer;
transition: all 0.3s ease;
}
.carousel-indicator-ebay.active {
background: white;
border-color: white;
transform: scale(1.2);
}
.carousel-indicator-ebay:hover {
background: rgba(255, 255, 255, 0.8);
transform: scale(1.1);
}
/* Styles eBay-style pour les détails de boutique */
.shop-avatar-container-ebay {
position: relative;
margin-right: 20px;
}
.shop-avatar-ebay {
width: 80px;
height: 80px;
border-radius: 8px;
object-fit: cover;
border: 3px solid white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.verified-badge-ebay {
position: absolute;
bottom: -5px;
right: -5px;
background: #28a745;
color: white;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
border: 2px solid white;
}
.shop-info-ebay {
padding: 10px 0;
}
.shop-name-section {
margin-bottom: 8px;
}
.shop-name-ebay {
font-size: 1.8rem;
font-weight: 600;
color: #333;
margin: 0 15px 0 0;
display: inline-block;
}
.verified-text {
color: #28a745;
font-size: 0.9rem;
font-weight: 500;
}
.shop-category-section {
margin-bottom: 12px;
}
.shop-category-ebay {
background: #f8f9fa;
color: #666;
padding: 4px 12px;
border-radius: 16px;
font-size: 0.85rem;
font-weight: 500;
}
.shop-stats-ebay {
margin-top: 15px;
}
.stat-row {
display: flex;
gap: 30px;
margin-bottom: 10px;
}
.stat-item-ebay {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.stat-percentage {
font-size: 1.2rem;
font-weight: 700;
color: #28a745;
line-height: 1;
}
.stat-number-ebay {
font-size: 1.2rem;
font-weight: 700;
color: #333;
line-height: 1;
}
.stat-label-ebay {
font-size: 0.8rem;
color: #666;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-top: 2px;
}
.shop-additional-info {
display: flex;
gap: 20px;
font-size: 0.85rem;
color: #666;
}
.member-since {
font-weight: 400;
}
.location {
display: flex;
align-items: center;
}
.shop-actions-ebay {
display: flex;
flex-direction: column;
gap: 10px;
min-width: 140px;
}
.btn-ebay {
padding: 8px 16px;
font-size: 0.9rem;
font-weight: 500;
border-radius: 4px;
text-align: center;
transition: all 0.3s ease;
border-width: 1px;
}
.btn-ebay:hover {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.btn-ebay.following {
background: #28a745;
border-color: #28a745;
color: white;
}
/* Styles pour les avis */
.review-stats {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.stat-card {
padding: 15px;
}
.stat-number {
font-size: 2.5rem;
font-weight: 700;
color: #333;
margin: 0;
}
.stat-label {
color: #666;
font-size: 0.9rem;
margin: 5px 0 0;
}
.rating-stars {
color: #ffc107;
font-size: 1.2rem;
margin: 10px 0;
}
.reviews-preview {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.review-item {
border-bottom: 1px solid #f0f0f0;
padding: 15px 0;
}
.review-item:last-child {
border-bottom: none;
}
.review-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 10px;
}
.reviewer-info {
display: flex;
align-items: center;
gap: 10px;
}
.reviewer-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: #f8f9fa;
display: flex;
align-items: center;
justify-content: center;
color: #666;
}
.reviewer-name {
margin: 0;
font-size: 1rem;
font-weight: 600;
}
.review-rating {
color: #ffc107;
font-size: 0.9rem;
}
.review-meta {
text-align: right;
}
.review-date {
color: #666;
font-size: 0.8rem;
}
.verified-badge {
display: inline-block;
background: #28a745;
color: white;
padding: 2px 8px;
border-radius: 12px;
font-size: 0.7rem;
margin-left: 10px;
}
.review-comment {
margin: 10px 0 0;
line-height: 1.5;
color: #333;
}
.review-actions-card {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
text-align: center;
}
.shop-banner-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.3);
z-index: 1;
}
.shop-header-content {
background: white;
border: 1px solid #e1e1e1;
border-radius: 4px;
padding: 20px;
margin: 0 20px 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
z-index: 2;
}
.shop-avatar {
width: 80px;
height: 80px;
border-radius: 4px;
border: 1px solid #e1e1e1;
object-fit: cover;
position: relative;
z-index: 3;
}
.shop-title {
font-size: 1.5rem;
font-weight: 600;
color: #333;
margin-bottom: 8px;
}
.shop-subtitle {
color: #666;
font-size: 0.9rem;
margin-bottom: 15px;
}
.shop-stats-row {
display: flex;
align-items: center;
gap: 20px;
flex-wrap: wrap;
margin-bottom: 15px;
}
.shop-stat-item {
display: flex;
align-items: center;
gap: 5px;
font-size: 0.9rem;
}
.positive-feedback {
color: #007bff;
font-weight: 600;
}
.items-sold {
color: #666;
}
.followers-count {
color: #666;
}
.shop-badges {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.shop-badge {
background: #f0f0f0;
color: #333;
padding: 4px 8px;
border-radius: 3px;
font-size: 0.8rem;
font-weight: 500;
}
.shop-badge.verified {
background: #d4edda;
color: #155724;
}
.shop-badge.premium {
background: #fff3cd;
color: #856404;
}
.shop-actions-row {
display: flex;
align-items: center;
gap: 15px;
flex-wrap: wrap;
}
.shop-action-btn {
background: #007bff;
color: white;
border: none;
padding: 8px 16px;
border-radius: 3px;
font-size: 0.9rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 5px;
}
.shop-action-btn:hover {
background: #0056b3;
color: white;
}
.shop-action-btn.following {
background: #28a745;
}
.shop-action-btn.following:hover {
background: #1e7e34;
}
.shop-action-btn.secondary {
background: #6c757d;
}
.shop-action-btn.secondary:hover {
background: #545b62;
}
/* Onglets eBay-style avec classes Karma */
.shop-tabs {
background: white;
border: 1px solid #e1e1e1;
border-top: none;
border-radius: 0 0 4px 4px;
margin-top: 0;
}
.shop-tabs-nav {
display: flex;
border-bottom: 1px solid #e1e1e1;
margin: 0;
padding: 0;
list-style: none;
background: #f8f9fa;
}
.shop-tab {
margin: 0;
}
.shop-tab-link {
display: block;
padding: 12px 20px;
color: #000000;
text-decoration: none;
border-bottom: 2px solid transparent;
transition: all 0.2s;
font-weight: 500;
font-size: 1rem;
}
.shop-tab-link:hover,
.shop-tab-link.active {
color: #095ad3;
border-bottom-color: #095ad3;
background: #ffa200;
}
.shop-tab-content {
padding: 30px;
min-height: 400px;
}
.shop-tab-content:not(.active) {
display: none;
}
.shop-tab-content.active {
display: block;
}
/* Cards d'information avec style Karma */
.shop-info-card {
background: #f8f9fa;
border: 1px solid #e1e1e1;
border-radius: 4px;
padding: 20px;
margin-bottom: 20px;
}
.shop-info-card h6 {
color: #333;
font-weight: 600;
margin-bottom: 15px;
font-size: 1.1rem;
}
.shop-info-card p {
color: #666;
font-size: 0.9rem;
margin: 0;
line-height: 1.5;
}
.shop-contact-info {
display: flex;
flex-direction: column;
gap: 10px;
}
.shop-contact-item {
display: flex;
align-items: center;
gap: 10px;
font-size: 0.9rem;
color: #666;
padding: 5px 0;
}
.shop-contact-item i {
width: 16px;
color: #007bff;
text-align: center;
}
.shop-social-links {
display: flex;
gap: 10px;
margin-top: 15px;
flex-wrap: wrap;
}
.shop-social-link {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
background: #f0f0f0;
color: #666;
border-radius: 4px;
text-decoration: none;
transition: all 0.2s;
font-size: 1.1rem;
}
.shop-social-link:hover {
background: #007bff;
color: white;
transform: translateY(-2px);
}
/* Produits avec style Karma */
.product-card {
background: white;
border: 1px solid #e1e1e1;
border-radius: 4px;
overflow: hidden;
transition: all 0.3s ease;
margin-bottom: 20px;
}
.product-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
/* Animation de tri des produits */
.product-item {
transition: all 0.3s ease;
}
.product-item.sorting {
opacity: 0;
transform: translateY(20px);
}
.product-item.sorted {
opacity: 1;
transform: translateY(0);
}
.product-image {
height: 200px;
background-size: cover;
background-position: center;
position: relative;
overflow: hidden;
}
.product-info {
padding: 15px;
}
.product-title {
font-size: 1rem;
font-weight: 600;
margin-bottom: 8px;
color: #333;
line-height: 1.3;
}
.product-title a {
color: #333;
text-decoration: none;
}
.product-title a:hover {
color: #007bff;
}
.product-price {
font-size: 1.2rem;
font-weight: bold;
color: #ff6b35;
margin-bottom: 10px;
}
.product-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.85rem;
color: #666;
}
.rating {
color: #ffc107;
}
/* Responsive avec classes Karma */
/* Responsive amélioré pour la page shop */
@media(max-width: 991.98px) {
.shop-carousel-ebay {
margin: 0 10px;
height: 300px;
}
.shop-header-content {
padding: 15px;
margin: 0 10px 20px;
}
.shop-header-content .row {
flex-wrap: wrap;
}
.shop-info-ebay {
margin-top: 15px;
}
}
@media(max-width: 768px) {
.shop-banner,
.shop-carousel-ebay {
height: 250px;
margin: 0;
border-radius: 0;
}
.shop-carousel-ebay .carousel-container {
border-radius: 0;
}
.carousel-controls-ebay {
padding: 0 10px;
bottom: 15px;
}
.carousel-btn-ebay {
width: 35px;
height: 35px;
font-size: 14px;
}
.carousel-indicators-ebay {
bottom: 10px;
gap: 6px;
}
.carousel-indicator-ebay {
width: 10px;
height: 10px;
}
.shop-header-content {
padding: 15px;
margin: 0;
}
.shop-header-content .container {
padding-left: 15px;
padding-right: 15px;
}
.shop-avatar {
width: 60px;
height: 60px;
}
.shop-title {
font-size: 1.2rem;
}
.shop-actions-row {
flex-direction: column;
gap: 10px;
}
/* Styles eBay-style responsive */
.shop-header-content .row {
flex-direction: column;
text-align: center;
}
.shop-avatar-container-ebay {
margin-right: 0;
margin-bottom: 15px;
align-self: center;
}
.shop-avatar-ebay {
width: 80px;
height: 80px;
}
.shop-name-ebay {
font-size: 1.5rem;
margin-right: 0;
margin-bottom: 10px;
}
.stat-row {
justify-content: center;
gap: 15px;
flex-wrap: wrap;
}
.stat-item-ebay {
font-size: 0.9rem;
min-width: 100px;
}
.shop-additional-info {
justify-content: center;
flex-wrap: wrap;
}
.shop-actions-ebay {
flex-direction: column;
justify-content: center;
min-width: auto;
margin-top: 15px;
width: 100%;
}
.btn-ebay {
width: 100%;
min-width: auto;
margin-bottom: 10px;
}
.btn-shop,
.shop-action-btn {
width: 100%;
min-width: auto;
height: 45px;
font-size: 0.9rem;
padding: 12px 20px;
}
.shop-tabs-nav {
flex-wrap: wrap;
justify-content: center;
}
.shop-tab-link {
font-size: 0.85rem;
padding: 0.5rem 0.75rem;
flex: 1;
min-width: auto;
}
/* Produits responsive */
#products-container .product-item {
margin-bottom: 20px;
}
.product-card {
padding: 15px;
}
.product-title {
font-size: 0.95rem;
}
.product-price {
font-size: 1.1rem;
}
/* Détails de la boutique responsive */
.shop-info-ebay {
text-align: center;
}
}
@media(max-width: 575.98px) {
.shop-banner,
.shop-carousel-ebay {
height: 200px;
margin: 0;
}
.shop-header-content {
margin: 0;
padding: 15px;
}
.shop-name-ebay {
font-size: 1.3rem;
}
.stat-row {
gap: 10px;
flex-direction: column;
}
.stat-item-ebay {
font-size: 0.85rem;
width: 100%;
}
.carousel-btn-ebay {
width: 25px;
height: 25px;
font-size: 10px;
}
.carousel-indicators-ebay {
bottom: 8px;
}
.carousel-indicator-ebay {
width: 6px;
height: 6px;
}
.shop-tab-content {
padding: 15px 10px;
}
.shop-stats-row {
flex-direction: column;
gap: 10px;
align-items: flex-start;
}
}
.follow-button {
background: #ffa200;
border: none;
color: white;
padding: 12px 30px;
border-radius: 25px;
font-weight: 600;
transition: all 0.3s ease;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 8px;
}
.follow-button:hover {
background: #e8910a;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(255, 162, 0, 0.3);
}
.follow-button.following {
background: #28a745;
}
.follow-button.following:hover {
background: #218838;
}
.follow-button:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.follow-stats {
display: flex;
gap: 30px;
margin-top: 20px;
flex-wrap: wrap;
}
.follow-stat {
text-align: center;
padding: 15px;
background: #f8f9fa;
border-radius: 10px;
min-width: 120px;
}
.follow-stat-number {
font-size: 1.8rem;
font-weight: bold;
color: #ffa200;
display: block;
}
.follow-stat-label {
color: #666;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.shop-actions {
display: flex;
gap: 15px;
align-items: center;
flex-wrap: wrap;
margin-top: 20px;
}
.action-button {
background: white;
border: 2px solid #ffa200;
color: #ffa200;
padding: 10px 20px;
border-radius: 20px;
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 8px;
}
.action-button:hover {
background: #ffa200;
color: white;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(255, 162, 0, 0.3);
}
.positive-feedback {
color: #28a745;
font-weight: bold;
}
.items-sold {
color: #666;
font-size: 0.9rem;
}
.followers-count {
color: #666;
font-size: 0.9rem;
}
.shop-avatar {
width: 120px;
height: 120px;
border-radius: 50%;
border: 4px solid white;
object-fit: cover;
margin-bottom: 20px;
}
.shop-stats {
background: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
margin-top: -50px;
position: relative;
z-index: 10;
}
.stat-item {
text-align: center;
padding: 20px;
}
.stat-number {
font-size: 2.5rem;
font-weight: bold;
color: #ffa200;
display: block;
}
.stat-label {
color: #666;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 1px;
}
.shop-description {
background: #f8f9fa;
padding: 30px;
border-radius: 10px;
margin-bottom: 40px;
}
.shop-contact {
background: white;
border: 1px solid #e9ecef;
border-radius: 10px;
padding: 25px;
margin-bottom: 40px;
}
.contact-item {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.contact-item i {
color: #ffa200;
margin-right: 15px;
width: 20px;
}
.product-card {
background: white;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
margin-bottom: 30px;
}
.product-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
.product-image {
height: 200px;
background-size: cover;
background-position: center;
position: relative;
}
.product-info {
padding: 20px;
}
.product-title {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 10px;
color: #333;
}
.product-price {
font-size: 1.3rem;
font-weight: bold;
color: #ffa200;
margin-bottom: 15px;
}
.product-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.9rem;
color: #666;
}
.rating {
color: #ffa200;
}
/* Boutons d'action uniformes */
.btn-shop,
.shop-action-btn {
background: #ffa200;
border: 1px solid #ffa200;
color: white;
padding: 12px 24px;
border-radius: 6px;
font-weight: 500;
font-size: 0.9rem;
transition: all 0.3s ease;
text-decoration: none;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
min-width: 120px;
height: 44px;
white-space: nowrap;
}
.btn-shop:hover,
.shop-action-btn:hover {
background: #e8910a;
border-color: #e8910a;
color: white;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(255, 162, 0, 0.3);
}
/* Boutons secondaires */
.shop-action-btn.secondary {
background: transparent;
border: 1px solid #6c757d;
color: #6c757d;
}
.shop-action-btn.secondary:hover {
background: #6c757d;
border-color: #6c757d;
color: white;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(108, 117, 125, 0.3);
}
/* Responsive */
@media(max-width: 768px) {
.shop-header {
padding: 100px 0 40px;
}
.shop-avatar {
width: 80px;
height: 80px;
}
.shop-stats {
margin-top: -30px;
padding: 20px;
}
.stat-number {
font-size: 2rem;
}
}
/* Très petits écrans */
@media(max-width: 480px) {
.btn-shop,
.shop-action-btn {
min-width: 90px;
height: 38px;
font-size: 0.8rem;
padding: 8px 16px;
}
.shop-actions-row {
gap: 8px;
}
}
/* Styles pour la section des avis */
.review-stats-card {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.stats-header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.overall-rating {
text-align: center;
margin-right: 20px;
}
.rating-number {
font-size: 36px;
font-weight: bold;
color: #333;
display: block;
}
.stars {
color: #ffc107;
font-size: 18px;
margin-top: 5px;
}
.rating-summary p {
margin: 0;
color: #666;
}
.rating-breakdown {
margin-top: 15px;
}
.rating-bar {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.rating-label {
width: 40px;
font-size: 14px;
color: #666;
}
.rating-progress {
flex: 1;
height: 6px;
background: #e9ecef;
border-radius: 3px;
margin: 0 10px;
overflow: hidden;
}
.rating-fill {
height: 100%;
background: linear-gradient(45deg, #ffc107, #ff8c00);
transition: width 0.3s ease;
}
.rating-count {
width: 30px;
text-align: right;
font-size: 14px;
color: #666;
}
.reviews-preview {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.review-card-preview {
border-bottom: 1px solid #f0f0f0;
padding-bottom: 15px;
margin-bottom: 15px;
}
.review-card-preview:last-child {
border-bottom: none;
margin-bottom: 0;
}
.review-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.review-user {
display: flex;
align-items: center;
}
.user-avatar {
width: 35px;
height: 35px;
border-radius: 50%;
background: linear-gradient(45deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
margin-right: 10px;
}
.user-info h6 {
margin: 0;
font-size: 14px;
font-weight: 600;
color: #333;
}
.user-info small {
color: #666;
font-size: 12px;
}
.review-rating {
display: flex;
align-items: center;
gap: 5px;
}
.verified-badge {
background: #28a745;
color: white;
padding: 2px 4px;
border-radius: 3px;
font-size: 10px;
font-weight: bold;
}
.review-content {
color: #666;
font-size: 14px;
line-height: 1.5;
}
.empty-reviews {
text-align: center;
padding: 40px 20px;
color: #666;
}
.empty-reviews i {
font-size: 48px;
color: #ddd;
margin-bottom: 15px;
}
.empty-reviews h4 {
color: #333;
margin-bottom: 10px;
}
.section-title h2 {
color: #333;
margin-bottom: 10px;
}
.section-title p {
color: #666;
margin-bottom: 30px;
}
@media(max-width: 768px) {
.stats-header {
flex-direction: column;
text-align: center;
}
.overall-rating {
margin-right: 0;
margin-bottom: 15px;
}
.review-header {
flex-direction: column;
align-items: flex-start;
}
.review-rating {
margin-top: 5px;
}
}
</style>
{% endblock %}
{% block body %}
<!-- Shop Header eBay-style avec Karma - Pleine largeur -->
<section
class="shop-header">
<!-- Carrousel eBay-style -->
<div class="shop-carousel-ebay">
<div class="carousel-container">
{% set allBannerImages = shop.getAllBannerImages() %}
{% if allBannerImages|length > 0 %}
{% for image in allBannerImages %}
<div class="carousel-slide {% if loop.first %}active{% endif %}" style="background-image: url('{{ asset(image) }}')">
<div class="shop-banner-overlay"></div>
</div>
{% endfor %}
{% else %}
<!-- Slide par défaut avec dégradé si aucune image de bannière -->
<div class="carousel-slide active" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);">
<div class="shop-banner-overlay"></div>
</div>
{% endif %}
</div>
<!-- Contrôles eBay-style intégrés - uniquement si plusieurs images de bannière -->
{% set totalBannerImages = allBannerImages|length %}
{% if totalBannerImages > 1 %}
<div class="carousel-controls-ebay">
<button class="carousel-btn-ebay prev-btn" onclick="previousSlide()" id="prevBtn">
<i class="lnr lnr-chevron-left"></i>
</button>
<button class="carousel-btn-ebay pause-btn" onclick="toggleCarousel()" id="pauseBtn">
<i class="lnr lnr-pause" id="pauseIcon"></i>
</button>
<button class="carousel-btn-ebay next-btn" onclick="nextSlide()" id="nextBtn">
<i class="lnr lnr-chevron-right"></i>
</button>
</div>
<!-- Indicateurs eBay-style - uniquement pour les images de bannière -->
<div class="carousel-indicators-ebay">
{% for image in allBannerImages %}
<button class="carousel-indicator-ebay {% if loop.first %}active{% endif %}" onclick="goToSlide({{ loop.index0 }})"></button>
{% endfor %}
</div>
{% endif %}
</div>
<!-- Contenu de la boutique eBay-style -->
<div class="shop-header-content">
<div
class="row align-items-center">
<!-- Logo de la boutique -->
<div class="col-auto">
<div class="shop-avatar-container-ebay">
{% if shop.logo %}
<img src="{{ asset(shop.logo) }}" alt="{{ shop.name }}" class="shop-avatar-ebay">
{% else %}
<div class="shop-avatar-ebay" style="background: #f0f0f0; display: flex; align-items: center; justify-content: center; font-size: 2rem; color: #666;">
<i class="lnr lnr-store"></i>
</div>
{% endif %}
{% if shop.isVerified %}
<div class="verified-badge-ebay">
<i class="lnr lnr-checkmark-circle"></i>
</div>
{% endif %}
</div>
</div>
<!-- Informations principales -->
<div class="col">
<div
class="shop-info-ebay">
<!-- Nom de la boutique -->
<div class="shop-name-section">
<h1 class="shop-name-ebay">{{ shop.name }}</h1>
{% if shop.isVerified %}
<span class="verified-text">
<i class="lnr lnr-checkmark-circle me-1"></i>Vendeur vérifié
</span>
{% endif %}
</div>
<!-- Catégorie -->
{% if shop.shopCategory %}
<div class="shop-category-section">
<span class="shop-category-ebay">{{ shop.shopCategory.name }}</span>
</div>
{% endif %}
<!-- Statistiques eBay-style -->
<div class="shop-stats-ebay">
<div class="stat-row">
{% if shop.averageRating > 0 %}
<div class="stat-item-ebay">
<span class="stat-percentage">{{ shop.averageRating|number_format(1) }}%</span>
<span class="stat-label-ebay">Évaluations positives</span>
</div>
{% endif %}
{% if stats.totalProductSales > 0 %}
<div class="stat-item-ebay">
<span class="stat-number-ebay">{{ stats.totalProductSales|number_format }}</span>
<span class="stat-label-ebay">Articles vendus</span>
</div>
{% endif %}
{% if followStats.active_follows > 0 %}
<div class="stat-item-ebay">
<span class="stat-number-ebay">{{ followStats.active_follows|number_format }}</span>
<span class="stat-label-ebay">Suiveurs</span>
</div>
{% endif %}
</div>
<!-- Informations supplémentaires -->
<div class="shop-additional-info">
<div class="row">
<div class="col-12">
<span class="member-since col-md-3 col-sm-6 w-100">
<i class="lnr lnr-thumbs-up"></i>
7% positive feedback</span>
<span class="member-since col-md-3 col-sm-6 w-100">
<i class="lnr lnr-cart"></i>
29 produits vendus</span>
<span class="member-since col-md-3 col-sm-6 w-100">
<i class="lnr lnr-star"></i>
150 followers</span>
<span class="member-since col-md-3 w-100">
<i class="lnr lnr-history"></i>
Créé depuis
{{ shop.createdAt|date('M Y') }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Actions eBay-style -->
<div class="col-auto">
<div class="shop-actions-ebay">
{% if app.user %}
<button id="follow-button" class="btn btn-primary btn-ebay {% if isFollowing %}following{% endif %}" data-shop-id="{{ shop.id }}" data-following="{{ isFollowing ? 'true' : 'false' }}">
<span id="follow-text">
{% if isFollowing %}
<i class="lnr lnr-checkmark-circle me-1"></i> Suivi
{% else %}
<i class="lnr lnr-plus me-1"></i> Suivre
{% endif %}
</span>
</button>
{% else %}
<a href="{{ path('ui_app_login') }}" class="btn btn-primary btn-ebay">
<i class="lnr lnr-user me-1"></i> Se connecter pour suivre
</a>
{% endif %}
<button class="btn btn-outline-secondary btn-ebay" onclick="shareShop()">
<i class="lnr lnr-bubble me-1"></i> Partager
</button>
<button class="btn btn-outline-danger btn-ebay" onclick="reportShop()">
<i class="lnr lnr-flag me-1"></i> Signaler
</button>
{% if canEdit %}
<a href="{{ path('seller_shop_edit', {slug: shop.slug}) }}" class="btn btn-outline-primary btn-ebay">
<i class="lnr lnr-pencil me-1"></i> Modifier la boutique
</a>
{% endif %}
</div>
</div>
</div>
</div>
</section>
<!-- Shop Tabs eBay-style avec Karma -->
<section class="container">
<div class="shop-tabs">
<ul class="nav nav-tabs shop-tabs-nav" role="tablist">
<li class="nav-item shop-tab">
<a href="#shop-items" class="nav-link shop-tab-link active" data-tab="items" role="tab">
Boutique
</a>
</li>
<li class="nav-item shop-tab">
<a href="#shop-sale" class="nav-link shop-tab-link" data-tab="sale" role="tab">
Promotions
</a>
</li>
<li class="nav-item shop-tab">
<a href="#shop-about" class="nav-link shop-tab-link" data-tab="about" role="tab">
À propos
</a>
</li>
<li class="nav-item shop-tab">
<a href="#shop-feedback" class="nav-link shop-tab-link" data-tab="feedback" role="tab">
Avis ({{ shop.getVisibleReviewsCount() }})
</a>
</li>
</ul>
<!-- Tab Content: Shop Items avec Karma -->
<div id="shop-items" class="tab-content shop-tab-content active">
<div class="row">
<div class="col-lg-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<h4 class="mb-0">Produits de
{{ shop.name }}</h4>
<div class="d-flex align-items-center gap-3">
<span style="font-size: 2rem; font-weight: 600; min-width: 100px; display: inline-block; text-align: center;">
<span class="product-count">{{ products|length|number_format }}</span>
<span style="font-size: 1rem; font-weight: 400;">produits</span>
</span>
<select class="form-select" id="product-sort" style="width: auto;" onchange="if(window.sortProducts) window.sortProducts(this.value);">
<option value="">Trier par</option>
<option value="price_asc">Prix : Croissant</option>
<option value="price_desc">Prix : Décroissant</option>
<option value="newest">Plus récents</option>
<option value="popular">Plus populaires</option>
<option value="name_asc">Nom : A-Z</option>
<option value="name_desc">Nom : Z-A</option>
</select>
</div>
</div>
{% if products|length > 0 %}
<div class="row" id="products-container">
{% for product in products %}
<div class="col-xl-3 col-lg-4 col-md-6 col-sm-6 mb-4 d-flex align-items-stretch product-item" data-price="{{ product.price }}" data-name="{{ product.name|lower }}" data-views="{{ product.viewCount ?? 0 }}" data-created="{{ product.publishedAt|date('Y-m-d') }}">
{% include 'home/_single_product_card.html.twig' with {'product': product} %}
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-5">
<i class="lnr lnr-package" style="font-size: 4rem; color: #ccc;"></i>
<h4 class="mt-3">Aucun produit disponible</h4>
<p class="text-muted">Cette boutique n'a pas encore de produits en vente.</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Tab Content: Sale avec Karma -->
<div id="shop-sale" class="tab-content shop-tab-content">
<div class="text-center py-5">
<i class="lnr lnr-tag" style="font-size: 4rem; color: #ccc;"></i>
<h4 class="mt-3">Aucune promotion actuellement</h4>
<p class="text-muted">Cette boutique n'a pas de promotions actives pour le moment.</p>
</div>
</div>
<!-- Tab Content: About avec Karma -->
<div id="shop-about" class="tab-content shop-tab-content">
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="lnr lnr-user me-2"></i>À propos de
{{ shop.name }}
</h5>
</div>
<div class="card-body">
{% if shop.description %}
<p class="card-text">{{ shop.description }}</p>
{% else %}
<p class="text-muted">Aucune description disponible.</p>
{% endif %}
{% if shop.businessHours %}
<h6 class="mt-4">
<i class="lnr lnr-clock me-2"></i>Heures d'ouverture
</h6>
<p>{{ shop.businessHours }}</p>
{% endif %}
{% if shop.returnPolicy %}
<h6 class="mt-4">
<i class="lnr lnr-undo me-2"></i>Politique de retour
</h6>
<p>{{ shop.returnPolicy }}</p>
{% endif %}
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card shop-info-card">
<div class="card-header">
<h6 class="mb-0">
<i class="lnr lnr-chart me-2"></i>Statistiques de la boutique
</h6>
</div>
<div class="card-body">
<div class="row text-center">
<div class="col-6">
<div class="shop-stat-item">
<span class="stat-number h4 text-primary">{{ stats.activeProducts }}</span>
<span class="stat-label d-block">Produits actifs</span>
</div>
</div>
<div class="col-6">
<div class="shop-stat-item">
<span class="stat-number h4 text-info">{{ stats.shopViews }}</span>
<span class="stat-label d-block">Vues boutique</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Tab Content: Feedback avec Karma -->
<div id="shop-feedback" class="tab-content shop-tab-content">
<div class="row">
<div
class="col-lg-8">
<!-- Statistiques des avis -->
<div class="review-stats mb-4">
<div class="row">
<div class="col-md-4">
<div class="stat-card text-center">
<h3 class="stat-number">{{ shop.getAverageRating() }}</h3>
<div class="rating-stars">
{% for i in 1..5 %}
<i class="lnr lnr-star{% if i <= shop.getAverageRating() %}{% else %}-empty{% endif %}"></i>
{% endfor %}
</div>
<p class="stat-label">Note moyenne</p>
</div>
</div>
<div class="col-md-4">
<div class="stat-card text-center">
<h3 class="stat-number">{{ shop.getVisibleReviewsCount() }}</h3>
<p class="stat-label">Avis clients</p>
</div>
</div>
<div class="col-md-4">
<div class="stat-card text-center">
<h3 class="stat-number">{{ ((shop.getVisibleReviewsCount() / 100) * 100)|round }}%</h3>
<p class="stat-label">Satisfaction</p>
</div>
</div>
</div>
</div>
<!-- Liste des avis récents -->
<div class="reviews-preview">
<h5 class="mb-3">Avis récents</h5>
{% if shop.reviews|length > 0 %}
<div class="reviews-list">
{% for review in shop.reviews|slice(0, 5) %}
{% if review.isVisible %}
<div class="review-item">
<div class="review-header">
<div class="reviewer-info">
<div class="reviewer-avatar">
<i class="lnr lnr-user"></i>
</div>
<div class="reviewer-details">
<h6 class="reviewer-name">{{ review.user.userIdentifier }}</h6>
<div class="review-rating">
{% for i in 1..5 %}
<i class="lnr lnr-star{% if i <= review.rating %}{% else %}-empty{% endif %}"></i>
{% endfor %}
</div>
</div>
</div>
<div class="review-meta">
<span class="review-date">{{ review.createdAt|date('d/m/Y') }}</span>
{% if review.isVerified %}
<span class="verified-badge">
<i class="lnr lnr-checkmark-circle"></i>
Vérifié
</span>
{% endif %}
</div>
</div>
{% if review.comment %}
<div class="review-comment">
<p>{{ review.comment|length > 150 ? review.comment|slice(0, 150) ~ '...' : review.comment }}</p>
</div>
{% endif %}
</div>
{% endif %}
{% endfor %}
</div>
<div class="text-center mt-4">
<a href="{{ path('shop_reviews_index', {'slug': shop.slug}) }}" class="btn btn-primary">
<i class="lnr lnr-star me-1"></i>Voir tous les avis
</a>
</div>
{% else %}
<div class="text-center py-4">
<i class="lnr lnr-star" style="font-size: 3rem; color: #ccc;"></i>
<h5 class="mt-3">Aucun avis pour le moment</h5>
<p class="text-muted">Cette boutique n'a pas encore reçu d'avis clients.</p>
</div>
{% endif %}
</div>
</div>
<div
class="col-lg-4">
<!-- Lien vers la page complète des avis -->
<div class="review-actions-card">
<h5>Évaluer cette boutique</h5>
<p class="text-muted">Partagez votre expérience avec cette boutique.</p>
<a href="{{ path('shop_reviews_new', {'slug': shop.slug}) }}" class="btn btn-primary w-100">
<i class="lnr lnr-star me-1"></i>Laisser un avis
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Modal de signalement -->
<div class="modal fade" id="reportModal" tabindex="-1" aria-labelledby="reportModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="reportModalLabel">
<i class="lnr lnr-flag me-2"></i> Signaler cette boutique
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="reportForm">
<div class="mb-3">
<label for="reportReason" class="form-label">Motif du signalement *</label>
<select class="form-select" id="reportReason" required>
<option value="">Sélectionnez un motif</option>
<option value="fake_products">Produits contrefaits</option>
<option value="inappropriate_content">Contenu inapproprié</option>
<option value="spam">Spam ou publicité abusive</option>
<option value="fraud">Fraude ou escroquerie</option>
<option value="harassment">Harcèlement</option>
<option value="other">Autre</option>
</select>
</div>
<div class="mb-3">
<label for="reportDescription" class="form-label">Description détaillée *</label>
<textarea class="form-control" id="reportDescription" rows="4" placeholder="Décrivez le problème rencontré..." required></textarea>
</div>
<div class="mb-3">
<label for="reportEmail" class="form-label">Votre email (optionnel)</label>
<input type="email" class="form-control" id="reportEmail" placeholder="votre@email.com">
<div class="form-text">Nous pourrons vous contacter pour plus d'informations</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<button type="button" class="btn btn-danger" onclick="submitReport()">
<i class="lnr lnr-flag me-2"></i>Envoyer le signalement
</button>
</div>
</div>
</div>
</div>
<!-- Section des avis -->
<div class="container my-5">
<div class="row">
<div class="col-12">
<div class="section-title text-center">
<h2>Avis clients</h2>
<p>Découvrez ce que pensent nos clients de cette boutique</p>
</div>
</div>
</div>
<div
class="row">
<!-- Statistiques des avis -->
<div class="col-md-4">
<div class="review-stats-card">
<div class="stats-header">
<div class="overall-rating">
<span class="rating-number">{{ shop.reviews|length > 0 ? (shop.reviews|map(r => r.rating)|reduce((a, b) => a + b) / shop.reviews|length)|number_format(1) : '0.0' }}</span>
<div class="stars">
{% set avgRating = shop.reviews|length > 0 ? (shop.reviews|map(r => r.rating)|reduce((a, b) => a + b) / shop.reviews|length) : 0 %}
{% for i in 1..5 %}
{% if i <= avgRating %}
★
{% elseif i - avgRating < 1 %}
☆
{% else %}
☆
{% endif %}
{% endfor %}
</div>
</div>
<div class="rating-summary">
<p class="mb-1">{{ shop.reviews|length }}
avis</p>
<p class="text-muted small">Basé sur
{{ shop.reviews|filter(r => r.isVerified)|length }}
avis vérifiés</p>
</div>
</div>
<div class="rating-breakdown">
{% for rating in 5..1 %}
{% set count = shop.reviews|filter(r => r.rating == rating)|length %}
{% set percentage = shop.reviews|length > 0 ? (count / shop.reviews|length * 100) : 0 %}
<div class="rating-bar">
<span class="rating-label">{{ rating }}★</span>
<div class="rating-progress">
<div class="rating-fill" style="width: {{ percentage }}%"></div>
</div>
<span class="rating-count">{{ count }}</span>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Aperçu des avis -->
<div class="col-md-8">
<div class="reviews-preview">
{% if shop.reviews|length > 0 %}
{% for review in shop.reviews|slice(0, 3) %}
<div class="review-card-preview">
<div class="review-header">
<div class="review-user">
<div class="user-avatar">
{{ review.user.firstName|first|upper|default(review.user.email|first|upper) }}
</div>
<div class="user-info">
<h6>{{ review.user.firstName|default('Utilisateur') }}</h6>
<small>{{ review.getTimeAgo() }}</small>
</div>
</div>
<div class="review-rating">
<div class="stars">{{ review.getRatingStars() }}</div>
{% if review.isVerified %}
<span class="verified-badge">✓</span>
{% endif %}
</div>
</div>
<div class="review-content">
{{ review.comment|slice(0, 150) }}
{% if review.comment|length > 150 %}...
{% endif %}
</div>
</div>
{% endfor %}
<div class="text-center mt-3">
<a href="{{ path('shop_reviews_index', {'slug': shop.slug}) }}" class="btn btn-outline-primary">
Voir tous les avis ({{ shop.reviews|length }})
</a>
</div>
{% else %}
<div class="empty-reviews">
<i class="lnr lnr-star"></i>
<h4>Aucun avis pour le moment</h4>
<p>Soyez le premier à laisser un avis sur cette boutique !</p>
{% if app.user %}
<a href="{{ path('shop_reviews_new', {'slug': shop.slug}) }}" class="btn btn-primary">
<i class="lnr lnraccount_recently_viewed-star"></i>
Laisser un avis
</a>
{% endif %}
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block javascripts %}
<script>
document.addEventListener('DOMContentLoaded', function () { // Initialisation du carrousel
initCarousel();
// Gestion des onglets eBay-style avec Bootstrap
const tabLinks = document.querySelectorAll('.shop-tab-link');
const tabContents = document.querySelectorAll('.shop-tab-content');
tabLinks.forEach(link => {
link.addEventListener('click', function (e) {
e.preventDefault();
// Retirer la classe active de tous les liens et contenus
tabLinks.forEach(l => {
l.classList.remove('active');
l.setAttribute('aria-selected', 'false');
});
tabContents.forEach(c => c.classList.remove('active'));
// Ajouter la classe active au lien cliqué
this.classList.add('active');
this.setAttribute('aria-selected', 'true');
// Afficher le contenu correspondant
const targetTab = this.dataset.tab;
const targetContent = document.getElementById (`shop-${targetTab}`);
if (targetContent) {
targetContent.classList.add('active');
}
});
});
// Gestion du système de follow
const followButton = document.getElementById('follow-button');
if (followButton) {
followButton.addEventListener('click', function () {
const shopId = this.dataset.shopId;
const isFollowing = this.dataset.following === 'true';
// Désactiver le bouton pendant la requête
this.disabled = true;
const originalText = this.innerHTML;
this.innerHTML = '<i class="lnr lnr-spinner"></i> Loading...';
// Envoyer la requête
fetch("{{ path('ui_api_shop_toggle_follow', {id: '__SHOP_ID__'}) }}".replace('__SHOP_ID__', shopId), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
}).then(response => response.json()).then(data => {
if (data.success) { // Mettre à jour l'interface
this.dataset.following = data.isFollowing;
if (data.isFollowing) {
this.classList.add('following');
this.innerHTML = '<i class="lnr lnr-checkmark"></i> Suivi';
} else {
this.classList.remove('following');
this.innerHTML = '<i class="lnr lnr-plus"></i> Suivre';
}
// Mettre à jour le compteur de followers
if (followersCount && data.followersCount !== undefined) {
followersCount.textContent = data.followersCount.toLocaleString();
}
// Afficher un message de confirmation
showNotification(data.message, 'success');
} else {
showNotification(data.message, 'error');
}
}).catch(error => {
console.error('Erreur:', error);
showNotification('Une erreur est survenue', 'error');
}). finally(() => {
this.disabled = false;
});
});
}
// Fonction pour afficher les notifications
function showNotification(message, type = 'info') { // Créer l'élément de notification
const notification = document.createElement('div');
notification.className = `alert alert-${
type === 'success' ? 'success' : type === 'error' ? 'danger' : 'info'
} alert-dismissible fade show position-fixed`;
notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
notification.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(notification);
// Supprimer automatiquement après 5 secondes
setTimeout(() => {
if (notification.parentNode) {
notification.remove();
}
}, 5000);
}
// Fonctions pour les actions de boutique
window.shareShop = function () { // Vérifier si l'API Web Share est disponible et si on est sur mobile
if (navigator.share && /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
navigator.share({title: '{{ shop.name }}- Boutique sur MaketOu', text: 'Découvrez cette boutique et ses produits sur MaketOu', url: window.location.href}).then(() => {
console.log('Partage réussi');
showNotification('Lien partagé avec succès !', 'success');
}).catch((error) => {
console.log('Erreur lors du partage:', error);
// Fallback vers la copie
copyToClipboard();
});
} else { // Sur desktop ou si Web Share n'est pas disponible, copier directement
copyToClipboard();
}
};
// Fonction pour copier le lien dans le presse-papiers
function copyToClipboard() {
const shopUrl = window.location.href;
const shopName = '{{ shop.name }}';
const shareText = `Découvrez la boutique "${shopName}" sur MaketOu : ${shopUrl}`;
// Utiliser directement le fallback pour éviter les conflits
fallbackCopyToClipboard(shareText);
}
// Fallback pour copier le texte
function fallbackCopyToClipboard(text) {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
showNotification('Lien copié dans le presse-papiers !', 'success');
} catch (err) {
console.error('Impossible de copier:', err);
showNotification('Impossible de copier le lien', 'error');
}
document.body.removeChild(textArea);
}
window.contactShop = function () { // Ouvrir un modal de signalement
openReportModal();
};
window.saveShop = function () { // Sauvegarder la boutique dans les favoris
showNotification('Boutique sauvegardée dans vos favoris', 'success');
};
// Fonction pour ouvrir le modal de signalement
window.openReportModal = function () {
const modal = new bootstrap.Modal(document.getElementById('reportModal'));
modal.show();
};
// Fonction pour soumettre le signalement
window.submitReport = function () {
const reason = document.getElementById('reportReason').value;
const description = document.getElementById('reportDescription').value;
const email = document.getElementById('reportEmail').value;
if (! reason || ! description) {
showNotification('Veuillez remplir tous les champs obligatoires', 'error');
return;
}
// Simuler l'envoi du signalement
const reportData = {
shopId: {{ shop.id }},
reason: reason,
description: description,
email: email,
reportedAt: new Date().toISOString()
};
console.log('Signalement envoyé:', reportData);
// Fermer le modal
const modal = bootstrap.Modal.getInstance(document.getElementById('reportModal'));
modal.hide();
// Réinitialiser le formulaire
document.getElementById('reportForm').reset();
// Afficher la confirmation
showNotification('Signalement envoyé avec succès. Nous examinerons votre demande.', 'success');
};
// Gestion du carrousel eBay-style
let currentSlide = 0;
let carouselInterval;
let isPaused = false;
let slides = [];
let indicators = [];
function initCarousel() {
// Réinitialiser les variables
currentSlide = 0;
isPaused = false;
// Récupérer les slides et indicateurs à nouveau
const carouselContainer = document.querySelector('.shop-carousel-ebay');
if (!carouselContainer) {
console.log('Carousel container not found');
return;
}
const allSlides = carouselContainer.querySelectorAll('.carousel-slide');
const allIndicators = carouselContainer.querySelectorAll('.carousel-indicator-ebay');
if (allSlides.length === 0) {
// Masquer les contrôles si aucune image
const controls = carouselContainer.querySelector('.carousel-controls-ebay');
const indicators = carouselContainer.querySelector('.carousel-indicators-ebay');
if (controls) controls.style.display = 'none';
if (indicators) indicators.style.display = 'none';
return;
}
// Si une seule image, masquer les contrôles
if (allSlides.length <= 1) {
const controls = carouselContainer.querySelector('.carousel-controls-ebay');
const indicators = carouselContainer.querySelector('.carousel-indicators-ebay');
if (controls) controls.style.display = 'none';
if (indicators) indicators.style.display = 'none';
// S'assurer que la slide unique est active
allSlides[0].classList.add('active');
return;
}
// Afficher les contrôles si plusieurs images
const controls = carouselContainer.querySelector('.carousel-controls-ebay');
const indicators = carouselContainer.querySelector('.carousel-indicators-ebay');
if (controls) controls.style.display = 'flex';
if (indicators) indicators.style.display = 'flex';
// Mettre à jour les références globales
slides = allSlides;
indicators = allIndicators;
// S'assurer que la première slide est active
updateCarousel();
// Démarrer le carrousel automatique
startCarousel();
// Gérer les événements de survol
carouselContainer.addEventListener('mouseenter', pauseCarousel);
carouselContainer.addEventListener('mouseleave', () => {
if (!isPaused) startCarousel();
});
}
function startCarousel() {
// Nettoyer l'intervalle existant
clearInterval(carouselInterval);
if (slides.length <= 1) return;
carouselInterval = setInterval(() => {
if (!isPaused && slides.length > 0) {
nextSlide();
}
}, 4000); // Change toutes les 4 secondes
}
function pauseCarousel() {
isPaused = true;
clearInterval(carouselInterval);
const pauseIcon = document.getElementById('pauseIcon');
if (pauseIcon) {
pauseIcon.className = 'lnr lnr-play';
}
}
function resumeCarousel() {
isPaused = false;
const pauseIcon = document.getElementById('pauseIcon');
if (pauseIcon) {
pauseIcon.className = 'lnr lnr-pause';
}
startCarousel();
}
function toggleCarousel() {
if (isPaused) {
resumeCarousel();
} else {
pauseCarousel();
}
}
function nextSlide() {
if (slides.length === 0) return;
currentSlide = (currentSlide + 1) % slides.length;
updateCarousel();
}
function previousSlide() {
if (slides.length === 0) return;
currentSlide = (currentSlide - 1 + slides.length) % slides.length;
updateCarousel();
}
function goToSlide(index) {
if (slides.length === 0) return;
if (index < 0 || index >= slides.length) return;
currentSlide = index;
updateCarousel();
}
function updateCarousel() {
if (slides.length === 0 || indicators.length === 0) return;
// Masquer toutes les slides
slides.forEach(slide => slide.classList.remove('active'));
indicators.forEach(indicator => indicator.classList.remove('active'));
// Afficher la slide active
if (slides[currentSlide]) {
slides[currentSlide].classList.add('active');
}
if (indicators[currentSlide]) {
indicators[currentSlide].classList.add('active');
}
}
// Fonctions globales pour les boutons
window.nextSlide = nextSlide;
window.previousSlide = previousSlide;
window.goToSlide = goToSlide;
window.toggleCarousel = toggleCarousel;
// Gestion du tri des produits via API Symfony
console.log('=== INITIALIZING PRODUCT SORTING ===');
console.log('Shop ID:', {{ shop.id }});
// Fonction de tri via AJAX - RENDUE GLOBALE
window.sortProducts = function (sortValue) {
console.log('=== SORT PRODUCTS CALLED ===');
console.log('Sort value:', sortValue);
const productsContainer = document.getElementById('products-container');
console.log('Products container:', productsContainer);
if (! productsContainer) {
console.error('Products container not found!');
return;
}
if (! sortValue) {
console.log('Resetting to original order');
// Recharger la page pour revenir à l'ordre original
window.location.reload();
return;
}
console.log('Showing loading spinner...');
// Afficher un indicateur de chargement
productsContainer.innerHTML = '<div class="col-12 text-center py-5"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Chargement...</span></div><p class="mt-3">Tri des produits en cours...</p></div>';
// Récupérer l'ID de la boutique
const shopId = {{ shop.id }};
console.log('Shop ID for request:', shopId);
const url = "{{ path('ui_api_shop_products_sort', {id: '__SHOP_ID__'}) }}".replace('__SHOP_ID__', shopId);
console.log('Request URL:', url);
const requestData = {
sortBy: sortValue
};
console.log('Request data:', requestData);
// Envoyer la requête AJAX
console.log('Sending AJAX request...');
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify(requestData)
}).then(response => {
console.log('Response received:', response);
console.log('Response status:', response.status);
return response.json();
}).then(data => {
console.log('Sort response data:', data);
if (data.success) {
console.log('Sort successful, updating content...');
// Mettre à jour le contenu avec le HTML retourné
productsContainer.innerHTML = data.html;
// Mettre à jour le compteur de produits
const productCount = document.querySelector('.product-count');
if (productCount) {
productCount.textContent = data.count;
}
console.log('Products sorted successfully!');
} else {
console.error('Sort failed:', data.message);
showNotification('Erreur lors du tri: ' + data.message, 'error');
// Recharger la page en cas d'erreur
window.location.reload();
}
}).catch(error => {
console.error('Sort request failed:', error);
showNotification('Erreur de connexion lors du tri', 'error');
// Recharger la page en cas d'erreur
window.location.reload();
});
};
// Attendre que le DOM soit chargé
console.log('Setting up event listeners...');
setTimeout(() => {
const sortSelect = document.getElementById('product-sort');
console.log('Sort select element:', sortSelect);
if (sortSelect) {
console.log('Adding change event listener...');
// Ecouter l'événement change avec jQuery (nécessaire à cause de nice-select)
if (typeof $ !== 'undefined') {
$('#product-sort').on('change', function() {
console.log('=== SELECT CHANGE EVENT TRIGGERED (jQuery) ===');
if(window.sortProducts) window.sortProducts(this.value);
});
}
sortSelect.addEventListener('change', function () {
console.log('=== SELECT CHANGE EVENT TRIGGERED ===');
console.log('Selected value:', this.value);
console.log('Calling sortProducts...');
window.sortProducts(this.value);
});
console.log('Event listener added successfully');
} else {
console.error('Sort select element not found!');
console.log('Available elements with ID containing "sort":', document.querySelectorAll('[id*="sort"]'));
console.log('Available elements with class containing "form-select":', document.querySelectorAll('.form-select'));
}
}, 100);
// Gestion du bouton "Suivre"
const followBtn = document.querySelector('.btn-shop');
if (followBtn) {
followBtn.addEventListener('click', function () {
if (this.innerHTML.includes('Suivre')) {
this.innerHTML = '<i class="lnr lnr-heart me-1"></i> Suivi';
this.classList.remove('btn-shop');
this.classList.add('btn-success');
} else {
this.innerHTML = '<i class="lnr lnr-heart me-1"></i> Suivre';
this.classList.remove('btn-success');
this.classList.add('btn-shop');
}
});
}
});
</script>
{% endblock %}