Checkout Steps Commande HTML CSS JS Pur

Extraits & Composants HTML 10/04/2026 22:00:00 angularforall.com
Html Css Javascript Checkout Stepper E Commerce Multi Etapes Template

Processus de commande multi-étapes en HTML CSS JS pur : stepper sans dépendance, transitions fluides, panier dynamique et confirmation animée.

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8" />
  <meta name="copyright" content="AngularForAll" />
  <meta name="author" content="AngularForAll" />
  <meta name="robots" content="noindex, nofollow" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="Cache-Control" content="public, max-age=604800" />
  <title>Snippets Checkout Step HTML CSS JS 2026 05020023 | AngularForAll</title>
<style>
    /* =============================================
       RESET & VARIABLES
       ============================================= */
    *, *::before, *::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    :root {
      --color-primary: #5b5fef;
      --color-primary-light: #eeefff;
      --color-primary-dark: #4845d2;
      --color-success: #2dd4a8;
      --color-success-light: #e6faf4;
      --color-warning: #f59e0b;
      --color-gray-50: #f9fafb;
      --color-gray-100: #f3f4f6;
      --color-gray-200: #e5e7eb;
      --color-gray-300: #d1d5db;
      --color-gray-400: #9ca3af;
      --color-gray-500: #6b7280;
      --color-gray-600: #4b5563;
      --color-gray-700: #374151;
      --color-gray-800: #1f2937;
      --color-white: #ffffff;
      --color-red-400: #f87171;
      --color-red-500: #ef4444;
      
      --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
      --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.06);
      --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.08), 0 4px 10px rgba(0, 0, 0, 0.05);
      --shadow-glow: 0 0 0 8px rgba(91, 95, 239, 0.12), 0 4px 16px rgba(91, 95, 239, 0.18);
      --shadow-success-glow: 0 0 0 8px rgba(45, 212, 168, 0.1), 0 4px 12px rgba(45, 212, 168, 0.15);
      
      --radius-sm: 8px;
      --radius-md: 12px;
      --radius-lg: 16px;
      --radius-xl: 20px;
      --radius-2xl: 24px;
      
      --transition-fast: 0.2s ease;
      --transition-smooth: 0.35s cubic-bezier(0.4, 0, 0.2, 1);
      --transition-bounce: 0.5s cubic-bezier(0.16, 1, 0.3, 1);
    }

    /* =============================================
       BASE
       ============================================= */
    body {
      font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
      background: linear-gradient(160deg, #f8f9fc 0%, #eef0f8 40%, #f5f3ff 100%);
      background-attachment: fixed;
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
      color: var(--color-gray-800);
      line-height: 1.5;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
    }

    /* Motif de fond subtil */
    body::before {
      content: '';
      position: fixed;
      inset: 0;
      background-image: 
        radial-gradient(circle at 15% 20%, rgba(91, 95, 239, 0.04) 0%, transparent 50%),
        radial-gradient(circle at 85% 75%, rgba(45, 212, 168, 0.04) 0%, transparent 50%),
        radial-gradient(circle at 50% 50%, rgba(245, 158, 11, 0.02) 0%, transparent 60%);
      pointer-events: none;
      z-index: 0;
    }

    /* =============================================
       CONTENEUR PRINCIPAL
       ============================================= */
    .checkout-wrapper {
      position: relative;
      z-index: 1;
      width: 100%;
      max-width: 660px;
    }

    .checkout-card {
      background: var(--color-white);
      border-radius: var(--radius-2xl);
      box-shadow: var(--shadow-lg);
      overflow: hidden;
      border: 1px solid rgba(0, 0, 0, 0.04);
    }

    /* =============================================
       EN-TÊTE
       ============================================= */
    .checkout-header {
      background: linear-gradient(135deg, #5b5fef 0%, #6c63ff 50%, #4845d2 100%);
      padding: 28px 32px;
      color: white;
      position: relative;
      overflow: hidden;
    }

    .checkout-header::before {
      content: '';
      position: absolute;
      top: -50%;
      right: -20%;
      width: 200px;
      height: 200px;
      background: radial-gradient(circle, rgba(255,255,255,0.08) 0%, transparent 70%);
      border-radius: 50%;
    }

    .checkout-header::after {
      content: '';
      position: absolute;
      bottom: -30%;
      left: 40%;
      width: 150px;
      height: 150px;
      background: radial-gradient(circle, rgba(255,255,255,0.05) 0%, transparent 70%);
      border-radius: 50%;
    }

    .header-content {
      position: relative;
      z-index: 1;
      display: flex;
      align-items: center;
      gap: 14px;
    }

    .header-icon {
      width: 44px;
      height: 44px;
      background: rgba(255, 255, 255, 0.18);
      backdrop-filter: blur(4px);
      border-radius: var(--radius-md);
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 20px;
      flex-shrink: 0;
    }

    .header-text h1 {
      font-size: 1.35rem;
      font-weight: 700;
      letter-spacing: -0.02em;
      margin-bottom: 2px;
    }

    .header-text p {
      font-size: 0.8rem;
      opacity: 0.7;
      letter-spacing: 0.01em;
    }

    /* =============================================
       CORPS
       ============================================= */
    .checkout-body {
      padding: 28px 32px 32px;
    }

    /* =============================================
       INDICATEUR D'ÉTAPES
       ============================================= */
    .steps-container {
      position: relative;
      display: flex;
      align-items: flex-start;
      justify-content: space-between;
      margin-bottom: 32px;
      padding: 0 8px;
    }

    /* Ligne de connexion */
    .steps-connector {
      position: absolute;
      top: 27px;
      left: 42px;
      right: 42px;
      height: 3px;
      background: var(--color-gray-200);
      border-radius: 3px;
      z-index: 0;
    }

    .steps-connector-fill {
      height: 100%;
      background: linear-gradient(90deg, var(--color-primary), var(--color-success));
      border-radius: 3px;
      transition: width var(--transition-smooth);
      width: 0%;
    }

    /* Étape individuelle */
    .step {
      display: flex;
      flex-direction: column;
      align-items: center;
      position: relative;
      z-index: 2;
      cursor: pointer;
      flex: 1;
      transition: transform var(--transition-fast);
    }

    .step:hover {
      transform: translateY(-2px);
    }

    .step-circle {
      width: 54px;
      height: 54px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 1.15rem;
      font-weight: 700;
      transition: all var(--transition-smooth);
      position: relative;
      background: var(--color-gray-200);
      color: var(--color-gray-500);
      border: 3px solid transparent;
      margin-bottom: 10px;
      flex-shrink: 0;
    }

    /* État actif */
    .step.active .step-circle {
      background: var(--color-white);
      color: var(--color-primary);
      border-color: var(--color-primary);
      box-shadow: var(--shadow-glow);
      transform: scale(1.06);
    }

    /* État complété */
    .step.completed .step-circle {
      background: var(--color-success);
      color: var(--color-white);
      border-color: var(--color-success);
      box-shadow: var(--shadow-success-glow);
    }

    .step-number {
      transition: opacity var(--transition-fast);
    }

    .step-check {
      display: none;
      font-size: 1.3rem;
    }

    .step.completed .step-number {
      display: none;
    }

    .step.completed .step-check {
      display: inline;
    }

    /* Labels */
    .step-label {
      font-size: 0.82rem;
      font-weight: 600;
      color: var(--color-gray-500);
      text-transform: uppercase;
      letter-spacing: 0.04em;
      transition: color var(--transition-smooth);
      text-align: center;
      display: flex;
      align-items: center;
      gap: 4px;
    }

    .step.active .step-label {
      color: var(--color-primary);
    }

    .step.completed .step-label {
      color: var(--color-success);
    }

    .step-sublabel {
      font-size: 0.68rem;
      color: var(--color-gray-400);
      margin-top: 2px;
      text-align: center;
      transition: color var(--transition-smooth);
    }

    .step.active .step-sublabel {
      color: var(--color-primary);
      opacity: 0.7;
    }

    .step.completed .step-sublabel {
      color: var(--color-success);
      opacity: 0.7;
    }

    /* =============================================
       CONTENU DES ÉTAPES
       ============================================= */
    .step-content {
      min-height: 260px;
      animation: fadeSlideIn 0.35s ease forwards;
      background: var(--color-gray-50);
      border-radius: var(--radius-xl);
      padding: 24px;
      border: 1px solid var(--color-gray-100);
    }

    @keyframes fadeSlideIn {
      from {
        opacity: 0;
        transform: translateY(8px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    .content-header {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-bottom: 20px;
    }

    .content-icon {
      width: 40px;
      height: 40px;
      background: var(--color-primary-light);
      border-radius: var(--radius-md);
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 18px;
      color: var(--color-primary);
      flex-shrink: 0;
    }

    .content-title h3 {
      font-size: 1.1rem;
      font-weight: 700;
      color: var(--color-gray-800);
      margin-bottom: 2px;
    }

    .content-title p {
      font-size: 0.8rem;
      color: var(--color-gray-400);
    }

    /* =============================================
       ÉLÉMENTS DU PANIER
       ============================================= */
    .cart-items {
      display: flex;
      flex-direction: column;
      gap: 10px;
      margin-bottom: 16px;
    }

    .cart-item {
      display: flex;
      align-items: center;
      gap: 14px;
      padding: 14px;
      background: var(--color-white);
      border-radius: var(--radius-lg);
      border: 1px solid var(--color-gray-100);
      transition: all var(--transition-fast);
    }

    .cart-item:hover {
      border-color: var(--color-gray-200);
      box-shadow: var(--shadow-sm);
    }

    .cart-item-image {
      width: 50px;
      height: 50px;
      background: var(--color-gray-100);
      border-radius: var(--radius-md);
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 22px;
      color: var(--color-gray-400);
      flex-shrink: 0;
    }

    .cart-item-info {
      flex: 1;
      min-width: 0;
    }

    .cart-item-name {
      font-weight: 600;
      font-size: 0.9rem;
      color: var(--color-gray-800);
      margin-bottom: 2px;
    }

    .cart-item-detail {
      font-size: 0.75rem;
      color: var(--color-gray-400);
    }

    .cart-item-price {
      font-weight: 700;
      font-size: 0.95rem;
      color: var(--color-gray-800);
      flex-shrink: 0;
    }

    .cart-item-remove {
      background: none;
      border: none;
      color: var(--color-gray-300);
      cursor: pointer;
      font-size: 16px;
      padding: 4px;
      transition: color var(--transition-fast);
      flex-shrink: 0;
    }

    .cart-item-remove:hover {
      color: var(--color-red-400);
    }

    .cart-total {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 16px;
      background: var(--color-primary-light);
      border-radius: var(--radius-lg);
    }

    .cart-total-label {
      font-size: 0.85rem;
      color: var(--color-gray-600);
    }

    .cart-total-price {
      font-weight: 700;
      font-size: 1.2rem;
      color: var(--color-primary);
    }

    /* =============================================
       FORMULAIRES
       ============================================= */
    .form-grid {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 12px;
      margin-bottom: 16px;
    }

    .form-group {
      display: flex;
      flex-direction: column;
      gap: 4px;
    }

    .form-group.full {
      grid-column: 1 / -1;
    }

    .form-label {
      font-size: 0.7rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.05em;
      color: var(--color-gray-500);
    }

    .form-input {
      padding: 10px 14px;
      border: 2px solid var(--color-gray-200);
      border-radius: var(--radius-md);
      font-size: 0.9rem;
      font-family: inherit;
      color: var(--color-gray-800);
      background: var(--color-white);
      transition: all var(--transition-fast);
      outline: none;
      width: 100%;
    }

    .form-input:focus {
      border-color: var(--color-primary);
      box-shadow: 0 0 0 3px rgba(91, 95, 239, 0.1);
    }

    /* Options de sélection */
    .options-list {
      display: flex;
      flex-direction: column;
      gap: 8px;
    }

    .option-card {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 14px 16px;
      border: 2px solid var(--color-gray-200);
      border-radius: var(--radius-lg);
      cursor: pointer;
      transition: all var(--transition-fast);
      background: var(--color-white);
    }

    .option-card:hover {
      border-color: var(--color-gray-300);
    }

    .option-card.selected {
      border-color: var(--color-primary);
      background: var(--color-primary-light);
    }

    .option-radio {
      width: 18px;
      height: 18px;
      accent-color: var(--color-primary);
      cursor: pointer;
    }

    .option-info {
      flex: 1;
    }

    .option-title {
      font-weight: 600;
      font-size: 0.9rem;
      color: var(--color-gray-800);
    }

    .option-subtitle {
      font-size: 0.75rem;
      color: var(--color-gray-400);
    }

    .option-badge {
      font-size: 0.75rem;
      font-weight: 600;
      padding: 4px 10px;
      border-radius: 20px;
      background: var(--color-success-light);
      color: var(--color-success);
    }

    /* =============================================
       RÉSUMÉ PAIEMENT
       ============================================= */
    .summary-card {
      background: var(--color-white);
      border-radius: var(--radius-lg);
      padding: 16px;
      border: 1px solid var(--color-gray-100);
    }

    .summary-row {
      display: flex;
      justify-content: space-between;
      padding: 8px 0;
      font-size: 0.88rem;
      color: var(--color-gray-600);
    }

    .summary-row:not(:last-child) {
      border-bottom: 1px solid var(--color-gray-100);
    }

    .summary-row.total {
      font-weight: 700;
      font-size: 1.05rem;
      color: var(--color-gray-800);
      border-bottom: none;
      padding-top: 12px;
    }

    .summary-row .highlight {
      color: var(--color-primary);
      font-weight: 700;
    }

    .text-green {
      color: var(--color-success);
      font-weight: 600;
    }

    /* =============================================
       BOUTONS
       ============================================= */
    .nav-buttons {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-top: 24px;
      padding-top: 20px;
      border-top: 1px solid var(--color-gray-100);
    }

    .btn {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 11px 22px;
      border-radius: var(--radius-md);
      font-size: 0.9rem;
      font-weight: 600;
      font-family: inherit;
      cursor: pointer;
      transition: all var(--transition-fast);
      border: 2px solid transparent;
      outline: none;
      white-space: nowrap;
    }

    .btn:active {
      transform: scale(0.96);
    }

    .btn-prev {
      background: var(--color-white);
      border-color: var(--color-gray-200);
      color: var(--color-gray-600);
    }

    .btn-prev:hover:not(:disabled) {
      background: var(--color-gray-50);
      border-color: var(--color-gray-300);
    }

    .btn-prev:disabled {
      opacity: 0.4;
      cursor: not-allowed;
      background: var(--color-gray-100);
      color: var(--color-gray-400);
    }

    .btn-next {
      background: var(--color-primary);
      color: white;
      border-color: var(--color-primary);
      box-shadow: 0 4px 14px rgba(91, 95, 239, 0.3);
    }

    .btn-next:hover {
      background: var(--color-primary-dark);
      border-color: var(--color-primary-dark);
      box-shadow: 0 6px 18px rgba(91, 95, 239, 0.35);
    }

    .btn-confirm {
      background: var(--color-success);
      color: white;
      border-color: var(--color-success);
      box-shadow: 0 4px 14px rgba(45, 212, 168, 0.3);
      font-size: 0.9rem;
    }

    .btn-confirm:hover {
      background: #25bf97;
      border-color: #25bf97;
      box-shadow: 0 6px 18px rgba(45, 212, 168, 0.35);
    }

    .step-counter {
      font-size: 0.8rem;
      color: var(--color-gray-400);
      font-weight: 500;
    }

    /* =============================================
       ÉTAT DE SUCCÈS
       ============================================= */
    .success-state {
      text-align: center;
      padding: 30px 20px;
    }

    .success-icon {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 72px;
      height: 72px;
      background: var(--color-success-light);
      border-radius: 50%;
      font-size: 36px;
      color: var(--color-success);
      margin-bottom: 20px;
      animation: bounceIn 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
    }

    @keyframes bounceIn {
      0% { opacity: 0; transform: scale(0.7); }
      50% { transform: scale(1.08); }
      100% { opacity: 1; transform: scale(1); }
    }

    .success-title {
      font-size: 1.25rem;
      font-weight: 700;
      color: var(--color-gray-800);
      margin-bottom: 8px;
    }

    .success-message {
      font-size: 0.9rem;
      color: var(--color-gray-500);
      margin-bottom: 6px;
    }

    .success-order-id {
      font-weight: 700;
      color: var(--color-gray-700);
    }

    .success-email {
      font-size: 0.8rem;
      color: var(--color-gray-400);
      margin-bottom: 20px;
    }

    .btn-restart {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 11px 22px;
      border-radius: var(--radius-md);
      font-size: 0.9rem;
      font-weight: 600;
      font-family: inherit;
      cursor: pointer;
      background: var(--color-primary);
      color: white;
      border: 2px solid var(--color-primary);
      box-shadow: 0 4px 14px rgba(91, 95, 239, 0.3);
      transition: all var(--transition-fast);
    }

    .btn-restart:hover {
      background: var(--color-primary-dark);
      box-shadow: 0 6px 18px rgba(91, 95, 239, 0.35);
    }

    /* =============================================
       RESPONSIVE
       ============================================= */
    @media (max-width: 600px) {
      .checkout-header {
        padding: 22px 20px;
      }

      .checkout-body {
        padding: 20px 16px 24px;
      }

      .step-circle {
        width: 42px;
        height: 42px;
        font-size: 0.95rem;
      }

      .steps-connector {
        top: 21px;
        left: 28px;
        right: 28px;
      }

      .step-label {
        font-size: 0.7rem;
      }

      .step-sublabel {
        font-size: 0.6rem;
      }

      .form-grid {
        grid-template-columns: 1fr;
      }

      .nav-buttons {
        flex-wrap: wrap;
        gap: 10px;
        justify-content: center;
      }

      .step-counter {
        order: 3;
        width: 100%;
        text-align: center;
      }

      .option-card {
        padding: 12px;
      }

      .cart-item {
        flex-wrap: wrap;
        gap: 8px;
      }
    }

    @media (max-width: 380px) {
      .steps-container {
        flex-direction: column;
        align-items: flex-start;
        gap: 20px;
        padding-left: 16px;
      }

      .step {
        flex-direction: row;
        gap: 14px;
        flex: none;
      }

      .step-circle {
        margin-bottom: 0;
      }

      .steps-connector {
        display: none;
      }

      /* Ligne verticale entre les étapes */
      .step:not(:last-child)::after {
        content: '';
        position: absolute;
        left: 21px;
        top: 44px;
        width: 3px;
        height: 24px;
        background: var(--color-gray-200);
        z-index: 0;
      }

      .step.completed:not(:last-child)::after {
        background: var(--color-success);
      }

      .step.active:not(:last-child)::after {
        background: linear-gradient(to bottom, var(--color-primary), var(--color-gray-200));
      }
    }
  </style>
</head>
<body>

  <div class="checkout-wrapper">
    <div class="checkout-card">
      
      <!-- ========== EN-TÊTE ========== -->
      <div class="checkout-header">
        <div class="header-content">
          <div class="header-icon">🛒</div>
          <div class="header-text">
            <h1>Finaliser la commande</h1>
            <p>Complétez les étapes ci-dessous</p>
          </div>
        </div>
      </div>

      <!-- ========== CORPS ========== -->
      <div class="checkout-body">
        
        <!-- ========== INDICATEUR D'ÉTAPES ========== -->
        <div class="steps-container" id="stepsContainer">
          <div class="steps-connector">
            <div class="steps-connector-fill" id="connectorFill"></div>
          </div>

          <!-- Étape 1 -->
          <div class="step active" data-step="1" onclick="goToStep(1)">
            <div class="step-circle">
              <span class="step-number">1</span>
              <span class="step-check">✓</span>
            </div>
            <div>
              <div class="step-label">🛍️ Panier</div>
              <div class="step-sublabel">Vérifier</div>
            </div>
          </div>

          <!-- Étape 2 -->
          <div class="step" data-step="2" onclick="goToStep(2)">
            <div class="step-circle">
              <span class="step-number">2</span>
              <span class="step-check">✓</span>
            </div>
            <div>
              <div class="step-label">🚚 Livraison</div>
              <div class="step-sublabel">Adresse</div>
            </div>
          </div>

          <!-- Étape 3 -->
          <div class="step" data-step="3" onclick="goToStep(3)">
            <div class="step-circle">
              <span class="step-number">3</span>
              <span class="step-check">✓</span>
            </div>
            <div>
              <div class="step-label">💳 Paiement</div>
              <div class="step-sublabel">Finaliser</div>
            </div>
          </div>
        </div>

        <!-- ========== CONTENU DYNAMIQUE ========== -->
        <div class="step-content" id="stepContent">
          <!-- Rempli par JavaScript -->
        </div>

        <!-- ========== BOUTONS DE NAVIGATION ========== -->
        <div class="nav-buttons" id="navButtons">
          <button class="btn btn-prev" id="btnPrev" onclick="previousStep()" disabled>
            ← Précédent
          </button>
          <span class="step-counter" id="stepCounter">Étape 1/3</span>
          <button class="btn btn-next" id="btnNext" onclick="nextStep()">
            Suivant →
          </button>
        </div>

      </div>
    </div>
  </div>

  <script>
    (function() {
      // ============ ÉTAT ============
      const TOTAL_STEPS = 3;
      let currentStep = 1;
      const completedSteps = new Set();

      // ============ ÉLÉMENTS DOM ============
      const stepElements = document.querySelectorAll('.step');
      const connectorFill = document.getElementById('connectorFill');
      const stepContent = document.getElementById('stepContent');
      const btnPrev = document.getElementById('btnPrev');
      const btnNext = document.getElementById('btnNext');
      const stepCounter = document.getElementById('stepCounter');
      const navButtons = document.getElementById('navButtons');

      // ============ CONTENUS DES ÉTAPES ============
      function getStepContent(step) {
        switch(step) {
          case 1:
            return `
              <div class="content-header">
                <div class="content-icon">🛍️</div>
                <div class="content-title">
                  <h3>Votre Panier</h3>
                  <p>Vérifiez vos articles avant de continuer</p>
                </div>
              </div>

              <div class="cart-items">
                <div class="cart-item">
                  <div class="cart-item-image">👟</div>
                  <div class="cart-item-info">
                    <div class="cart-item-name">Chaussures Air Max Neon</div>
                    <div class="cart-item-detail">Taille 42 • Noir/Blanc</div>
                  </div>
                  <div class="cart-item-price">129,99 €</div>
                  <button class="cart-item-remove" title="Supprimer">✕</button>
                </div>

                <div class="cart-item">
                  <div class="cart-item-image">⌚</div>
                  <div class="cart-item-info">
                    <div class="cart-item-name">Montre FitPro X200</div>
                    <div class="cart-item-detail">Bracelet silicone • Noir</div>
                  </div>
                  <div class="cart-item-price">249,99 €</div>
                  <button class="cart-item-remove" title="Supprimer">✕</button>
                </div>
              </div>

              <div class="cart-total">
                <span class="cart-total-label">Total (2 articles)</span>
                <span class="cart-total-price">379,98 €</span>
              </div>
            `;

          case 2:
            return `
              <div class="content-header">
                <div class="content-icon">🚚</div>
                <div class="content-title">
                  <h3>Adresse de livraison</h3>
                  <p>Où souhaitez-vous recevoir votre commande ?</p>
                </div>
              </div>

              <div class="form-grid">
                <div class="form-group">
                  <label class="form-label">Prénom</label>
                  <input type="text" class="form-input" value="Thomas" placeholder="Votre prénom">
                </div>
                <div class="form-group">
                  <label class="form-label">Nom</label>
                  <input type="text" class="form-input" value="Martin" placeholder="Votre nom">
                </div>
                <div class="form-group full">
                  <label class="form-label">Adresse</label>
                  <input type="text" class="form-input" value="15 Avenue des Champs-Élysées" placeholder="Numéro et rue">
                </div>
                <div class="form-group">
                  <label class="form-label">Code Postal</label>
                  <input type="text" class="form-input" value="75008" placeholder="75000">
                </div>
                <div class="form-group">
                  <label class="form-label">Ville</label>
                  <input type="text" class="form-input" value="Paris" placeholder="Ville">
                </div>
              </div>

              <div class="options-list">
                <label class="option-card selected">
                  <input type="radio" name="delivery" class="option-radio" checked>
                  <div class="option-info">
                    <div class="option-title">Standard</div>
                    <div class="option-subtitle">3-5 jours ouvrés</div>
                  </div>
                  <span class="option-badge">Gratuit</span>
                </label>
                <label class="option-card">
                  <input type="radio" name="delivery" class="option-radio">
                  <div class="option-info">
                    <div class="option-title">Express</div>
                    <div class="option-subtitle">1-2 jours ouvrés</div>
                  </div>
                  <span style="font-size:0.8rem;color:var(--color-gray-500);">+ 9,99 €</span>
                </label>
              </div>
            `;

          case 3:
            return `
              <div class="content-header">
                <div class="content-icon">💳</div>
                <div class="content-title">
                  <h3>Paiement sécurisé</h3>
                  <p>Choisissez votre méthode de paiement</p>
                </div>
              </div>

              <div class="options-list" style="margin-bottom:16px;">
                <label class="option-card selected">
                  <input type="radio" name="payment" class="option-radio" checked>
                  <div class="option-info">
                    <div class="option-title">💳 Carte Bancaire</div>
                    <div class="option-subtitle">Visa, Mastercard, CB</div>
                  </div>
                </label>
                <label class="option-card">
                  <input type="radio" name="payment" class="option-radio">
                  <div class="option-info">
                    <div class="option-title">🅿️ PayPal</div>
                    <div class="option-subtitle">Connexion sécurisée</div>
                  </div>
                </label>
                <label class="option-card">
                  <input type="radio" name="payment" class="option-radio">
                  <div class="option-info">
                    <div class="option-title">🍎 Apple Pay</div>
                    <div class="option-subtitle">Paiement express</div>
                  </div>
                </label>
              </div>

              <div class="summary-card">
                <div class="summary-row">
                  <span>Sous-total</span>
                  <span>379,98 €</span>
                </div>
                <div class="summary-row">
                  <span>Livraison</span>
                  <span class="text-green">Gratuite</span>
                </div>
                <div class="summary-row">
                  <span>TVA (20%)</span>
                  <span>63,33 €</span>
                </div>
                <div class="summary-row total">
                  <span>Total</span>
                  <span class="highlight">379,98 €</span>
                </div>
              </div>
            `;

          default:
            return '';
        }
      }

      // ============ MISE À JOUR DE L'INTERFACE ============
      function updateUI() {
        // Mise à jour des classes des étapes
        stepElements.forEach((stepEl, index) => {
          const stepNum = index + 1;
          stepEl.classList.remove('active', 'completed');

          if (completedSteps.has(stepNum)) {
            stepEl.classList.add('completed');
          } else if (stepNum === currentStep) {
            stepEl.classList.add('active');
          }
        });

        // Barre de progression
        const progressPercent = currentStep === 1 ? 0 : currentStep === 2 ? 50 : 100;
        connectorFill.style.width = progressPercent + '%';

        // Contenu
        stepContent.innerHTML = getStepContent(currentStep);

        // Réattacher les événements des options cards
        attachOptionCardEvents();

        // Bouton précédent
        if (currentStep === 1) {
          btnPrev.disabled = true;
        } else {
          btnPrev.disabled = false;
        }

        // Bouton suivant
        if (currentStep === TOTAL_STEPS) {
          btnNext.textContent = '✓ Confirmer';
          btnNext.className = 'btn btn-confirm';
          btnNext.onclick = confirmOrder;
        } else {
          btnNext.textContent = 'Suivant →';
          btnNext.className = 'btn btn-next';
          btnNext.onclick = nextStep;
        }

        // Compteur
        stepCounter.textContent = `Étape ${currentStep}/${TOTAL_STEPS}`;
      }

      // ============ ÉVÉNEMENTS DES OPTIONS ============
      function attachOptionCardEvents() {
        const optionCards = document.querySelectorAll('.option-card');
        optionCards.forEach(card => {
          card.addEventListener('click', function() {
            // Désélectionner toutes les cartes du même groupe
            const radio = this.querySelector('input[type="radio"]');
            if (!radio) return;
            
            const name = radio.name;
            const allCards = document.querySelectorAll(`input[name="${name}"]`);
            
            allCards.forEach(input => {
              input.closest('.option-card').classList.remove('selected');
            });
            
            // Sélectionner la carte cliquée
            this.classList.add('selected');
            radio.checked = true;
          });
        });
      }

      // ============ NAVIGATION ============
      function goToStep(step) {
        if (step < currentStep || completedSteps.has(step - 1)) {
          currentStep = step;
          updateUI();
          // Animation de feedback
          pulseCurrentStep();
        }
      }

      function nextStep() {
        if (currentStep < TOTAL_STEPS) {
          completedSteps.add(currentStep);
          currentStep++;
          updateUI();
          pulseCurrentStep();
        }
      }

      function previousStep() {
        if (currentStep > 1) {
          currentStep--;
          updateUI();
        }
      }

      function pulseCurrentStep() {
        const activeStep = document.querySelector('.step.active .step-circle');
        if (activeStep) {
          activeStep.style.transform = 'scale(1.12)';
          setTimeout(() => {
            activeStep.style.transform = 'scale(1.06)';
          }, 200);
        }
      }

      function confirmOrder() {
        // Marquer l'étape 3 comme complétée
        completedSteps.add(3);
        updateUI();

        // Animation de chargement
        btnNext.textContent = '⏳ Traitement...';
        btnNext.disabled = true;
        btnNext.style.opacity = '0.75';
        btnNext.style.cursor = 'wait';

        setTimeout(() => {
          // Afficher l'état de succès
          stepContent.innerHTML = `
            <div class="success-state">
              <div class="success-icon">✓</div>
              <div class="success-title">Commande confirmée !</div>
              <div class="success-message">
                Votre commande <span class="success-order-id">#CMD-2026-0421</span> a bien été enregistrée.
              </div>
              <div class="success-email">Un email a été envoyé à thomas.martin@email.fr</div>
              <button class="btn-restart" onclick="location.reload()">
                ↻ Nouvelle commande
              </button>
            </div>
          `;

          // Mettre à jour la barre de progression
          connectorFill.style.width = '100%';

          // Mettre toutes les étapes en complétées
          stepElements.forEach(el => {
            el.classList.remove('active');
            el.classList.add('completed');
          });

          // Cacher les boutons de navigation
          navButtons.style.display = 'none';
        }, 1500);
      }

      // ============ FONCTIONS GLOBALES ============
      window.goToStep = goToStep;
      window.nextStep = nextStep;
      window.previousStep = previousStep;
      window.confirmOrder = confirmOrder;

      // ============ INITIALISATION ============
      updateUI();
      attachOptionCardEvents();

      console.log('✅ CheckoutSteps • Vanilla JS • Prêt à l\'emploi');
    })();
  </script>

</body>
</html>

Télécharger le fichier source

Partager