|
| 1 | +<div class="cart-page"> |
| 2 | + |
| 3 | + @if (step() === 'cart') { |
| 4 | + <div class="cart-view"> |
| 5 | + <h2 class="cart-title"> |
| 6 | + Mon panier |
| 7 | + @if (itemCount() > 0) { |
| 8 | + <span class="cart-badge">{{ itemCount() }}</span> |
| 9 | + } |
| 10 | + </h2> |
| 11 | + |
| 12 | + @if (items().length === 0) { |
| 13 | + <div class="cart-empty"> |
| 14 | + <p>Votre panier est vide.</p> |
| 15 | + </div> |
| 16 | + } |
| 17 | + |
| 18 | + @if (items().length > 0) { |
| 19 | + <ul class="cart-list"> |
| 20 | + @for (item of items(); track item.cartItemId) { |
| 21 | + <li class="cart-item"> |
| 22 | + |
| 23 | + <div class="item-header"> |
| 24 | + <div class="item-meta"> |
| 25 | + <span class="item-badge" [class.badge-menu]="item.type === 'menu'"> |
| 26 | + {{ item.type === 'menu' ? 'Menu' : 'Produit' }} |
| 27 | + </span> |
| 28 | + <strong class="item-name"> |
| 29 | + {{ item.type === 'product' ? item.product!.name : item.menu!.name }} |
| 30 | + </strong> |
| 31 | + </div> |
| 32 | + <div class="item-right"> |
| 33 | + <div class="qty-control"> |
| 34 | + <button class="qty-btn" (click)="cartService.decrementItem(item.cartItemId)">−</button> |
| 35 | + <span class="qty-val">{{ item.quantity }}</span> |
| 36 | + <button class="qty-btn" (click)="cartService.incrementItem(item.cartItemId)">+</button> |
| 37 | + </div> |
| 38 | + <span class="item-price"> |
| 39 | + {{ ((item.type === 'product' ? item.product!.price : item.menu!.price) * item.quantity).toFixed(2) }}€ |
| 40 | + </span> |
| 41 | + <button class="remove-btn" (click)="cartService.removeItem(item.cartItemId)">✕</button> |
| 42 | + </div> |
| 43 | + </div> |
| 44 | + |
| 45 | + @if (item.type === 'product') { |
| 46 | + <div class="item-summary"> |
| 47 | + @if (summaryIngredients(item.product!.customization.ingredients)) { |
| 48 | + <span class="summary-tag removed">{{ summaryIngredients(item.product!.customization.ingredients) }}</span> |
| 49 | + } |
| 50 | + @if (summaryExtras(item.product!.customization.extras)) { |
| 51 | + <span class="summary-tag">{{ summaryExtras(item.product!.customization.extras) }}</span> |
| 52 | + } |
| 53 | + </div> |
| 54 | + } |
| 55 | + |
| 56 | + @if (item.type === 'menu') { |
| 57 | + <div class="item-summary"> |
| 58 | + @for (cust of item.menu!.customizations; track cust.productId) { |
| 59 | + <div class="menu-product-summary"> |
| 60 | + <span class="menu-product-label">{{ cust.productName }}</span> |
| 61 | + @if (summaryIngredients(cust.ingredients)) { |
| 62 | + <span class="summary-tag removed">{{ summaryIngredients(cust.ingredients) }}</span> |
| 63 | + } |
| 64 | + @if (summaryExtras(cust.extras)) { |
| 65 | + <span class="summary-tag">{{ summaryExtras(cust.extras) }}</span> |
| 66 | + } |
| 67 | + </div> |
| 68 | + } |
| 69 | + </div> |
| 70 | + } |
| 71 | + |
| 72 | + </li> |
| 73 | + } |
| 74 | + </ul> |
| 75 | + |
| 76 | + <div class="cart-footer"> |
| 77 | + <div class="cart-total"> |
| 78 | + <span>Total</span> |
| 79 | + <strong>{{ total().toFixed(2) }}€</strong> |
| 80 | + </div> |
| 81 | + <button class="btn-fire" (click)="goToCheckout()"> |
| 82 | + Commander — {{ total().toFixed(2) }}€ |
| 83 | + </button> |
| 84 | + <button class="btn-ghost" (click)="cartService.clearCart()">Vider le panier</button> |
| 85 | + </div> |
| 86 | + } |
| 87 | + </div> |
| 88 | + } |
| 89 | + |
| 90 | + @if (step() === 'checkout') { |
| 91 | + <div class="checkout-view"> |
| 92 | + <button class="back-btn" (click)="backToCart()">← Retour au panier</button> |
| 93 | + <h2 class="cart-title">Finaliser la commande</h2> |
| 94 | + |
| 95 | + <form class="checkout-form" [formGroup]="checkoutForm" (ngSubmit)="submitOrder()"> |
| 96 | + |
| 97 | + <fieldset class="form-section"> |
| 98 | + <legend class="section-legend">Coordonnées</legend> |
| 99 | + |
| 100 | + <div class="form-row"> |
| 101 | + <div class="form-field" [class.error]="fieldInvalid('firstName')"> |
| 102 | + <label>Prénom</label> |
| 103 | + <input type="text" formControlName="firstName" placeholder="Jean" /> |
| 104 | + @if (fieldInvalid('firstName')) { <span class="error-msg">Requis</span> } |
| 105 | + </div> |
| 106 | + <div class="form-field" [class.error]="fieldInvalid('lastName')"> |
| 107 | + <label>Nom</label> |
| 108 | + <input type="text" formControlName="lastName" placeholder="Dupont" /> |
| 109 | + @if (fieldInvalid('lastName')) { <span class="error-msg">Requis</span> } |
| 110 | + </div> |
| 111 | + </div> |
| 112 | + |
| 113 | + <div class="form-field" [class.error]="fieldInvalid('email')"> |
| 114 | + <label>Email</label> |
| 115 | + <input type="email" formControlName="email" placeholder="jean@example.com" /> |
| 116 | + @if (fieldInvalid('email')) { <span class="error-msg">Email invalide</span> } |
| 117 | + </div> |
| 118 | + |
| 119 | + <div class="form-field" [class.error]="fieldInvalid('address')"> |
| 120 | + <label>Adresse</label> |
| 121 | + <input type="text" formControlName="address" placeholder="12 rue de la Paix" /> |
| 122 | + @if (fieldInvalid('address')) { <span class="error-msg">Requis</span> } |
| 123 | + </div> |
| 124 | + |
| 125 | + <div class="form-row"> |
| 126 | + <div class="form-field" [class.error]="fieldInvalid('city')"> |
| 127 | + <label>Ville</label> |
| 128 | + <input type="text" formControlName="city" placeholder="Belfort" /> |
| 129 | + @if (fieldInvalid('city')) { <span class="error-msg">Requis</span> } |
| 130 | + </div> |
| 131 | + <div class="form-field" [class.error]="fieldInvalid('zip')"> |
| 132 | + <label>Code postal</label> |
| 133 | + <input type="text" formControlName="zip" placeholder="90000" /> |
| 134 | + @if (fieldInvalid('zip')) { <span class="error-msg">Requis</span> } |
| 135 | + </div> |
| 136 | + </div> |
| 137 | + </fieldset> |
| 138 | + |
| 139 | + <fieldset class="form-section"> |
| 140 | + <legend class="section-legend">Paiement</legend> |
| 141 | + |
| 142 | + <div class="form-field" [class.error]="fieldInvalid('cardNumber')"> |
| 143 | + <label>Numéro de carte</label> |
| 144 | + <input |
| 145 | + type="text" |
| 146 | + formControlName="cardNumber" |
| 147 | + placeholder="1234567812345678" |
| 148 | + maxlength="16" |
| 149 | + (input)="formatCardNumber($event)" |
| 150 | + /> |
| 151 | + @if (fieldInvalid('cardNumber')) { <span class="error-msg">16 chiffres requis</span> } |
| 152 | + </div> |
| 153 | + |
| 154 | + <div class="form-row"> |
| 155 | + <div class="form-field" [class.error]="fieldInvalid('cardExpiry')"> |
| 156 | + <label>Expiration</label> |
| 157 | + <input |
| 158 | + type="text" |
| 159 | + formControlName="cardExpiry" |
| 160 | + placeholder="MM/AA" |
| 161 | + maxlength="5" |
| 162 | + (input)="formatExpiry($event)" |
| 163 | + /> |
| 164 | + @if (fieldInvalid('cardExpiry')) { <span class="error-msg">Format MM/AA</span> } |
| 165 | + </div> |
| 166 | + <div class="form-field" [class.error]="fieldInvalid('cardCvc')"> |
| 167 | + <label>CVC</label> |
| 168 | + <input type="text" formControlName="cardCvc" placeholder="123" maxlength="4" /> |
| 169 | + @if (fieldInvalid('cardCvc')) { <span class="error-msg">3-4 chiffres</span> } |
| 170 | + </div> |
| 171 | + </div> |
| 172 | + </fieldset> |
| 173 | + |
| 174 | + <div class="order-summary"> |
| 175 | + <span>Total à payer</span> |
| 176 | + <strong>{{ total().toFixed(2) }}€</strong> |
| 177 | + </div> |
| 178 | + |
| 179 | + <button type="submit" class="btn-fire"> |
| 180 | + Confirmer et payer — {{ total().toFixed(2) }}€ |
| 181 | + </button> |
| 182 | + |
| 183 | + </form> |
| 184 | + </div> |
| 185 | + } |
| 186 | + |
| 187 | + @if (step() === 'confirm') { |
| 188 | + <div class="confirm-view"> |
| 189 | + <div class="confirm-icon">✓</div> |
| 190 | + <h2 class="confirm-title">Commande confirmée !</h2> |
| 191 | + <p class="confirm-sub">Votre commande a été enregistrée. Merci !</p> |
| 192 | + <button class="btn-fire" (click)="restartShopping()">Retour à la carte</button> |
| 193 | + </div> |
| 194 | + } |
| 195 | + |
| 196 | +</div> |
0 commit comments