贈品活動支援 X 件中選擇 Y 件贈送

贈品活動(滿額滿件 / 任選優惠 / A+B 組合)支援多選贈品,優惠頁面支援新版 UI。

  1. 新增以下樣式
    .PromotionInfo-summary-view-gifts {
      font-weight: 700;
      letter-spacing: 0;
      text-decoration: underline;
      color: var(--primary-color, $color-primary);
      cursor: pointer;
    
      &.is-inline {
        margin-left: 4px;
      }
    }
    
    .promotion-gift-info-modal {
      promotion-gift-info {
        .promotion-gift-info__title,
        .promotion-gift-info__tier-title {
          color: var(--text-color, #333);
        }
    
        .promotion-gift-info__spinner {
          border-top-color: var(--primary-color, #c74060);
        }
    
        .promotion-gift-info__close:focus-visible {
          outline-color: var(--primary-color, #c74060);
        }
      }
    }
  1. 更新 promotion_page.liquid
    {{ 'page-promotions.css' | asset_source_tag: render_to_top: true }}
    {{ 'page-categories.css' | asset_source_tag: render_to_top: true }}
    
    <div class="ProductList-breadcrumb nav-bg-color hidden-xs">
      <div class="block-inner">
        <a class="Label" href="/products">{{ 'shopline_translations.themes.products.view_all' | translate }}</a>
        <span class="promotion-title dark-primary" ng-non-bindable>{{ promotion.title }}</span>
      </div>
    </div>
    
    {% if promotion.banner_media_url %}
      <div class="PromotionPage-banner">
        <img class="sl-lazy-image" alt="{{ promotion.banner_media_alt }}" src="{{ promotion.banner_media_url }}" />
      </div>
    {% endif %}
    
    <div class="PromotionInfo">
      <div class="PromotionInfo-icon">
        <img src="https://s3-ap-southeast-1.amazonaws.com/static.shoplineapp.com/web/assets/icon_promotion.svg" width="158" height="150" alt="promotion hint">
      </div>
      <div class="PromotionInfo-qualifications">
        <div ng-bind-html="::getFormattedDateString('promotions.page.end_at', '{{ end_date }}')"></div>
        <div ng-if="promotion.first_purchase_only" ng-bind-html="getFirstPurchaseOnlyText()"></div>
        <div>
          {% if promotion.requires_membership == true %}
            {% if promotion.membership_tiers.size >= 1 %}
              {% if shop.current_locale.code contains 'zh' %}
                <b>{{ promotion.membership_tiers | map: 'name' | join: ',' }}</b>
              {% else %}
                <b>{{ promotion.membership_tiers | map: 'name' | join: ', ' }}</b>
              {% endif %}
              {{ 'shopline_translations.themes.promotions.membership.only' | translate }}
            {% elsif is_specific_member %}
              {{ 'shopline_translations.themes.promotions.membership.specific_member_only' | translate }}
            {% else %}
              {{ 'shopline_translations.themes.promotions.membership.member_only' | translate }}
            {% endif %}
          {% else %}
            {{ 'shopline_translations.themes.promotions.membership.all' | translate }}
          {% endif %}
        </div>
      </div>
      <div class="PromotionInfo-summary">
        {% if shop.features contains 'promotion_gift_multi_numbers' %}
          <div ng-if="isGiftPromotion && hasMultiTier()">
            <div ng-bind-html="getPromotionSummary()"></div>
            <div class="PromotionInfo-summary-view-gifts" ng-click="openGiftInfoModal()">{% raw %}{{ 'promotions.page.view_gifts' | translate }}{% endraw %}</div>
          </div>
          <div ng-if="isGiftPromotion && !hasMultiTier()">
            <span ng-bind-html="getPromotionSummary()"></span>
            <span class="PromotionInfo-summary-view-gifts is-inline" ng-click="openGiftInfoModal()">{% raw %}{{ 'promotions.page.view_gifts' | translate }}{% endraw %}</span>
          </div>
        {% endif %}
        <div {% if shop.features contains 'promotion_gift_multi_numbers' %}ng-if="!isGiftPromotion" {% endif %}ng-bind-html="getPromotionSummary()"></div>
        <div class="available-platforms">{% raw %}{{'promotions.page.available_platform' | translate}}{% endraw %}
          <b>
            <ng-container ng-repeat="platform in availablePlatform">
              <span ng-if="$index > 0">/</span>
              <span ng-if="platform === 'selected_retail'"
                ng-click="showSelectedRetail()"
                class="show-selected-retail-button"
                ng-bind-html="'promotions.available_platform.' + platform | translate">
              </span>
              <span ng-if="platform !== 'selected_retail'"
                ng-bind-html="'promotions.available_platform.' + platform | translate">
              </span>
            </ng-container>
          </b>
        </div>
        {% if promotion.term != '' %}
          {% javascript_cloak %}
          {% show_on_ready %}
            <div class="show-term-button" ng-click="showTermModal('{{ promotion.term | escape }}')">
              {% raw %}{{ 'promotions.page.term.title' | translate }}{% endraw %}
            </div>
          {% end_javascript_cloak %}
        {% endif %}
      </div>
    </div>
    
    <div class="PromotionPage-icon-container fixed-height">
      <div class="container with-border">
        {% if use_revamped_theme_settings %}
          <svg><use xlink:href="#icon-expired"></use></svg>
        {% else %}
        <svg viewBox="0 0 146 140">
          <g id="icon_expired" stroke="none" stroke-width="1" fill-rule="evenodd">
            <g id="Group-24-Copy">
                <path d="M100,59.000133 C100,61.2092768 101.790723,63 104.000133,63 C106.209277,63 108,61.2092768 108,59.000133 C108,56.7909892 106.209277,55 104.000133,55 C101.790723,55 100,56.7909892 100,59.000133" id="Fill-1" />
                <path d="M84,59.000133 C84,56.7909892 82.2092768,55 79.999867,55 C77.7907232,55 76,56.7909892 76,59.000133 C76,61.2092768 77.7907232,63 79.999867,63 C82.2092768,63 84,61.2092768 84,59.000133" id="Fill-3" />
                <path d="M31.999867,55 C29.7907232,55 28,56.7909892 28,59.000133 C28,61.2092768 29.7907232,63 31.999867,63 C34.2092768,63 36,61.2092768 36,59.000133 C36,56.7909892 34.2092768,55 31.999867,55" id="Fill-5" />
                <path d="M56.999867,55 C54.7907232,55 53,56.7909892 53,59.000133 C53,61.2092768 54.7907232,63 56.999867,63 C59.2092768,63 61,61.2092768 61,59.000133 C61,56.7909892 59.2092768,55 56.999867,55" id="Fill-7" />
                <path d="M31.999867,79 C29.7907232,79 28,80.7907232 28,83.000133 C28,85.2092768 29.7907232,87 31.999867,87 C34.2092768,87 36,85.2092768 36,83.000133 C36,80.7907232 34.2092768,79 31.999867,79" id="Fill-9" />
                <path d="M56.999867,79 C54.7907232,79 53,80.7907232 53,83.000133 C53,85.2092768 54.7907232,87 56.999867,87 C59.2092768,87 61,85.2092768 61,83.000133 C61,80.7907232 59.2092768,79 56.999867,79" id="Fill-11" />
                <path d="M31.999867,100 C29.7907232,100 28,101.790783 28,104 C28,106.209217 29.7907232,108 31.999867,108 C34.2092768,108 36,106.209217 36,104 C36,101.790783 34.2092768,100 31.999867,100" id="Fill-13" />
                <path d="M56.999867,100 C54.7907232,100 53,101.790783 53,104 C53,106.209217 54.7907232,108 56.999867,108 C59.2092768,108 61,106.209217 61,104 C61,101.790783 59.2092768,100 56.999867,100" id="Fill-15" />
                <g id="Group-19">
                    <mask id="mask-2" fill="white">
                        <use xlink:href="#path-1"/>
                    </mask>
                    <g id="Clip-18"/>
                    <path d="M12.9234875,17.414965 L29.5068562,17.414965 L29.5068562,21.8729292 C29.5068562,26.3375535 33.0601187,29.9696728 37.4275512,29.9696728 C41.7952442,29.9696728 45.3487674,26.3375535 45.3487674,21.8729292 L45.3487674,17.414965 L90.7270106,17.414965 L90.7270106,21.8729292 C90.7270106,26.3375535 94.2802732,29.9696728 98.6479662,29.9696728 C103.015659,29.9696728 106.568922,26.3375535 106.568922,21.8729292 L106.568922,17.414965 L121.922696,17.414965 C126.174675,17.414965 129.633854,20.9509133 129.633854,25.2972553 L129.633854,35.7724322 L5.21232915,35.7724322 L5.21232915,25.2972553 C5.21232915,20.9509133 8.67176931,17.414965 12.9234875,17.414965 Z M34.7192114,8.19160915 C34.7192114,6.66459523 35.9342114,5.42263101 37.4275512,5.42263101 C38.9214122,5.42263101 40.1364122,6.66459523 40.1364122,8.19160915 L40.1364122,21.8729292 C40.1364122,23.3996767 38.9214122,24.641641 37.4275512,24.641641 C35.9342114,24.641641 34.7192114,23.3996767 34.7192114,21.8729292 L34.7192114,8.19160915 Z M95.9393658,8.19160915 C95.9393658,6.66459523 97.1543658,5.42263101 98.6479662,5.42263101 C100.141567,5.42263101 101.356567,6.66459523 101.356567,8.19160915 L101.356567,21.8729292 C101.356567,23.3996767 100.141567,24.641641 98.6479662,24.641641 C97.1543658,24.641641 95.9393658,23.3996767 95.9393658,21.8729292 L95.9393658,8.19160915 Z M76.5392403,128.438893 L12.9234875,128.438893 C8.67176931,128.438893 5.21232915,124.902679 5.21232915,120.556603 L5.21232915,41.100464 L129.633854,41.100464 L129.633854,67.9380266 C129.633854,69.4093626 130.800901,70.6020425 132.240032,70.6020425 C133.679424,70.6020425 134.846209,69.4093626 134.846209,67.9380266 L134.846209,25.2972553 C134.846209,18.0130366 129.048767,12.0869332 121.922696,12.0869332 L106.568922,12.0869332 L106.568922,8.19160915 C106.568922,3.72698489 103.015659,0.0945992048 98.6479662,0.0945992048 C94.2802732,0.0945992048 90.7270106,3.72698489 90.7270106,8.19160915 L90.7270106,12.0869332 L45.3487674,12.0869332 L45.3487674,8.19160915 C45.3487674,3.72698489 41.7952442,0.0945992048 37.4275512,0.0945992048 C33.0601187,0.0945992048 29.5068562,3.72698489 29.5068562,8.19160915 L29.5068562,12.0869332 L12.9234875,12.0869332 C5.79741602,12.0869332 -2.60617761e-05,18.0130366 -2.60617761e-05,25.2972553 L-2.60617761e-05,120.556603 C-2.60617761e-05,127.840822 5.79741602,133.766925 12.9234875,133.766925 L76.5392403,133.766925 C77.9783716,133.766925 79.145418,132.573979 79.145418,131.102909 C79.145418,129.631573 77.9783716,128.438893 76.5392403,128.438893 Z" id="Fill-17" mask="url(#mask-2)"/>
                </g>
                <path d="M114.5,134.637046 C99.9535249,134.637046 88.1192043,122.239237 88.1192043,107.000134 C88.1192043,91.7610316 99.9535249,79.3629542 114.5,79.3629542 C129.046475,79.3629542 140.880796,91.7610316 140.880796,107.000134 C140.880796,122.239237 129.046475,134.637046 114.5,134.637046 M114.5,74 C97.1307957,74 83,88.8036306 83,107.000134 C83,125.196369 97.1307957,140 114.5,140 C131.869204,140 146,125.196369 146,107.000134 C146,88.8036306 131.869204,74 114.5,74" id="Fill-20" />
                <path d="M128.282152,106.984552 L115.435697,106.984552 L115.435697,89.5077238 C115.435697,88.1227079 114.218916,87 112.717848,87 C111.217053,87 110,88.1227079 110,89.5077238 L110,109.492276 C110,110.877041 111.217053,112 112.717848,112 L128.282152,112 C129.782947,112 131,110.877041 131,109.492276 C131,108.107511 129.782947,106.984552 128.282152,106.984552" id="Fill-22" />
            </g>
          </g>
        </svg>
        {% endif %}
        <div class="PromotionPage-icon-text">
          {{ 'shopline_translations.themes.promotions.coming_soon' | translate }}
        </div>
        <div class="PromotionPage-icon-description" ng-bind-html="::getFormattedDateString('promotions.page.start_at', '{{ start_date }}')"></div>
      </div>
    </div>
    
    <div class="PromotionPage-nav-container">
      <div class="ProductList-info sl-products-list-settings">
        <div class="breadcrumb PromotionPage-breadcrumb text-primary-color">
          <h1 class="Label" ng-non-bindable>
            {{ promotion.title }}
            {% if theme.settings.show_products_total %}
              {% assign products_total = paginate.total | default: 0 %}
              {% if shop.sku_expand_enabled %}
                {% assign products_total = paginate.spu_total | default: 0 %}
              {% endif %}
              <span class="ProductList-total">{{ 'shopline_translations.themes.products.total' | translate: total: products_total }}</span>
            {% endif %}
          </h1>
        </div>
    
        <div class="ProductList-select js-productlist-select clearfix">
          {% if discount_type == 'bundle_group' or discount_type == 'bundle_group_percentage' or discount_type == 'bundle_group_amount' or discount_type == 'bundle_group_gift' %}
            <div class="select-filter js-select-filter">
              <span></span>
              <ul></ul>
            </div>
          {% endif %}
          <div class="select-limit js-select-limit">
            <span></span>
            <ul></ul>
          </div>
        </div>
        <div class="ProductList-settings form">
          <span><select class="ProductList-settings-limit js-productlist-settings-limit form-control sl-products-limit" disabled>
            {% for option in paginate.limit_options %}
              <option value="{{ option.value }}" {% if option.value == paginate.page_size %}selected{% endif %}>{{ option.title }}</option>
            {% endfor %}
          </select></span>
          {% if discount_type == 'bundle_group' or discount_type == 'bundle_group_percentage' or discount_type == 'bundle_group_amount' or discount_type == 'bundle_group_gift' %}
            <span>
              <select class="ProductList-settings-filter js-productlist-settings-filter form-control sl-products-filter" disabled>
                <option value="all" {% if filter == 'all' %}selected{% endif %}>
                  {{ 'shopline_translations.themes.products.bundle_group_options.all' | translate }}
                </option>
                <option value="red" {% if filter == 'red' %}selected{% endif %}>
                  {{ 'shopline_translations.themes.products.bundle_group_options.red' | translate }}
                </option>
                <option value="green" {% if filter == 'green' %}selected{% endif %}>
                  {{ 'shopline_translations.themes.products.bundle_group_options.green' | translate }}
                </option>
              </select>
            </span>
          {% endif %}
        </div>
      </div>
    </div>
    
    <div class="row">
      <div class="col-xs-12 ProductList-list">
        {% for product in products %}
          {% promotion_product_thumb %} {% end_promotion_product_thumb %}
        {% endfor %}
      </div>
    
      {% if paginate.pages > 1 %}
        <div class="col-xs-12 text-center">
          <ul class="ProductList-paginator pagination">
            {% if paginate.previous.is_link %}
              <li class="ProductList-paginator-button">
                <a class="Label" href="{{ paginate.previous.url }}"><i class="fa fa-angle-left" aria-hidden="true"></i></a>
              </li>
            {% endif %}
            {% for part in paginate.parts %}
              <li class="ProductList-paginator-button {% if part.page == paginate.current_page %}active{% endif %}"><a class="Label" href="{{ part.handle }}">{{ part.title }}</a></li>
            {% endfor %}
            {% if paginate.next.is_link %}
              <li class="ProductList-paginator-button">
                <a class="Label" href="{{ paginate.next.url }}"><i class="fa fa-angle-right" aria-hidden="true"></i></a>
              </li>
            {% endif %}
          </ul>
        </div>
      {% endif %}
    </div>
    
    {% if shop.features contains 'promotion_gift_multi_numbers' %}
    <sl-modal sl-modal-id="promotion-gift-info" class="promotion-gift-info-modal">
      <sl-modal-mask></sl-modal-mask>
      <sl-modal-container>
        <promotion-gift-info></promotion-gift-info>
      </sl-modal-container>
    </sl-modal>
    {% endif %}