diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2024-10-24 11:01:08 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2024-10-24 11:01:08 +0700 |
| commit | 9abd621285d739a9c502d661013db5ce96edec33 (patch) | |
| tree | 98ff4ae0bf8adcced77699de33aebe50616233dc | |
| parent | ca30c28dd0b19977eb771fc32ff5e520cdef1068 (diff) | |
| parent | e0aa9e04a473a4f7a21b389b42314d3fed06b43e (diff) | |
Merge branch 'new-release' into CR/new_product_detail
29 files changed, 2035 insertions, 514 deletions
diff --git a/public/images/CHECKOUT-PESANAN.svg b/public/images/CHECKOUT-PESANAN.svg new file mode 100644 index 00000000..6291b4cd --- /dev/null +++ b/public/images/CHECKOUT-PESANAN.svg @@ -0,0 +1,958 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#EBEBEB;} + .st1{fill:#FAFAFA;} + .st2{fill:#E0E0E0;} + .st3{fill:#F5F5F5;} + .st4{fill:#FFFFFF;} + .st5{display:none;} + .st6{display:inline;} + .st7{display:inline;fill:#EBEBEB;} + .st8{fill:#263238;} + .st9{fill:#EA0000;} + .st10{font-family:'Gilroy-Bold';} + .st11{font-size:12.4079px;} + .st12{font-family:'Gilroy-Regular';} + .st13{font-size:9.0789px;} + .st14{fill:#FFBE9D;} + .st15{fill:#EB996E;} + .st16{fill:#455A64;} + .st17{fill:none;stroke:#FFFFFF;stroke-width:2.000000e-02;stroke-miterlimit:10;} + .st18{opacity:0.3;} + .st19{fill:#E8505B;} + .st20{fill:#CC0000;} +</style> +<g id="Background_Complete"> + <g> + <g> + <g> + <path class="st0" d="M450.1,142.2L360.5,162c-3.7,0.8-7.3-1.5-8.1-5.2l-18.7-84.3c-0.8-3.7,1.5-7.3,5.2-8.1l89.6-19.8 + c3.7-0.8,7.3,1.5,8.1,5.2l18.7,84.3C456,137.8,453.7,141.4,450.1,142.2z"/> + </g> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st1" d="M414.9,114.2c0,0-0.2,0.1-0.7,0.2c-0.5,0.1-1.2,0.3-2,0.5c-1.8,0.4-4.3,1-7.4,1.7 + c-6.3,1.4-15,3.4-24.7,5.6l-0.2,0l-0.1-0.2c-0.5-1.3-1-2.6-1.5-4c-4.3-11.6-8.2-22-10.7-28.8l0.2,0.1 + c-2.8,0.6-5,1.1-6.6,1.4c-0.7,0.1-1.3,0.3-1.8,0.4c-0.4,0.1-0.6,0.1-0.6,0.1c0,0,0.2-0.1,0.6-0.2c0.4-0.1,1-0.3,1.7-0.4 + c1.6-0.4,3.8-0.9,6.6-1.5l0.1,0l0,0.1c2.6,6.8,6.5,17.1,10.9,28.7c0.5,1.4,1,2.7,1.5,4l-0.3-0.1c9.8-2.2,18.5-4.1,24.8-5.5 + c3.1-0.7,5.6-1.2,7.4-1.6c0.8-0.2,1.5-0.3,2-0.4C414.7,114.2,414.9,114.2,414.9,114.2z"/> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st1" d="M377.5,115c0,0,0.1,0,0.2-0.1c0.1,0,0.3-0.1,0.5-0.1c0.5-0.1,1.1-0.3,2-0.5c1.8-0.4,4.3-1,7.4-1.7 + c6.4-1.5,15.3-3.5,25.7-5.8l-0.2,0.2c-0.2-4.5-0.4-9.3-0.7-14.4c-0.1-2.6-0.2-5.1-0.3-7.5l0.3,0.2c-12,2.7-22.6,5-30.3,6.7 + c-3.8,0.8-6.8,1.5-9,1.9c-1,0.2-1.8,0.4-2.4,0.5c-0.3,0-0.5,0.1-0.6,0.1c-0.1,0-0.2,0-0.2,0c0,0,0.1,0,0.2-0.1 + c0.2,0,0.4-0.1,0.6-0.2c0.6-0.1,1.4-0.3,2.4-0.6c2.1-0.5,5.2-1.2,8.9-2.1c7.6-1.7,18.2-4.1,30.2-6.9l0.3-0.1l0,0.3 + c0.1,2.4,0.2,5,0.3,7.5c0.2,5,0.4,9.9,0.6,14.4l0,0.2l-0.2,0c-10.4,2.3-19.3,4.3-25.7,5.7c-3.2,0.7-5.7,1.2-7.5,1.6 + c-0.8,0.2-1.5,0.3-2,0.4c-0.2,0-0.4,0.1-0.5,0.1C377.6,115,377.5,115,377.5,115z"/> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st1" d="M391,129.5c0,0-0.1-0.3-0.4-0.8c-0.3-0.5-0.8-1.1-1.7-1.5c-0.9-0.4-2.1-0.4-3.2,0.3 + c-1.1,0.7-1.8,2.1-1.4,3.5c0.3,1.4,1.6,2.4,2.8,2.6c1.3,0.2,2.4-0.4,3-1.1c0.6-0.7,0.8-1.6,0.9-2.1 + C391,129.8,390.9,129.5,391,129.5c0,0,0.2,0.3,0.2,0.9c0,0.6-0.1,1.5-0.8,2.3c-0.6,0.8-1.9,1.5-3.3,1.3 + c-1.4-0.1-2.9-1.3-3.2-2.9c-0.4-1.6,0.5-3.3,1.7-4c1.2-0.8,2.7-0.7,3.6-0.2c1,0.5,1.5,1.2,1.7,1.7 + C391,129.2,391,129.5,391,129.5z"/> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st1" d="M413.3,124.5c0,0-0.1-0.3-0.4-0.8c-0.3-0.5-0.8-1.1-1.7-1.5c-0.9-0.4-2.1-0.4-3.2,0.3 + c-1.1,0.7-1.8,2.1-1.4,3.5c0.3,1.4,1.6,2.4,2.8,2.6c1.3,0.2,2.4-0.4,3-1.1c0.6-0.7,0.8-1.6,0.9-2.1 + C413.4,124.8,413.3,124.5,413.3,124.5c0,0,0.2,0.3,0.2,0.9c0,0.6-0.1,1.5-0.8,2.3c-0.6,0.8-1.9,1.5-3.3,1.3 + c-1.4-0.1-2.9-1.3-3.2-2.9c-0.4-1.6,0.5-3.3,1.7-4c1.2-0.8,2.7-0.7,3.6-0.2c1,0.5,1.5,1.2,1.7,1.7 + C413.4,124.1,413.4,124.5,413.3,124.5z"/> + </g> + </g> + </g> + <g> + <g> + <path class="st1" d="M419.6,79.8c1.2,5.5-2.2,10.9-7.7,12.2c-5.5,1.2-10.9-2.2-12.2-7.7c-1.2-5.5,2.2-10.9,7.7-12.2 + C412.9,70.8,418.3,74.3,419.6,79.8z"/> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st2" d="M414.2,77.1c0.1,0-0.3,0.8-0.9,1.9c-0.6,1.1-1.5,2.7-2.5,4.4c-0.4,0.6-0.7,1.2-1.1,1.8l-0.1,0.2 + l-0.2-0.1c-2.6-1.4-4.4-2.5-4.3-2.6c0.1-0.1,2,0.8,4.6,2.2l-0.3,0.1c0.3-0.6,0.7-1.2,1.1-1.8c1-1.7,2-3.2,2.7-4.3 + C413.7,77.7,414.1,77,414.2,77.1z"/> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st2" d="M72.3,194.4c-1.8-6.5-10.3-5.9-10.3-5.9l0.2,4.5c4.9-0.8,8,4.9,8,4.9L72.3,194.4z"/> + </g> + </g> + <g> + <g> + <path class="st2" d="M197,118.9c9.8,3,16-8.4,16-8.4l-6-3.4c-2.9,7-12.8,6.2-12.8,6.2L197,118.9z"/> + </g> + </g> + <g> + <g> + <path class="st2" d="M278.7,179.9c-1.9-5.4-9.1-4.4-9.1-4.4l0.4,3.8c4.1-1,7,3.7,7,3.7L278.7,179.9z"/> + </g> + </g> + <g> + <g> + <path class="st2" d="M165.8,52.7c-1.9-5.4-9.1-4.4-9.1-4.4l0.4,3.8c4.1-1,7,3.7,7,3.7L165.8,52.7z"/> + </g> + </g> + <g> + <g> + <path class="st0" d="M80.4,122.2c-1.9-5.4-9.1-4.4-9.1-4.4l0.4,3.8c4.1-1,7,3.7,7,3.7L80.4,122.2z"/> + </g> + </g> + <g> + <g> + <path class="st0" d="M62.5,71.4c-5.7,0.9-6,8.1-6,8.1l3.9,0.2c-0.2-4.2,4.9-6.2,4.9-6.2L62.5,71.4z"/> + </g> + </g> + <g> + <g> + <path class="st0" d="M21.6,240.4c9.9,3,16-8.4,16-8.4l-6-3.4c-2.9,7-12.8,6.2-12.8,6.2L21.6,240.4z"/> + </g> + </g> + <g> + <g> + <path class="st2" d="M302.2,119.6c0.7-4.6-4.8-6.5-4.8-6.5l-1.1,2.9c3.3,0.8,3.6,5.2,3.6,5.2L302.2,119.6z"/> + </g> + </g> + <g> + <g> + <path class="st0" d="M269.5,69.5c-3.8,2.5-1.7,7.9-1.7,7.9l2.9-1.1c-1.6-3,1.5-6.2,1.5-6.2L269.5,69.5z"/> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <polygon class="st3" points="436.1,171.6 422.8,210.7 462.1,218.5 464.4,177.2 "/> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <path class="st4" d="M460,182.4c0,0-0.1,0.4-0.4,1.1c-0.4,0.7-1,1.6-2,2.6c-1,1-2.4,2-4.2,2.6c-1.8,0.6-3.9,0.7-6,0.3 + c-2.1-0.4-4-1.2-5.5-2.5c-1.5-1.2-2.3-2.7-2.8-4c-0.5-1.3-0.6-2.5-0.7-3.2c0-0.8,0-1.2,0.1-1.2c0.1,0,0,1.7,1.1,4.2 + c0.5,1.2,1.4,2.6,2.8,3.7c1.4,1.1,3.2,1.9,5.2,2.3c2,0.4,4,0.3,5.7-0.2c1.7-0.5,3-1.4,4-2.3 + C459.2,183.9,459.9,182.3,460,182.4z"/> + </g> + </g> + </g> + </g> + </g> +</g> +<g id="Background_Simple" class="st5"> + <g class="st6"> + <path class="st0" d="M462.6,168.7c-10.1-32-28.2-62.7-55.9-80.6c-25.8-16.7-58.9-21-88-11.3c-29,9.7-53.4,33.1-64.6,62.2 + c-6,15.6-8.4,32.4-13.4,48.4c-5,16-13.4,31.9-27.6,40.2c-15.9,9.3-35.8,7.3-53.6,2.5c-17.7-4.8-35.1-12.1-53.5-12.5 + c-38-0.8-67.2,33.9-75.5,72c-9.2,42.5-4.1,86.6,51.5,117.4c0.9,0.5,1.2,0.7,1.1,0.7c20.2,12.8,32,22.3,54.3,28.4 + c52.7,12.9,110.8,2.8,152.9,0c54.8-3.7,73.2-18.6,107.5-43.8c32.9-24.2,56.8-60.6,67.8-100.6C476.7,251.5,475.1,208.2,462.6,168.7 + z"/> + <path class="st0" d="M83.2,407.6c-0.4-0.2-0.7-0.5-1.1-0.7C78.8,405.6,83,407.6,83.2,407.6z"/> + </g> + <path class="st7" d="M175.1,60.3c-10.8-8.5-25.8-11-39.1-7.5c-11.6,3-22.4,10.8-26.5,22.1c-3.3,9-2,19.3,2.2,27.9 + c5.9,12.2,17.5,21.6,30.7,24.9c13.2,3.2,27.8,0.3,38.7-7.8l-1.8,0.7c6.6-4.5,7.8-13.9,9.9-23.7C191.9,83.5,185.9,68.8,175.1,60.3z" + /> +</g> +<g id="Desk"> + <g> + <g> + <path class="st8" d="M474.1,454.2c0,0.1-102.6,0.3-229.1,0.3c-126.5,0-229.1-0.1-229.1-0.3s102.5-0.3,229.1-0.3 + C371.5,453.9,474.1,454,474.1,454.2z"/> + </g> + </g> +</g> +<g id="Screen"> + <g> + <g> + <g> + <rect x="32.8" y="145.8" class="st1" width="243.9" height="190.9"/> + </g> + <g> + <g> + <path class="st8" d="M276.6,336.7c0-1.8-0.1-75.7-0.2-190.9l0.2,0.2c-69.5,0-153.4,0-243.8,0h0l0.3-0.3c0,68.8,0,133.9,0,190.9 + l-0.2-0.2C177.5,336.6,274.6,336.7,276.6,336.7c-2,0-99.1,0.1-243.9,0.2l-0.2,0l0-0.2c0-57,0-122.1,0-190.9l0-0.3h0.3h0 + c90.4,0,174.3,0,243.8,0l0.2,0l0,0.2C276.7,261,276.6,334.9,276.6,336.7z"/> + </g> + </g> + </g> + <g> + <g> + <path class="st9" d="M190.9,310.7h-72.5c-8.3,0-15-6.7-15-15l0,0c0-8.3,6.7-15,15-15h72.5c8.3,0,15,6.7,15,15l0,0 + C206,304,199.2,310.7,190.9,310.7z"/> + </g> + <g> + <path class="st1" d="M136.4,298.7c-0.8,0-1.4-0.2-2-0.5c-0.5-0.3-0.9-0.8-1.1-1.4l1.5-0.9c0.3,0.7,0.8,1.1,1.6,1.1 + c0.7,0,1-0.2,1-0.6c0-0.2-0.1-0.4-0.3-0.5c-0.2-0.1-0.6-0.3-1.3-0.4c-0.3-0.1-0.6-0.2-0.8-0.3c-0.2-0.1-0.5-0.3-0.7-0.4 + c-0.2-0.2-0.4-0.4-0.5-0.7s-0.2-0.6-0.2-0.9c0-0.7,0.3-1.3,0.8-1.7c0.5-0.4,1.1-0.6,1.8-0.6c0.6,0,1.2,0.1,1.7,0.4 + c0.5,0.3,0.9,0.7,1.1,1.3l-1.5,0.9c-0.1-0.3-0.3-0.5-0.5-0.7c-0.2-0.1-0.5-0.2-0.8-0.2c-0.3,0-0.5,0.1-0.6,0.2 + c-0.1,0.1-0.2,0.3-0.2,0.4c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.6,0.3,1.1,0.5c0.3,0.1,0.5,0.2,0.7,0.2c0.2,0.1,0.4,0.2,0.6,0.3 + c0.3,0.1,0.5,0.3,0.6,0.4s0.3,0.3,0.4,0.6c0.1,0.2,0.2,0.5,0.2,0.8c0,0.7-0.3,1.3-0.8,1.7C137.9,298.5,137.2,298.7,136.4,298.7z + "/> + <path class="st1" d="M142,296.8h3.1v1.7h-4.8v-7.7h4.8v1.7h-3v1.3h2.8v1.7H142V296.8z"/> + <path class="st1" d="M148.1,296.8h2.8v1.7h-4.5v-7.7h1.8V296.8z"/> + <path class="st1" d="M153.6,296.8h3.1v1.7h-4.8v-7.7h4.8v1.7h-3v1.3h2.8v1.7h-2.8V296.8z"/> + <path class="st1" d="M160.6,298.7c-0.8,0-1.4-0.2-2-0.5c-0.5-0.3-0.9-0.8-1.1-1.4l1.5-0.9c0.3,0.7,0.8,1.1,1.6,1.1 + c0.7,0,1-0.2,1-0.6c0-0.2-0.1-0.4-0.3-0.5c-0.2-0.1-0.6-0.3-1.3-0.4c-0.3-0.1-0.6-0.2-0.8-0.3c-0.2-0.1-0.5-0.3-0.7-0.4 + c-0.2-0.2-0.4-0.4-0.5-0.7s-0.2-0.6-0.2-0.9c0-0.7,0.3-1.3,0.8-1.7c0.5-0.4,1.1-0.6,1.8-0.6c0.6,0,1.2,0.1,1.7,0.4 + c0.5,0.3,0.9,0.7,1.1,1.3l-1.5,0.9c-0.1-0.3-0.3-0.5-0.5-0.7c-0.2-0.1-0.5-0.2-0.8-0.2c-0.3,0-0.5,0.1-0.6,0.2 + c-0.1,0.1-0.2,0.3-0.2,0.4c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.6,0.3,1.1,0.5c0.3,0.1,0.5,0.2,0.7,0.2c0.2,0.1,0.4,0.2,0.6,0.3 + c0.3,0.1,0.5,0.3,0.6,0.4s0.3,0.3,0.4,0.6c0.1,0.2,0.2,0.5,0.2,0.8c0,0.7-0.3,1.3-0.8,1.7C162.1,298.5,161.4,298.7,160.6,298.7z + "/> + <path class="st1" d="M169.4,298.5l-0.4-1.2h-3l-0.4,1.2h-1.9l2.6-7.7h2.2l2.6,7.7H169.4z M166.6,295.7h1.9l-1-2.8L166.6,295.7z" + /> + <path class="st1" d="M172.1,290.8h1.8v7.7h-1.8V290.8z"/> + </g> + </g> + <g> + <g> + <path class="st9" d="M156.7,219c-10.7,0-19.4-8.7-19.4-19.4c0-10.7,8.7-19.4,19.4-19.4s19.4,8.7,19.4,19.4 + C176.1,210.3,167.4,219,156.7,219z M156.7,182.2c-9.6,0-17.4,7.8-17.4,17.4c0,9.6,7.8,17.4,17.4,17.4c9.6,0,17.4-7.8,17.4-17.4 + C174.1,190,166.3,182.2,156.7,182.2z"/> + </g> + <g> + <path class="st9" d="M155.3,205.6c-0.2,0-0.5-0.1-0.7-0.2c-1.7-1.5-4.6-4.1-5-4.6c-0.3-0.5-0.2-1.1,0.3-1.4 + c0.5-0.3,1.1-0.2,1.4,0.3c0.3,0.3,2.1,2,4,3.7l9.8-9.3c0.4-0.4,1-0.4,1.4,0c0.4,0.4,0.4,1,0,1.4l-10.5,9.9 + C155.8,205.5,155.5,205.6,155.3,205.6z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M276.6,164.5c0,0.1-54.5,0.3-121.6,0.3c-67.2,0-121.6-0.1-121.6-0.3s54.4-0.3,121.6-0.3 + C222.2,164.2,276.6,164.3,276.6,164.5z"/> + </g> + </g> + <g> + <g> + <circle class="st8" cx="41.4" cy="154.9" r="1.4"/> + </g> + <g> + <circle class="st8" cx="46.7" cy="154.9" r="1.4"/> + </g> + <g> + <path class="st8" d="M53.3,154.9c0,0.8-0.6,1.4-1.4,1.4c-0.8,0-1.4-0.6-1.4-1.4c0-0.8,0.6-1.4,1.4-1.4 + C52.6,153.5,53.3,154.1,53.3,154.9z"/> + </g> + </g> + <text transform="matrix(1 0 0 1 61.8303 245.5229)" class="st8 st10 st11">Pembelianmu sudah kami terima</text> + <text transform="matrix(1 0 0 1 69.6563 258.5025)" class="st8 st12 st13">Mohon cek pesananmu di detail pesanan</text> + </g> +</g> +<g id="Character"> + <g> + <g> + <path class="st14" d="M436.9,274.1c0,0,12.1-7.4,14.9-5.2c3.9,3.1,5.3,8.4,5.3,8.4s6.4-24.4,12.5-23.5c3.5,0.5,1.8,3.3,0.2,6.7 + c-1.5,3.2-4,14.9-4,14.9s11.6-13.8,15-13.5c2.6,0.2,3,2.5-0.8,6.2c-3.8,3.7-10.1,15.4-10.1,15.4s8.1-7.6,11.5-7.6 + c2.7,0,4.4,1.8,0.9,4.8c-3.5,3-8.7,5.3-11.5,10.7c-3.4,6.7-10.8,23.4-10.8,23.4l-25.7-9.1c0,0-4.2-17.1-4.4-21.2 + c0,0,0.4-8.8,0.3-10.3c0-1.6,4.1-2,5.3,1c1.3,3,0.7,6.1,1.2,8.1c0.5,2,1.4,3.8,2.9,4.7c1.5,0.9,5.2,1,6.1-0.1 + c0.9-1.1,2.1-4.3,2.3-6.3c0.2-2-0.1-5.1-0.1-5.1S437.4,280.9,436.9,274.1z"/> + </g> + <g> + <g> + <g> + <path class="st14" d="M147.9,353.7L130,347c0,0-18.2-10.7-21.6-6.9c0,0-3.6-1.7-5.2,2.1c-0.9,2.2,2.1,5.5,2.1,5.5s-1,1,0.6,4.2 + c1.5,3.3,18.8,13.6,18.8,13.6s22.5,12.2,31.5,18.1l15.7-21.3l-2.2-0.8c0,0-1.3-10.6-5.6-13.5c-4.7-3.1-10.4-11.4-11.7-14.7 + c-1.3-3.3-7.3-1.8-6.3,5c1,6.8,6.3,8.5,5.8,13.1C151.4,356,147.9,353.7,147.9,353.7z"/> + </g> + <g> + <g> + <path class="st15" d="M120.5,356.2c-0.1,0.1-3.6-1.7-7.8-4.1c-4.2-2.4-7.6-4.4-7.5-4.5c0.1-0.1,3.6,1.7,7.8,4.1 + C117.2,354,120.5,356.1,120.5,356.2z"/> + </g> + </g> + <g> + <g> + <path class="st15" d="M129.2,351.2c0,0.1-1.3-0.4-3.2-1.3c-2-0.9-4.6-2.1-7.5-3.6c-2.9-1.5-5.5-3-7.2-4.1 + c-0.9-0.6-1.6-1.1-2.1-1.4c-0.5-0.4-0.7-0.6-0.7-0.6c0-0.1,1.1,0.7,3,1.7c1.8,1.1,4.4,2.5,7.3,4c2.9,1.5,5.5,2.7,7.5,3.7 + C128.1,350.5,129.2,351.1,129.2,351.2z"/> + </g> + </g> + <g> + <g> + <path class="st15" d="M133,361c0,0-0.6-0.3-1.6-0.9c-1.1-0.6-2.5-1.5-4.2-2.5l0,0l0-0.1c-0.8-1.7-1.8-3.7-3-5.8 + c-0.6-1-1.3-2.1-2.3-3c-0.9-0.9-2.4-1-3.5-0.3c-0.2,0.1-0.5,0.4-0.6,0.5c0,0,0,0.1,0,0.1l0.1,0.2c0,0.1,0.1,0.3,0.2,0.4 + c0.2,0.6,0.5,1.2,0.7,1.8c0.5,1.2,0.9,2.3,1.4,3.3c0.9,2.1,1.7,4.1,2.4,5.8l0-0.1c1.5,1.7,2.7,3.1,3.6,4.2 + c0.4,0.5,0.7,0.9,1,1.2c0.2,0.3,0.3,0.4,0.3,0.4c0,0-0.2-0.1-0.4-0.4c-0.3-0.3-0.6-0.7-1-1.1c-0.9-1-2.2-2.4-3.7-4.1l0,0l0,0 + c-0.7-1.7-1.6-3.6-2.5-5.7c-0.4-1.1-0.9-2.2-1.4-3.3c-0.2-0.6-0.5-1.2-0.7-1.8c-0.1-0.2-0.1-0.3-0.2-0.5l-0.1-0.2 + c0-0.1,0-0.2-0.1-0.4c0.1-0.3,0.2-0.4,0.4-0.5c0.1-0.1,0.3-0.2,0.4-0.3c0.6-0.4,1.4-0.6,2.2-0.6c0.8,0,1.4,0.4,2,0.9 + c1,1,1.7,2.1,2.4,3.1c1.3,2.1,2.2,4.2,3,5.9l-0.1-0.1c1.7,1.1,3.1,2,4.1,2.7C132.5,360.6,133,361,133,361z"/> + </g> + </g> + </g> + <g> + <g> + <path class="st15" d="M150.9,361.2c0,0.1-0.9-0.2-2.2-0.5c-1.3-0.4-3.2-0.9-5.3-0.9c-2.1,0-3.9,0.5-5.1,1.2 + c-1.2,0.7-1.7,1.4-1.8,1.4c0,0,0.4-0.8,1.6-1.7c1.2-0.8,3.1-1.5,5.3-1.5c2.2,0.1,4.1,0.6,5.4,1.1 + C150.1,360.8,150.9,361.1,150.9,361.2z"/> + </g> + </g> + <g> + <g> + <path class="st15" d="M149.5,356.5c0.1,0.1-0.3,0.9-0.8,1.9c-0.4,1-0.7,1.8-0.9,1.8c-0.1,0-0.1-1,0.4-2 + C148.8,357.1,149.4,356.4,149.5,356.5z"/> + </g> + </g> + </g> + <g> + <g> + <path class="st8" d="M252.6,271.5c1.2-8.4,11-20.5,19.7-20.5c-5-7.2-5.1-17.4-0.2-24.6c3.3-5,8.8-8.7,11-14.3 + c2.6-6.3,0.6-13.4,0.9-20.2c0.4-9.9,5.5-19,10.5-27.6c4.6-7.9,10.2-16.5,19.3-18.5c5.7-1.2,11.7,0.6,17.1,2.9 + c25.7,11,45.8,34.1,52.6,60.8c1.6,6.4,2.7,13.3,7.2,18.2c4.7,5.2,13,8.1,14.4,14.9c1,4.9-2.1,9.8-1.7,14.8 + c0.4,4.2,8.2,16.3,10,20.1c3.1,6.5,2,13.6-1.2,20.1c-3.2,6.5-11.2,12.9-18.3,14.7l-79.8-26.6c-7.5,4.3-15,20.8-23.6,21.8 + c-8.6,1-19.1,4.8-27.4-4.3C254.4,293.8,251.3,279.9,252.6,271.5z"/> + </g> + <g> + <path class="st8" d="M384.9,192.1c-0.9,6.7,0.9,17.7,4.6,23.4c2.4,3.8,6.5,6.3,10.6,8.5c4,2.2,8.3,4.3,11.3,7.7 + c3.1,3.4,4.7,8.5,2.7,12.5c7.2,2.7,10.4,11.8,7.8,18.9c-2.6,7.1-9.9,11.8-17.4,13.3l-32.9-9.9l-7.2-42l19-32.4"/> + </g> + <g> + <g> + <path class="st16" d="M388.9,234.9c0,0,0.2,0.1,0.6,0.3c0.4,0.2,1.1,0.5,1.8,0.9c1.5,0.9,3.6,2.4,5.8,4.8 + c1.1,1.2,2.1,2.6,3.1,4.3c0.9,1.7,1.8,3.5,2.4,5.6c1.3,4.1,1.6,9.1,0.1,14l-0.1-0.3c1.9,1.1,3.7,2.4,5.4,4.1 + c4.2,4.2,6.6,9.6,7.2,14.7c0.6,5.1-0.7,9.7-2.4,13.2c-1.7,3.5-3.8,5.8-5.4,7.3c-0.8,0.7-1.4,1.2-1.9,1.6 + c-0.5,0.3-0.7,0.5-0.7,0.5c0,0,0.2-0.2,0.7-0.6c0.4-0.3,1.1-0.9,1.8-1.6c1.5-1.5,3.6-3.8,5.2-7.3c1.6-3.4,2.8-8,2.2-13 + c-0.6-5-3-10.3-7.1-14.3c-1.6-1.6-3.4-3-5.2-4l-0.2-0.1l0.1-0.2c1.4-4.8,1.2-9.7,0-13.7c-0.6-2.1-1.4-3.9-2.3-5.5 + c-0.9-1.6-1.9-3.1-3-4.2c-2.1-2.4-4.1-4-5.6-4.9c-0.7-0.5-1.4-0.8-1.7-1C389.1,235.1,388.9,234.9,388.9,234.9z"/> + </g> + </g> + </g> + <g> + <g> + <path class="st9" d="M291.6,278.4c0,0-14.7,4.5-19.9,12c-3.6,5.3-41,86.2-41,86.2l-56.7-17l-20.3,26.8l63.1,35 + c11.7,6.5,25.9,6.4,37.5-0.2l0,0c6.5-3.7,11.7-9.1,15.1-15.7l16-30.7L291.6,278.4z"/> + </g> + <g> + <g> + <path class="st9" d="M276.5,454.5l8.9-38.1l-6.7-27.7c-4.3-14.3-8-37.5-3.3-56.2l15.7-53.8l17.2-7.9l39.4-6.8 + c1.5,0.5,41.2,11.7,41.2,11.7c5.5,1.3,7.7,2.2,7.7,2.2l4.6,29.5l-13.7,48.6l-6,48.4l13.1,50.3H276.5z"/> + </g> + <g> + <g> + <path class="st17" d="M273.6,335.9"/> + </g> + </g> + <g> + <g> + <path class="st17" d="M366,339.4"/> + </g> + </g> + </g> + <g> + <path class="st14" d="M299.3,274.9l11.4-5.1l51.5,0.7l12.2,7.1c0,0-42.6,47-53.3,48.6C294.3,330,299.3,274.9,299.3,274.9z"/> + </g> + <g> + <path class="st9" d="M395.5,277.4c0,0,7.7,1.7,14.3,15.9c6.6,14.1,17.3,53.4,17.3,53.4l4.6-41.6l37.3,4.1l-7.2,99.5 + c0,0-13.2,19.1-35.3,17.4c-22.1-1.8-50.1-71.5-50.1-71.5L395.5,277.4z"/> + </g> + <g> + <g> + <path class="st8" d="M421.4,397.6c0,0,0-0.1,0-0.2c0-0.2,0-0.4,0-0.7c0-0.7,0.1-1.6,0.2-2.7c0.1-2.4,0.4-5.8,0.8-9.9 + c0.8-8.4,2.2-19.9,3.9-32.7c1.7-12.7,3.2-24.3,4.1-32.7c0.4-4.2,0.8-7.6,1-9.9c0.1-1.1,0.2-2,0.3-2.7c0-0.3,0.1-0.5,0.1-0.7 + c0-0.2,0-0.2,0-0.2c0,0,0,0.1,0,0.2c0,0.2,0,0.4,0,0.7c0,0.7-0.1,1.6-0.2,2.7c-0.1,2.4-0.4,5.8-0.8,9.9 + c-0.8,8.4-2.2,19.9-3.9,32.7c-1.7,12.7-3.2,24.3-4.1,32.6c-0.4,4.2-0.8,7.6-1,9.9c-0.1,1.1-0.2,2-0.3,2.7 + c0,0.3-0.1,0.5-0.1,0.7C421.4,397.5,421.4,397.6,421.4,397.6z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M231.4,398c0,0-0.2-0.3-0.4-0.7c-0.2-0.5-0.5-1.2-0.9-2.1c-0.7-1.8-1.3-4.5-1.6-7.5 + c-0.3-3-0.1-5.7,0.2-7.6c0.1-1,0.3-1.7,0.4-2.3c0.1-0.5,0.2-0.8,0.3-0.8c0.1,0-0.1,1.2-0.3,3.1c-0.2,1.9-0.3,4.6,0,7.5 + c0.3,2.9,0.9,5.5,1.5,7.4C231,396.9,231.4,398,231.4,398z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M237.6,399c0,0-0.3-0.2-0.7-0.7c-0.4-0.5-0.9-1.2-1.6-2.2c-1.2-1.9-2.7-4.7-3.9-8 + c-1.1-3.3-1.7-6.4-1.9-8.7c-0.1-1.1-0.2-2.1-0.2-2.7c0-0.6,0-1,0.1-1c0.1,0,0.2,1.4,0.5,3.6c0.3,2.2,0.9,5.3,2.1,8.6 + c1.1,3.3,2.6,6,3.7,8C236.9,397.8,237.7,398.9,237.6,399z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M281.7,310c0,0,0,0.3-0.2,0.8c-0.2,0.6-0.4,1.3-0.6,2.3c-0.6,2-1.4,4.9-2.4,8.4 + c-1.9,7.1-4.6,16.9-5.9,28.1c-0.6,5.6-0.8,10.9-0.2,15.8c0.5,4.8,1.6,9.1,2.6,12.6c1.1,3.5,2.1,6.3,2.7,8.3 + c0.3,0.9,0.6,1.7,0.8,2.2c0.2,0.5,0.3,0.8,0.2,0.8c0,0-0.1-0.3-0.3-0.8c-0.2-0.5-0.5-1.3-0.9-2.2c-0.7-1.9-1.8-4.7-2.9-8.2 + c-1.1-3.5-2.2-7.8-2.8-12.7c-0.6-4.9-0.5-10.3,0.2-15.9c1.3-11.2,4.1-21.1,6.1-28.1c1-3.5,1.9-6.4,2.5-8.3 + c0.3-0.9,0.5-1.7,0.7-2.3C281.6,310.3,281.7,310,281.7,310z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M386,375.6c0,0-0.1-0.1-0.1-0.2c-0.1-0.2-0.2-0.4-0.3-0.7c-0.3-0.7-0.7-1.6-1.3-2.9 + c-0.6-1.2-1.3-2.8-2-4.6c-0.7-1.8-1.5-3.9-2.4-6.1c-0.9-2.3-1.7-4.8-2.7-7.5c-0.4-1.4-0.9-2.8-1.3-4.3 + c-0.2-0.7-0.5-1.5-0.7-2.2c-0.2-0.8-0.4-1.5-0.6-2.3c-1.7-6.2-3.1-13.2-3.5-20.7c-0.5-7.5,0.3-14.7,2.2-20.9 + c1.8-6.3,4.9-11.4,8.3-15c3.3-3.6,6.8-5.7,9.3-6.8c1.3-0.5,2.3-0.9,3-1.1c0.3-0.1,0.6-0.2,0.8-0.2c0.2,0,0.3-0.1,0.3-0.1 + c0,0-0.1,0-0.3,0.1c-0.2,0.1-0.5,0.2-0.8,0.3c-0.7,0.2-1.7,0.6-2.9,1.2c-2.4,1.2-5.9,3.3-9.1,6.9c-3.3,3.6-6.3,8.7-8.1,14.8 + c-1.9,6.2-2.5,13.3-2.1,20.7c0.4,7.4,1.8,14.4,3.5,20.6c0.2,0.8,0.4,1.5,0.6,2.3c0.2,0.8,0.4,1.5,0.7,2.2 + c0.4,1.5,0.9,2.9,1.3,4.3c1,2.7,1.8,5.2,2.6,7.5c0.9,2.3,1.7,4.3,2.4,6.1c0.7,1.8,1.4,3.3,1.9,4.6c0.5,1.2,0.9,2.2,1.2,2.9 + c0.1,0.3,0.2,0.6,0.3,0.8C385.9,375.5,386,375.6,386,375.6z"/> + </g> + </g> + <g class="st18"> + <g> + <path d="M371.8,330.5c-4.9,23-4.9,46.8,3.5,68.8c0.5,1.3,2.4,5.8,3.8,5.9c1.7,0.1,2.6-2.1,2.9-3.8c0.6-3.5,1-9.3,1.6-12.8 + c0.8-4.4,1.8-14.6,1.8-14.6s-4-9.2-5.8-14.2c-3.3-9.2-6.1-17.9-7.6-28.6"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M367.8,419.8c0,0-0.1,0.2-0.4,0.6c-0.3,0.4-0.7,1-1.2,1.7c-0.3,0.4-0.6,0.8-0.9,1.2 + c-0.3,0.4-0.7,0.9-1.1,1.3c-0.8,0.9-1.7,2.1-2.9,3.2c-0.6,0.6-1.2,1.1-1.8,1.8c-0.6,0.6-1.4,1.2-2.1,1.8 + c-1.4,1.3-3.1,2.4-4.8,3.6c-3.5,2.3-7.6,4.6-12.2,6.4c-4.6,1.7-9.1,2.9-13.3,3.5c-2.1,0.2-4.1,0.5-6,0.6 + c-0.9,0-1.8,0.1-2.7,0.1c-0.9,0-1.7-0.1-2.5-0.1c-1.6,0-3-0.2-4.3-0.4c-0.6-0.1-1.2-0.1-1.8-0.2c-0.5-0.1-1-0.2-1.5-0.3 + c-0.8-0.2-1.5-0.3-2-0.4c-0.5-0.1-0.7-0.2-0.7-0.2c0,0,0.3,0,0.7,0.1c0.5,0.1,1.2,0.2,2,0.3c0.4,0.1,0.9,0.2,1.5,0.2 + c0.5,0.1,1.1,0.1,1.8,0.2c1.3,0.1,2.7,0.3,4.3,0.3c0.8,0,1.6,0,2.5,0c0.9,0,1.8-0.1,2.7-0.1c1.9,0,3.8-0.3,5.9-0.6 + c4.1-0.7,8.6-1.8,13.2-3.5c4.5-1.8,8.6-4,12.1-6.3c1.7-1.2,3.4-2.3,4.8-3.6c0.7-0.6,1.4-1.1,2.1-1.7c0.6-0.6,1.2-1.2,1.8-1.7 + c1.2-1.1,2.1-2.2,3-3.1c0.4-0.5,0.8-0.9,1.2-1.3c0.3-0.4,0.6-0.8,0.9-1.2c0.5-0.7,0.9-1.2,1.3-1.6 + C367.6,420,367.8,419.8,367.8,419.8z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M359.7,404.6c0,0,0,0.4-0.1,1.1c-0.1,0.7-0.3,1.7-0.7,2.9c-0.7,2.4-2,5.7-4.1,9c-2.1,3.3-4.6,5.8-6.5,7.4 + c-1,0.8-1.8,1.4-2.4,1.8c-0.6,0.4-0.9,0.6-0.9,0.6c-0.1-0.1,1.2-1,3.1-2.7c1.9-1.7,4.2-4.2,6.3-7.5c2.1-3.2,3.4-6.4,4.2-8.8 + C359.3,406.1,359.6,404.6,359.7,404.6z"/> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st9" d="M341.5,139.4c14,0.1,27.6,8,34.7,20c7.1,12,7.3,27.8,0.6,40c-2.3,4.2-5.6,8.1-10.1,9.6 + c1.5-23.9-8-48.3-25.3-64.9"/> + </g> + <g> + <path class="st9" d="M357.8,143.1c-2.1-4.3,0.1-9.7,3.8-12.7c3.7-3,8.5-4.3,13.2-5.4c4.6-1.1,9.5-2.3,13.2-5.2 + c-0.5,7.5-2.4,15.2-7.3,20.9c-4.8,5.7-13.2,8.9-20.2,6"/> + </g> + <g> + <path class="st9" d="M362.6,148c-3.2,1.3-7,0.5-9.8-1.4c-2.8-2-4.9-4.9-6.6-7.9c-2.1-3.7-3.7-7.7-4.2-11.9s0-8.6,2.1-12.3 + c5.5,5.8,11.5,10.7,14.6,18.1c1.8,4.3,1.6,11.3-0.4,15.5"/> + </g> + <g> + <g> + <path class="st8" d="M378.1,172.2c0,0,0.1,0.5,0.3,1.4c0.1,0.5,0.2,1,0.2,1.6c0.1,0.6,0.1,1.4,0.2,2.2 + c0.1,1.6,0.1,3.6-0.1,5.7c-0.2,2.2-0.5,4.5-1.1,6.9c-0.6,2.4-1.3,4.7-2.1,6.7c-0.8,2-1.7,3.8-2.5,5.2 + c-0.4,0.7-0.8,1.3-1.1,1.9c-0.3,0.6-0.7,1-0.9,1.4c-0.5,0.7-0.8,1.1-0.9,1.1c0,0,0.2-0.5,0.7-1.2c0.2-0.4,0.5-0.9,0.8-1.4 + c0.3-0.6,0.7-1.2,1.1-1.9c0.8-1.4,1.6-3.2,2.4-5.2c0.8-2,1.5-4.2,2.1-6.6c0.6-2.4,0.9-4.7,1.1-6.9c0.2-2.1,0.3-4.1,0.2-5.7 + c0-0.8-0.1-1.5-0.1-2.2c0-0.6-0.1-1.2-0.1-1.6C378.1,172.8,378.1,172.2,378.1,172.2z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M375,145.4c0,0-0.4,0.3-1.1,0.9c-0.8,0.4-2,1.1-3.6,1.4c-3.2,0.7-7.9,0.6-12.8-0.7l-0.1,0l0-0.1 + c-0.1-0.3-0.1-0.6-0.2-0.9c-0.5-2.6-0.6-5.2-0.3-7.4c0.3-2.3,1.1-4.3,2.1-5.7c1-1.5,2.2-2.3,3-2.8c0.9-0.5,1.3-0.7,1.3-0.7 + c0,0-0.4,0.3-1.2,0.8c-0.7,0.6-1.9,1.4-2.8,2.9c-0.9,1.4-1.7,3.3-1.9,5.6c-0.3,2.2-0.2,4.7,0.4,7.3c0.1,0.3,0.1,0.6,0.2,0.9 + l-0.2-0.2c4.8,1.3,9.4,1.5,12.5,0.9c1.6-0.3,2.8-0.8,3.6-1.2C374.6,145.7,375,145.4,375,145.4z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M379.1,132.5c0,0.1-1.5,0.3-3.8,1c-1.1,0.3-2.5,0.8-3.9,1.5c-1.4,0.7-3,1.5-4.5,2.5c-1.5,1-2.9,2.1-4,3.1 + c-1.2,1.1-2.1,2.1-2.9,3c-1.5,1.8-2.3,3.1-2.4,3.1c0,0,0.1-0.3,0.5-0.9c0.3-0.6,0.9-1.4,1.6-2.4c0.7-1,1.7-2,2.9-3.1 + c1.2-1.1,2.5-2.2,4.1-3.2c1.6-1,3.1-1.8,4.6-2.5c1.5-0.6,2.8-1.1,4-1.4c1.2-0.3,2.1-0.5,2.8-0.6 + C378.7,132.5,379.1,132.4,379.1,132.5z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M362.4,147.9c0,0,0,0.1,0,0.3c0,0.2-0.1,0.5-0.3,0.8c-0.3,0.7-0.9,1.7-2,2.5c-1.1,0.8-2.6,1.5-4.5,1.5 + c-1.8-0.1-3.8-1.2-4.9-2.9c-1.2-1.7-1.5-3.9-0.9-5.7c0.6-1.8,1.8-3,3-3.7c1.2-0.7,2.3-0.9,3-0.9c0.4,0,0.7,0,0.9,0 + c0.2,0,0.3,0.1,0.3,0.1c0,0.1-0.4,0-1.1,0.1c-0.7,0.1-1.8,0.4-2.9,1.1c-1.1,0.7-2.2,1.9-2.7,3.5c-0.5,1.6-0.2,3.6,0.9,5.2 + c1.1,1.6,2.9,2.6,4.5,2.7c1.7,0.1,3.2-0.5,4.2-1.3c1-0.8,1.7-1.6,2-2.3C362.3,148.3,362.4,147.9,362.4,147.9z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M350.3,148.1c0,0-0.3-0.5,0.1-1.3c0.2-0.4,0.6-0.7,1.2-0.9c0.5-0.2,1.2-0.2,1.8-0.2 + c2.5,0.2,4.3,1.2,4.2,1.3c-0.1,0.1-1.9-0.6-4.3-0.7c-1.2-0.1-2.2,0.2-2.6,0.8C350.3,147.6,350.4,148.1,350.3,148.1z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M344.1,114.4c0.1,0-1.1,1.5-1.5,4.3c-0.2,1.4-0.3,3.1-0.2,5c0,1.9,0.1,3.9,0.5,6.1 + c0.9,4.2,2.7,7.8,4.3,10.1c0.8,1.2,1.5,2.1,2,2.7c0.5,0.6,0.8,0.9,0.8,0.9c-0.1,0.1-1.4-1.1-3.1-3.4 + c-1.7-2.3-3.5-5.9-4.5-10.2c-0.4-2.2-0.5-4.3-0.5-6.2c0-1.9,0.1-3.6,0.4-5c0.3-1.4,0.7-2.5,1.1-3.2 + C343.8,114.7,344.1,114.4,344.1,114.4z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M349.3,126.3c0.1,0,0.6,0.6,1.4,1.7c0.8,1.1,1.8,2.7,2.7,4.6c0.9,1.9,1.4,3.7,1.8,5 + c0.3,1.3,0.4,2.2,0.3,2.2c-0.2,0-0.8-3.3-2.6-7C351.2,129.1,349.2,126.4,349.3,126.3z"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M347.6,132.5c0.1-0.1,1.8,1.6,4,3.6c2.2,2,4,3.6,3.9,3.8c-0.1,0.1-2-1.4-4.2-3.4 + C349.1,134.5,347.5,132.6,347.6,132.5z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M373.8,156c0,0,0,0.1-0.1,0.1c-0.1,0.1-0.3,0.2-0.4,0.4c-0.4,0.3-1,0.8-1.7,1.3c-1.5,1-3.7,2.2-6.3,3.1 + c-2.6,0.9-5.1,1.2-6.9,1.3c-0.9,0-1.6,0-2.1,0c-0.2,0-0.4,0-0.6,0c-0.1,0-0.2,0-0.2,0c0,0,0.1,0,0.2,0c0.2,0,0.4,0,0.6,0 + c0.5,0,1.2,0,2.1-0.1c1.8-0.1,4.2-0.5,6.8-1.3c2.6-0.9,4.8-2,6.3-3c0.7-0.5,1.3-0.9,1.7-1.2c0.2-0.1,0.3-0.2,0.5-0.3 + C373.7,156,373.8,155.9,373.8,156z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M379.7,168.1c0,0,0,0.1-0.1,0.1c-0.1,0.1-0.3,0.2-0.4,0.4c-0.4,0.3-1,0.8-1.7,1.3c-1.5,1-3.7,2.2-6.3,3.2 + c-2.6,0.9-5.1,1.4-6.8,1.6c-0.9,0.1-1.6,0.1-2.1,0.1c-0.2,0-0.4,0-0.6,0c-0.1,0-0.2,0-0.2,0c0,0,0.1,0,0.2,0 + c0.2,0,0.4,0,0.6,0c0.5,0,1.2-0.1,2.1-0.2c1.8-0.2,4.2-0.7,6.8-1.6c2.6-0.9,4.7-2.1,6.2-3.1c0.8-0.5,1.3-0.9,1.7-1.2 + c0.2-0.1,0.3-0.2,0.5-0.3C379.6,168.1,379.7,168,379.7,168.1z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M378.1,185.7c0,0-0.1,0.1-0.4,0.3c-0.3,0.2-0.7,0.4-1.2,0.7c-1.1,0.6-2.6,1.3-4.4,1.7 + c-1.8,0.5-3.5,0.6-4.7,0.6c-0.6,0-1.1,0-1.4,0c-0.3,0-0.5-0.1-0.5-0.1c0,0,0.2,0,0.5,0c0.3,0,0.8,0,1.4,0 + c1.2,0,2.9-0.2,4.6-0.7c1.8-0.5,3.3-1.1,4.4-1.7c0.5-0.3,1-0.5,1.3-0.7C377.9,185.8,378.1,185.7,378.1,185.7z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M381.5,183c0,0.1-0.6,0.2-1.4,0.4c-0.8,0.1-1.4,0.2-1.4,0.2s0.6-0.2,1.4-0.4 + C380.8,183,381.4,182.9,381.5,183z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M371.5,203.8c0,0.1-1,0.2-2.3,0.1c-1.3-0.1-2.3-0.4-2.2-0.4c0-0.1,1,0.2,2.3,0.2 + C370.5,203.8,371.5,203.7,371.5,203.8z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M352.6,151.5c0,0.1-0.6,0.4-1.3,0.9c-0.8,0.4-1.4,0.7-1.4,0.7s0.6-0.4,1.3-0.9 + C351.9,151.7,352.5,151.4,352.6,151.5z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M347.6,141c0,0.1-1.4,0.5-2.9,1.6c-1.5,1.1-2.4,2.3-2.5,2.3c0,0,0.2-0.3,0.6-0.8c0.4-0.5,1-1.1,1.8-1.6 + c0.8-0.5,1.5-0.9,2.1-1.1C347.2,141,347.6,140.9,347.6,141z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M356.6,152.6c-0.1,0,0.3-1.4,0.1-3c-0.2-1.7-0.9-2.9-0.8-2.9c0,0,0.2,0.3,0.4,0.8 + c0.2,0.5,0.5,1.3,0.6,2.1c0.1,0.9,0.1,1.6,0,2.2C356.7,152.3,356.6,152.6,356.6,152.6z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M387.5,120c0,0-0.4,0.5-1.1,1.2c-0.7,0.7-1.9,1.7-3.5,2.7c-1.6,1-3.5,2-5.8,3c-2.2,1-4.7,2-7.2,3.2 + c-2.5,1.2-4.8,2.6-6.6,4.2c-1.8,1.6-3.1,3.4-3.9,5.1c-0.8,1.7-1.1,3.1-1.2,4.1c-0.1,1,0,1.6,0,1.6c0,0,0-0.1,0-0.4 + c0-0.3,0-0.7,0-1.2c0.1-1,0.4-2.5,1.1-4.2c0.8-1.7,2.1-3.5,3.9-5.1c1.8-1.6,4.1-3.1,6.7-4.3c2.5-1.2,5-2.2,7.3-3.2 + c2.2-1,4.2-2,5.7-2.9c1.6-1,2.7-1.9,3.5-2.6c0.4-0.3,0.7-0.6,0.9-0.8C387.4,120.1,387.5,120,387.5,120z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M384.8,131.9c0,0,0,0.1-0.1,0.2c-0.1,0.2-0.3,0.4-0.4,0.6c-0.4,0.5-0.9,1.3-1.7,2.2 + c-1.5,1.8-3.7,4.2-6.5,6.4c-2.8,2.2-5.7,3.8-7.8,4.7c-1.1,0.5-1.9,0.8-2.6,1.1c-0.3,0.1-0.5,0.2-0.7,0.2 + c-0.2,0.1-0.3,0.1-0.3,0.1c0,0,0.1,0,0.2-0.1c0.2-0.1,0.4-0.2,0.7-0.3c0.6-0.2,1.5-0.6,2.5-1.1c2.1-1,4.9-2.6,7.7-4.8 + c2.8-2.2,5-4.5,6.5-6.3c0.7-0.9,1.3-1.6,1.7-2.2c0.2-0.2,0.3-0.4,0.4-0.6C384.8,131.9,384.8,131.8,384.8,131.9z"/> + </g> + </g> + <g> + <g> + <path class="st1" d="M343.1,117.8c0,0,1.2,0.5,3,1.6c1.8,1.1,4.1,3,6.1,5.5c2,2.6,3.3,5.2,4,7.2c0.7,2,0.9,3.3,0.9,3.3 + c0,0,0-0.1-0.1-0.2c-0.1-0.2-0.1-0.4-0.2-0.7c-0.1-0.6-0.4-1.4-0.8-2.4c-0.7-2-2-4.6-4-7.2c-2-2.5-4.3-4.4-6-5.5 + c-0.9-0.6-1.6-1-2.1-1.3c-0.2-0.1-0.4-0.2-0.6-0.3C343.2,117.8,343.1,117.8,343.1,117.8z"/> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <path class="st8" d="M292.9,155.4c0.4,5.3-3.1,10-6.6,14c-3.5,4-7.5,8.1-8.2,13.4c-1.4,9.3,7.8,18,5.9,27.2 + c-1,4.9-5.1,8.9-5.8,13.9c-0.7,4.8,1.9,9.6,5.1,13.2c3.2,3.7,6.9,3.1,9.8,7.1c3,4.2,7.8,8.5,12.3,10.9 + c10.2,5.6,22.5-2.5,27.4-4"/> + </g> + </g> + <g> + <g> + <path class="st8" d="M370.3,177.1c4.7-2.1,5.1-18.9-6.7-20.9c-4.7-0.8-8.7-3.1-12.7-5.8c-3.5-2.4-4.6-8.4-7.6-11.4 + c-7.3-7.4-18.8-10.5-28.9-7.8c-10.1,2.7-18.4,11.2-20.9,21.4c-1.7,6.8-0.5,14.9,4.9,19.5c6.3,5.3,15.5,4.1,23.6,2.5 + c8-1.6,17.1-3.3,23.8,1.5c4,2.8,6.4,7.5,8.8,11.7c2.5,4.3,5.6,8.6,10.2,10.3c0,0,3.6,8.4,0.7,14.2s3.4-4.1,3.4-4.1 + S380.4,187.6,370.3,177.1"/> + </g> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st14" d="M310.4,295.7c-0.1-11,0-42,0-41.9c0,0-17.5-2.9-21.1-25.8c-1.8-11.4-1.2-30-0.2-45.3 + c0.9-13.7,10-30.5,23.7-29.1l42.7,10.9c4.2,0.4,7.3,4,7.2,8.2l0,0l-2.6,106L310.4,295.7z"/> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st8" d="M296.4,195.7c-0.1,1.5,1.2,2.9,2.8,3c1.6,0.1,3-1.1,3-2.6c0.1-1.5-1.2-2.9-2.8-3 + C297.8,193,296.4,194.2,296.4,195.7z"/> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st8" d="M293.1,192.4c0.4,0.4,2.6-1.3,5.7-1.2c3.2,0,5.5,1.6,5.8,1.2c0.2-0.2-0.2-0.9-1.2-1.6 + c-1-0.7-2.7-1.4-4.6-1.4c-2,0-3.6,0.7-4.6,1.5C293.3,191.5,292.9,192.2,293.1,192.4z"/> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st8" d="M324.1,197.4c0.4,0.4,2.6-1.3,5.7-1.2c3.2,0,5.5,1.6,5.8,1.2c0.2-0.2-0.2-0.9-1.2-1.6 + c-1-0.7-2.7-1.4-4.6-1.4c-2,0-3.6,0.7-4.6,1.5C324.3,196.5,324,197.2,324.1,197.4z"/> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st8" d="M312.6,216.4c0-0.2-1.9-0.5-5.1-0.9c-0.8-0.1-1.6-0.2-1.7-0.8c-0.2-0.6,0.2-1.5,0.5-2.4 + c0.8-1.9,1.6-4,2.4-6.1c3.3-8.7,5.7-15.9,5.4-16c-0.4-0.1-3.3,6.8-6.7,15.6c-0.8,2.2-1.6,4.2-2.3,6.2 + c-0.3,0.9-0.8,2-0.4,3.2c0.2,0.6,0.8,1,1.3,1.2c0.5,0.2,1,0.2,1.4,0.2C310.6,216.6,312.6,216.6,312.6,216.4z" + /> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st15" d="M310.4,253.8c0,0,15.4,1,30.6-8.1c-0.3,0.1-8.4,15.9-30.3,13.5L310.4,253.8z"/> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <path class="st15" d="M313.5,225.5c-0.4-1.9,1.9-2.6,3.6-3.6c1.7-1,2.6-2.4,4.2-1.2c0.9,0.7,1.5,1.7,1.9,2.7 + c0.3,0.7,0.4,1.5,0.3,2.2c-0.2,0.9-0.7,1.7-1.4,2.3c-0.9,0.9-2.1,1.6-3.4,1.8c-1.3,0.2-2.7-0.1-3.7-0.9 + c-1-0.8-1.6-2.2-1.4-3.5"/> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st8" d="M321.9,218.6c-0.5,0-0.5,3.4-3.5,5.8c-2.9,2.4-6.6,2-6.6,2.5c0,0.2,0.8,0.7,2.4,0.7 + c1.5,0.1,3.7-0.4,5.5-1.9c1.8-1.5,2.6-3.5,2.7-4.9C322.5,219.4,322.2,218.6,321.9,218.6z"/> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st8" d="M323.7,190.4c0.3,0.9,3.5,0.5,7.2,0.9c3.7,0.4,6.7,1.5,7.2,0.7c0.2-0.4-0.3-1.2-1.5-2 + c-1.2-0.8-3.1-1.6-5.3-1.9c-2.2-0.2-4.3,0.1-5.6,0.6C324.2,189.3,323.5,189.9,323.7,190.4z"/> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <g> + <path class="st8" d="M293.6,181.5c0.6,0.7,2.7,0,5.3-0.1c2.6-0.1,4.8,0.5,5.3-0.3c0.2-0.4-0.1-1.1-1.1-1.8 + c-1-0.7-2.5-1.2-4.3-1.2c-1.8,0.1-3.4,0.7-4.3,1.4C293.6,180.4,293.3,181.1,293.6,181.5z"/> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + </g> + <g> + <g> + <path class="st8" d="M365.1,241c-6.3,1.3-6.9-1.9-11.5-6.3c-4.7-4.4-7.1-11.1-6.3-17.4c0.7-5.6,3.7-11.3,1.8-16.6 + c-2.6-7-12.4-9.2-15-16.2c-1.5-4.1-0.2-8.8-1.9-12.8c-1.6-3.8-5.6-5.9-9.4-7.3c-3.8-1.4-8-2.4-11.2-4.9 + c-3.2-2.5-5.2-7.2-3.2-10.8c17.1,2,33.9,6.1,50,12.1c3.7,1.4,7.7,3.1,9.9,6.4c2.3,3.5,2.2,8,2,12.3 + c-1,20.5-1.9,41.1-2.9,61.6"/> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st16" d="M379.7,233.3c0,0,0.1-0.1,0.3-0.3c0.1-0.2,0.4-0.5,0.6-0.9c0.5-0.8,1.1-2.2,1.5-4 + c0.4-1.8,0.4-4.2-0.4-6.8c-0.7-2.6-2.5-5.3-5.3-7.2c-2.7-1.9-6.2-3.2-8.5-6.3c-1.1-1.5-1.6-3.4-1.2-5.4c0.3-2,1.2-3.9,2-5.9 + c1.7-4.1,1.8-9.2-0.3-13.7c-1-2.2-2.6-4.3-4.6-5.8c-2-1.5-4.5-2.3-7-2.9c-2.5-0.6-4.9-0.9-7.2-1.6c-2.3-0.7-4.5-1.7-6.1-3.3 + c-1.6-1.6-2.3-3.8-2.6-6c-0.3-2.2-0.5-4.5-1.1-6.6c-1.1-4.3-3.3-8.1-6.2-10.8c-2.9-2.7-6.4-4.3-9.7-4.8 + c-3.3-0.5-6.5,0.1-8.8,1.3c-2.4,1.2-4,2.9-5.1,4.4c-1.1,1.5-1.6,2.9-1.8,3.9c-0.2,1-0.2,1.5-0.2,1.5c0.1,0.1,0.2-2.1,2.3-5.1 + c1.1-1.4,2.7-3,5-4.2c2.3-1.1,5.3-1.7,8.5-1.1c3.2,0.5,6.5,2.1,9.2,4.7c2.7,2.6,4.8,6.3,5.9,10.5c0.6,2.1,0.7,4.3,1,6.6 + c0.3,2.3,1.1,4.8,2.9,6.5c1.8,1.8,4.1,2.9,6.5,3.6c2.4,0.7,4.9,1.1,7.3,1.6c2.4,0.5,4.8,1.3,6.6,2.7c1.9,1.4,3.4,3.3,4.3,5.4 + c1.9,4.2,2,9,0.3,12.9c-0.8,2-1.7,4-2,6.1c-0.4,2.1,0.2,4.4,1.4,6c2.5,3.3,6.1,4.6,8.8,6.4c2.7,1.8,4.4,4.3,5.2,6.7 + c0.8,2.4,0.8,4.7,0.5,6.5C381.1,231.7,379.6,233.3,379.7,233.3z"/> + </g> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st8" d="M349.9,210.6c-5.2,11.9-6.1,25.6-2.7,38.1c1,3.7,2.5,7.6,1.6,11.4c-1,4.1-4.4,7.1-6.9,10.4 + c-4.3,5.8-6,13.5-4.5,20.6c1.5,7.1,6.1,13.4,12.4,17c0.7-3.8,4.2-6.3,7.6-8c3.5-1.6,7.3-2.8,9.9-5.6c2.6-2.8,3.4-7.8,0.3-10.1 + c8.8-2.3,13.8-12.8,11.9-21.7c-1.9-8.9-9.1-15.9-17.3-19.8"/> + </g> + <g> + <path class="st8" d="M359.3,299.4c-1.6,0.9-3.1,1.6-3.3,3.4c-0.2,2.1,1.8,5.8,2.5,7.8c1.4,3.9,0.3,8.5-2.6,11.4 + c-3,2.9-7.6,3.8-11.5,2.3c2.8,0.2,5.2-2.5,5.5-5.3c0.3-2.8-1.1-5.5-2.8-7.8c-1.7-2.3-3.7-4.3-5.1-6.7 + c-2.9-5-7.2-18.5-3.9-26.1"/> + </g> + </g> + <g> + <g> + <path class="st16" d="M367.3,284.9c0,0,0.2-0.2,0.5-0.5c0.4-0.3,0.9-0.7,1.6-1.3c1.3-1.1,3.2-2.8,5.1-5.3 + c1.9-2.5,3.9-5.7,4.9-9.7c1-4,1.1-8.7-0.6-13.1c-0.9-2.2-2.1-4.2-3.6-5.8c-1.5-1.7-3.1-3.2-4.6-4.6c-1.5-1.4-2.9-2.8-4.1-4.3 + c-1.2-1.4-2.1-3-2.7-4.4c-1.3-2.9-1.3-5.6-0.9-7.3c0.2-0.9,0.5-1.5,0.7-1.9c0.2-0.4,0.4-0.6,0.4-0.6c0.1,0-0.5,0.8-0.9,2.5 + c-0.4,1.7-0.3,4.3,1,7.2c0.6,1.4,1.5,2.9,2.7,4.3c1.2,1.4,2.6,2.8,4.1,4.2c1.5,1.4,3.1,2.9,4.6,4.6c1.5,1.7,2.8,3.7,3.7,6 + c1.8,4.6,1.7,9.4,0.6,13.4c-1.1,4.1-3.1,7.4-5,9.8c-2,2.5-3.9,4.2-5.3,5.2c-0.7,0.5-1.2,0.9-1.6,1.2 + C367.6,284.7,367.3,284.9,367.3,284.9z"/> + </g> + </g> + </g> + </g> + </g> +</g> +<g id="Plant"> + <g> + <g> + <g> + <path class="st19" d="M79.9,404.3c2.5,3.2,7,1.8,8.9-0.4c2-2.2,2.7-5.1,3.3-8c1.4-6.5,2.9-13.3,1.1-19.7 + c-0.5-1.9-1.4-3.8-2.8-5.2c-1.5-1.4-3.6-2.1-5.5-1.5c-2.2,0.7-3.5,3.1-4.4,5.2c-2.6,6.4-3.8,13.4-3.4,20.3 + C77.4,398.4,78,401.7,79.9,404.3"/> + </g> + </g> + <g> + <g> + <path class="st20" d="M79.9,404.3c2.5,3.2,7,1.8,8.9-0.4c2-2.2,2.7-5.1,3.3-8c1.4-6.5,2.9-13.3,1.1-19.7 + c-0.5-1.9-1.4-3.8-2.8-5.2c-1.5-1.4-3.6-2.1-5.5-1.5c-2.2,0.7-3.5,3.1-4.4,5.2c-2.6,6.4-3.8,13.4-3.4,20.3 + C77.4,398.4,78,401.7,79.9,404.3"/> + </g> + </g> + <g> + <g> + <path class="st9" d="M89.7,420.5c3.7-2.2,8.1-2.7,12.4-2.3c2.3,0.2,4.7,0.8,6.3,2.4c1.6,1.6,2.1,4.6,0.5,6.1 + c-1,0.9-2.5,1.2-3.8,1.2c-3.3,0.2-7-0.2-9.5,2c-1.4,1.2-2.3,3.2-4.1,3.8c-1.7,0.7-3.8-0.3-4.8-1.8c-1-1.5-1.2-3.5-0.9-5.3 + C85.8,426.7,86,422.7,89.7,420.5z"/> + </g> + </g> + <g> + <g> + <path class="st9" d="M73.9,409.4c2.3-3.1,2.5-7.5,1.2-11.2c-1.4-3.7-4.1-6.7-7.2-9.1c-3.6-2.8-7.8-5-12.2-6.2 + c-1.7-0.5-3.6-0.9-5.3-0.6c-1.8,0.3-3.5,1.3-4.3,3c-1.1,2.4,0.3,5.2,1.7,7.5c2.5,4,5.4,7.8,8.5,11.3c2.5,2.8,5.3,5.6,9,6.7 + c3.6,1.1,7.3,0.7,9-1.8"/> + </g> + </g> + <g> + <g> + <g> + <path class="st8" d="M82.9,454.3c0,0,0.1-0.5,0.1-1.5c0-1.1,0.1-2.5,0.1-4.1c0.1-1.7,0.2-3.8,0.5-6.1c0.3-2.3,0.9-4.7,1.7-7.3 + c0.8-2.5,1.9-4.8,3.2-6.7c1.3-1.9,2.9-3.3,4.4-4.1c1.5-0.9,2.8-1.3,3.8-1.4c1-0.2,1.5-0.3,1.5-0.3c0,0-0.5,0-1.5,0.1 + c-1,0.1-2.4,0.5-4,1.3c-1.6,0.8-3.2,2.2-4.6,4.2c-1.4,1.9-2.5,4.3-3.4,6.8c-0.8,2.6-1.4,5.1-1.7,7.4c-0.3,2.3-0.4,4.4-0.4,6.2 + c0,1.8,0,3.2,0.1,4.1C82.8,453.7,82.9,454.3,82.9,454.3z"/> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st8" d="M83,451.1c0,0,0-0.2,0-0.7c0-0.5-0.1-1.2-0.1-2c-0.1-1.7-0.3-4.2-0.4-7.3c-0.2-6.2-0.2-14.8,0.2-24.3 + c0.4-9.5,1.3-18,2.2-24.2c0.2-1.5,0.4-2.9,0.6-4.1c0.2-1.2,0.4-2.3,0.5-3.1c0.1-0.8,0.3-1.5,0.3-2c0.1-0.5,0.1-0.7,0.1-0.7 + c0,0-0.1,0.2-0.2,0.7c-0.1,0.5-0.3,1.2-0.5,2c-0.2,0.8-0.4,1.9-0.6,3.1c-0.2,1.2-0.5,2.6-0.7,4.1c-1,6.1-1.9,14.7-2.3,24.2 + c-0.4,9.5-0.4,18.1,0,24.3c0.2,3.1,0.4,5.6,0.6,7.3c0.1,0.8,0.2,1.5,0.2,2C83,450.9,83,451.1,83,451.1z"/> + </g> + </g> + </g> + <g> + <g> + <g> + <path class="st8" d="M82,434.6c0,0,0-0.7-0.1-2.1c-0.2-1.3-0.5-3.3-1-5.6c-0.5-2.3-1.3-5.1-2.4-8.1c-1-3-2.4-6.3-4.1-9.5 + c-3.3-6.6-7.5-11.9-11.1-15.1c-0.8-0.9-1.8-1.5-2.5-2.1c-0.4-0.3-0.7-0.6-1.1-0.8c-0.3-0.2-0.7-0.4-1-0.6 + c-1.2-0.7-1.8-1.1-1.8-1c-0.1,0.1,2.6,1.5,6.1,4.8c3.5,3.3,7.6,8.5,10.9,15.1c1.7,3.2,3,6.5,4.1,9.4c1.1,3,1.9,5.7,2.5,8 + c0.6,2.3,0.9,4.2,1.2,5.5C81.8,433.8,82,434.6,82,434.6z"/> + </g> + </g> + </g> + </g> +</g> +<g id="Confetti"> + <g> + <g> + <path class="st19" d="M234.6,205.8c-1.8-6.5-10.3-5.9-10.3-5.9l0.2,4.5c4.9-0.8,8,4.9,8,4.9L234.6,205.8z"/> + </g> + </g> + <g> + <g> + <path class="st19" d="M151,129.7c-4.6,0.5-5.1,6.2-5.1,6.2l3.1,0.4c0-3.4,4.2-4.8,4.2-4.8L151,129.7z"/> + </g> + </g> + <g> + <g> + <path class="st19" d="M193.7,68.8c2.8,7.1,12.3,5.5,12.3,5.5l-0.8-5.1c-5.4,1.5-9.5-4.6-9.5-4.6L193.7,68.8z"/> + </g> + </g> + <g> + <g> + <path class="st19" d="M87.1,189.1c-4.6,0.5-5.1,6.2-5.1,6.2l3.1,0.4c0-3.4,4.2-4.8,4.2-4.8L87.1,189.1z"/> + </g> + </g> + <g> + <g> + <path class="st19" d="M106,91.5c0.7-4.6-4.8-6.5-4.8-6.5l-1.1,2.9c3.3,0.8,3.6,5.2,3.6,5.2L106,91.5z"/> + </g> + </g> + <g> + <g> + <path class="st19" d="M27.6,161.5c-0.8,7.2,8.7,8.9,8.7,8.9l1.7-4.7c-5.7-0.5-6.5-7.2-6.5-7.2L27.6,161.5z"/> + </g> + </g> + <g> + <g> + <path class="st19" d="M252.8,127c4.6,0.3,6.1-5.3,6.1-5.3l-3-0.9c-0.5,3.3-4.9,4-4.9,4L252.8,127z"/> + </g> + </g> +</g> +</svg> diff --git a/src-migrate/modules/page-content/index.tsx b/src-migrate/modules/page-content/index.tsx index edecb855..3423ca8b 100644 --- a/src-migrate/modules/page-content/index.tsx +++ b/src-migrate/modules/page-content/index.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useQuery } from 'react-query'; import { PageContentProps } from '~/types/pageContent'; import { getPageContent } from '~/services/pageContent'; @@ -8,18 +8,38 @@ type Props = { }; const PageContent = ({ path }: Props) => { + const [localData, setData] = useState<PageContentProps>(); + const [shouldFetch, setShouldFetch] = useState(false); + + useEffect(() => { + const localData = localStorage.getItem(`page-content:${path}`); + if (localData) { + setData(JSON.parse(localData)); + }else{ + setShouldFetch(true); + } + },[]) + const { data, isLoading } = useQuery<PageContentProps>( `page-content:${path}`, - async () => await getPageContent({ path }) + async () => await getPageContent({ path }), { + enabled: shouldFetch, + onSuccess: (data) => { + if (data) { + localStorage.setItem(`page-content:${path}`, JSON.stringify(data)); + setData(data); + } + }, + } ); const parsedContent = useMemo<string>(() => { - if (!data) return ''; - return data.content.replaceAll( + if (!localData) return ''; + return localData.content.replaceAll( 'src="/web/image', `src="${process.env.NEXT_PUBLIC_ODOO_API_HOST}/web/image` ); - }, [data]); + }, [localData]); if (isLoading) return <PageContentSkeleton />; return <div dangerouslySetInnerHTML={{ __html: parsedContent || '' }}></div>; diff --git a/src-migrate/modules/product-detail/components/AddToCart.tsx b/src-migrate/modules/product-detail/components/AddToCart.tsx index a5284637..280e4a7a 100644 --- a/src-migrate/modules/product-detail/components/AddToCart.tsx +++ b/src-migrate/modules/product-detail/components/AddToCart.tsx @@ -1,51 +1,55 @@ -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; import style from '../styles/price-action.module.css'; -import { Button, Link, useToast } from '@chakra-ui/react' -import product from 'next-seo/lib/jsonld/product' -import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' -import Image from '~/components/ui/image' -import { getAuth } from '~/libs/auth' -import { upsertUserCart } from '~/services/cart' +import { Button, Link, useToast } from '@chakra-ui/react'; +import product from 'next-seo/lib/jsonld/product'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import Image from '~/components/ui/image'; +import { getAuth } from '~/libs/auth'; +import { upsertUserCart } from '~/services/cart'; import LazyLoad from 'react-lazy-load'; import ProductSimilar from '../../../../src/lib/product/components/ProductSimilar'; import { IProductDetail } from '~/types/product'; import ImageNext from 'next/image'; -import { useProductCartContext } from '@/contexts/ProductCartContext' -import { createSlug } from '~/libs/slug' -import formatCurrency from '~/libs/formatCurrency' +import { useProductCartContext } from '@/contexts/ProductCartContext'; +import { createSlug } from '~/libs/slug'; +import formatCurrency from '~/libs/formatCurrency'; import { useProductDetail } from '../stores/useProductDetail'; type Props = { - variantId: number | null, + variantId: number | null; quantity?: number; source?: 'buy' | 'add_to_cart'; - products : IProductDetail -} + products: IProductDetail; +}; -type Status = 'idle' | 'loading' | 'success' +type Status = 'idle' | 'loading' | 'success'; const AddToCart = ({ variantId, quantity = 1, source = 'add_to_cart', - products + products, }: Props) => { - const auth = getAuth() - const router = useRouter() + let auth = getAuth(); + const router = useRouter(); const toast = useToast({ position: 'top', - isClosable: true - }) + isClosable: true, + }); - const { - askAdminUrl, - } = useProductDetail(); + const { askAdminUrl } = useProductDetail(); const [product, setProducts] = useState(products); - const [status, setStatus] = useState<Status>('idle') - const { productCart, setRefreshCart, setProductCart, refreshCart, isLoading, setIsloading } = - useProductCartContext() + const [status, setStatus] = useState<Status>('idle'); + const { + productCart, + setRefreshCart, + setProductCart, + refreshCart, + isLoading, + setIsloading, + } = useProductCartContext(); const productSimilarQuery = [ product?.name, @@ -55,32 +59,48 @@ const AddToCart = ({ const [addCartAlert, setAddCartAlert] = useState(false); const handleButton = async () => { - if (typeof auth !== 'object') { - const currentUrl = encodeURIComponent(router.asPath) - router.push(`/login?next=${currentUrl}`) - return; + let isLoggedIn = typeof auth === 'object'; + + if (!isLoggedIn) { + const currentUrl = encodeURIComponent(router.asPath); + await router.push(`/login?next=${currentUrl}`); + + // Tunggu login berhasil, misalnya dengan memantau perubahan status auth. + const authCheckInterval = setInterval(() => { + const newAuth = getAuth(); + if (typeof newAuth === 'object') { + isLoggedIn = true; + auth = newAuth; // Update nilai auth setelah login + clearInterval(authCheckInterval); + } + }, 500); // Periksa status login setiap 500ms + + await new Promise((resolve) => { + const checkLogin = setInterval(() => { + if (isLoggedIn) { + clearInterval(checkLogin); + resolve(null); + } + }, 500); + }); } - - if ( - !variantId || - isNaN(quantity) || - typeof auth !== 'object' - ) return; - if (status === 'success') return - setStatus('loading') + + if (!variantId || isNaN(quantity) || typeof auth !== 'object') return; + if (status === 'success') return; + setStatus('loading'); await upsertUserCart({ userId: auth.id, - type: 'product', - id: variantId, - qty: quantity, - selected: true, - source: source, - qtyAppend: true - }) - setStatus('idle') + type: 'product', + id: variantId, + qty: quantity, + selected: true, + source: source, + qtyAppend: true, + }); + setStatus('idle'); setRefreshCart(true); setAddCartAlert(true); - + toast({ title: 'Tambah ke keranjang', description: 'Berhasil menambahkan barang ke keranjang belanja', @@ -88,120 +108,130 @@ const AddToCart = ({ duration: 3000, isClosable: true, position: 'top', - }) - + }); + if (source === 'buy') { - router.push('/shop/checkout?source=buy') + router.push('/shop/checkout?source=buy'); } - } + }; useEffect(() => { - if (status === 'success') setTimeout(() => { setStatus('idle') }, 3000) - }, [status]) + if (status === 'success') + setTimeout(() => { + setStatus('idle'); + }, 3000); + }, [status]); const btnConfig = { - 'add_to_cart': { + add_to_cart: { colorScheme: 'yellow', - text: 'Keranjang' + text: 'Keranjang', }, - 'buy': { + buy: { colorScheme: 'red', - text: 'Beli' - } - } + text: 'Beli', + }, + }; return ( <div className='w-full'> - <Button onClick={handleButton} colorScheme={btnConfig[source].colorScheme} className='w-full'> + <Button + onClick={handleButton} + colorScheme={btnConfig[source].colorScheme} + className='w-full' + > {btnConfig[source].text} </Button> <BottomPopup - className='!container' - title='Berhasil Ditambahkan' - active={addCartAlert} - close={() => { - setAddCartAlert(false); - }} - > - <div className='flex mt-4'> - <div className='w-[10%]'> - <ImageNext - src={product.image} - alt={product.name} - className='h-32 object-contain object-center w-full border border-gray_r-4' - width={80} - height={80} - /> - </div> - <div className='ml-3 flex flex-1 items-start font-medium justify-center flex-col gap-y-1'> - {!!product.manufacture.name ? ( - <Link - href={createSlug('/shop/brands/', product.manufacture.name, product.manufacture.id.toString())} - className=' hover:underline' - color={"red"} - > - {product.manufacture.name} - </Link> - ) : '-'} - <p className='text-ellipsis overflow-hidden'> - {product.name} - </p> - <p> - {product.code} - </p> - {!!product.lowest_price && product.lowest_price.price > 0 && ( + className='!container' + title='Berhasil Ditambahkan' + active={addCartAlert} + close={() => { + setAddCartAlert(false); + }} + > + <div className='flex mt-4'> + <div className='w-[10%]'> + <ImageNext + src={product.image} + alt={product.name} + className='h-32 object-contain object-center w-full border border-gray_r-4' + width={80} + height={80} + /> + </div> + <div className='ml-3 flex flex-1 items-start font-medium justify-center flex-col gap-y-1'> + {!!product.manufacture.name ? ( + <Link + href={createSlug( + '/shop/brands/', + product.manufacture.name, + product.manufacture.id.toString() + )} + className=' hover:underline' + color={'red'} + > + {product.manufacture.name} + </Link> + ) : ( + '-' + )} + <p className='text-ellipsis overflow-hidden'>{product.name}</p> + <p>{product.code}</p> + {!!product.lowest_price && product.lowest_price.price > 0 && ( + <> + <div className='flex items-end gap-x-2'> + {product.lowest_price.discount_percentage > 0 && ( <> - <div className='flex items-end gap-x-2'> - {product.lowest_price.discount_percentage > 0 && ( - <> - <div className='badge-solid-red'> - {Math.floor(product.lowest_price.discount_percentage)}% - </div> - <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'> - Rp {formatCurrency(product.lowest_price.price || 0)} - </div> - </> - )} - <div className='text-danger-500 font-semibold'> - Rp {formatCurrency(product.lowest_price.price_discount || 0)} - </div> + <div className='badge-solid-red'> + {Math.floor(product.lowest_price.discount_percentage)}% + </div> + <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'> + Rp {formatCurrency(product.lowest_price.price || 0)} </div> </> )} + <div className='text-danger-500 font-semibold'> + Rp{' '} + {formatCurrency(product.lowest_price.price_discount || 0)} + </div> + </div> + </> + )} - {!!product.lowest_price && product.lowest_price.price === 0 && ( - <span> - Hubungi kami untuk dapatkan harga terbaik,{' '} - <Link - href={askAdminUrl} - target='_blank' - className='font-medium underline' - color={'red'} - > - klik disini - </Link> - </span> - )} - </div> - <div className='ml-3 flex items-center font-normal'> - <Link - href='/shop/cart' - className='flex-1 py-2 text-gray_r-12 btn-yellow' - > - Lihat Keranjang - </Link> - </div> + {!!product.lowest_price && product.lowest_price.price === 0 && ( + <span> + Hubungi kami untuk dapatkan harga terbaik,{' '} + <Link + href={askAdminUrl} + target='_blank' + className='font-medium underline' + color={'red'} + > + klik disini + </Link> + </span> + )} + </div> + <div className='ml-3 flex items-center font-normal'> + <Link + href='/shop/cart' + className='flex-1 py-2 text-gray_r-12 btn-yellow' + > + Lihat Keranjang + </Link> </div> - <div className='mt-8 mb-4'> - <div className='text-h-sm font-semibold mb-6'> - Kamu Mungkin Juga Suka - </div> - <LazyLoad> - <ProductSimilar query={productSimilarQuery} /> - </LazyLoad> + </div> + <div className='mt-8 mb-4'> + <div className='text-h-sm font-semibold mb-6'> + Kamu Mungkin Juga Suka </div> - </BottomPopup> + <LazyLoad> + <ProductSimilar query={productSimilarQuery} /> + </LazyLoad> + </div> + </BottomPopup> </div> - ) -} + ); +}; -export default AddToCart
\ No newline at end of file +export default AddToCart; diff --git a/src-migrate/modules/promo/components/FlashSaleNonDisplay.tsx b/src-migrate/modules/promo/components/FlashSaleNonDisplay.tsx new file mode 100644 index 00000000..5685b83a --- /dev/null +++ b/src-migrate/modules/promo/components/FlashSaleNonDisplay.tsx @@ -0,0 +1,17 @@ +import dynamic from 'next/dynamic'; +import React from 'react'; +import { FlashSaleSkeleton } from '@/lib/flashSale/skeleton/FlashSaleSkeleton'; +const FlashSaleNonDisplay = dynamic( + () => import('@/lib/flashSale/components/FlashSaleNonDisplay'), + { + loading: () => <FlashSaleSkeleton />, + } +); +const FlashSalePromo = () => { + return ( + <> + <FlashSaleNonDisplay /> + </> + ); +}; +export default FlashSalePromo; diff --git a/src-migrate/modules/promo/components/PromoList.tsx b/src-migrate/modules/promo/components/PromoList.tsx index d59d1867..9f808718 100644 --- a/src-migrate/modules/promo/components/PromoList.tsx +++ b/src-migrate/modules/promo/components/PromoList.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; -import { Button, Skeleton } from '@chakra-ui/react' -import clsxm from "~/libs/clsxm" +import { Button, Skeleton } from '@chakra-ui/react'; +import clsxm from '~/libs/clsxm'; import ProductPromoCard from '../../product-promo/components/Card'; import { fetchPromoItemsSolr } from '../../../../src/api/promoApi'; import { Swiper, SwiperSlide } from 'swiper/react'; @@ -8,7 +8,7 @@ import SwiperCore, { Navigation, Pagination } from 'swiper'; import useDevice from '@/core/hooks/useDevice'; import LogoSpinner from '../../../../src/core/components/elements/Spinner/LogoSpinner'; import usePromoStore from './promoStore'; -import Link from "next/link" +import Link from 'next/link'; import { IPromotion } from '~/types/promotion'; interface PromoListProps { selectedPromo: string; // Tipe selectedPromo ditetapkan sebagai string @@ -32,11 +32,11 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => { const swiperBanner = { modules: [Navigation], - className: 'h-[400px] w-full', + className: 'h-full w-full', slidesPerView: isMobile ? 1.1 : 3.25, spaceBetween: 10, - navigation:isMobile? true : false, - allowTouchMove:isMobile? false : true, + navigation: isMobile ? true : false, + allowTouchMove: isMobile ? false : true, }; useEffect(() => { @@ -56,7 +56,7 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => { const fetchPromotions = async () => { setIsLoading(true); try { - const items = await fetchPromoItemsSolr(`type_value_s:${slug}`, 0, 10); + const items = await fetchPromoItemsSolr(`type_value_s:${slug}`, 0, 10); setPromoItems(items); const promoDataPromises = items?.map(async (item) => { @@ -69,9 +69,11 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => { }); const promoDataArray = await Promise.all(promoDataPromises); - const mergedPromoData = promoDataArray?.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + const mergedPromoData = promoDataArray?.reduce( + (accumulator, currentValue) => accumulator.concat(currentValue), + [] + ); setPromoData(mergedPromoData); - } catch (error) { console.error('Error fetching promo items:', error); } finally { @@ -92,44 +94,49 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => { <div className='flex justify-between items-center'> <h1 className='text-h-sm md:text-h-lg font-semibold py-4'>{title}</h1> <div> - <Link href={`/shop/promo/${slug}`} className='!text-red-500 font-semibold'> + <Link + href={`/shop/promo/${slug}`} + className='!text-red-500 font-semibold' + > Lihat Semua </Link> </div> </div> {isLoading ? ( - <div className="loading-spinner flex justify-center"> + <div className='loading-spinner flex justify-center'> <LogoSpinner width={48} height={48} /> </div> ) : ( <Skeleton - isLoaded={!isLoading} - className={clsxm( - "flex gap-x-4 overflow-x-auto px-4 md:px-0", { - "min-h-[340px]": promoData[0] && promoData?.length > 0 - })} - > - {isDesktop && ( - <Swiper {...swiperBanner}> - {promoData?.map((promotion: IPromotion) => ( - <SwiperSlide key={promotion.id}> - <div className="min-w-36 max-w-[400px] mb-[20px] sm:w-full md:w-full lg:w-full xl:w-full"> - <ProductPromoCard product={promoItems} promotion={promotion} /> - </div> - </SwiperSlide> - ))} - </Swiper> - )} - {isMobile && (promoData?.map((promotion: IPromotion) => ( - <div key={promotion.id} className="min-w-[400px] max-w-[400px]"> - <ProductPromoCard product={promoItems} promotion={promotion} /> - </div> - )))} - - </Skeleton> + isLoaded={!isLoading} + className={clsxm('flex gap-x-4 overflow-x-auto px-4 md:px-0', { + 'min-h-[340px]': promoData[0] && promoData?.length > 0, + })} + > + {isDesktop && ( + <Swiper {...swiperBanner}> + {promoData?.map((promotion: IPromotion) => ( + <SwiperSlide key={promotion.id}> + <div className='min-w-36 max-w-[400px] mb-[20px] sm:w-full md:w-full lg:w-full xl:w-full'> + <ProductPromoCard + product={promoItems} + promotion={promotion} + /> + </div> + </SwiperSlide> + ))} + </Swiper> + )} + {isMobile && + promoData?.map((promotion: IPromotion) => ( + <div key={promotion.id} className='min-w-[400px] max-w-[400px]'> + <ProductPromoCard product={promoItems} promotion={promotion} /> + </div> + ))} + </Skeleton> )} </div> ); }; -export default PromoList;
\ No newline at end of file +export default PromoList; diff --git a/src-migrate/pages/shop/promo/index.tsx b/src-migrate/pages/shop/promo/index.tsx index febe31a4..689c2537 100644 --- a/src-migrate/pages/shop/promo/index.tsx +++ b/src-migrate/pages/shop/promo/index.tsx @@ -1,13 +1,14 @@ -import dynamic from 'next/dynamic' -import React, { useState } from 'react' -import { LazyLoadComponent } from 'react-lazy-load-image-component' -import Hero from '~/modules/promo/components/Hero' -import PromotionProgram from '~/modules/promo/components/PromotinProgram' -import Voucher from '~/modules/promo/components/Voucher' -import FlashSale from '../../../modules/promo/components/FlashSale' -const PromoList = dynamic(() => import('../../../modules/promo/components/PromoList')); - - +import dynamic from 'next/dynamic'; +import React, { useState } from 'react'; +import { LazyLoadComponent } from 'react-lazy-load-image-component'; +import Hero from '~/modules/promo/components/Hero'; +import PromotionProgram from '~/modules/promo/components/PromotinProgram'; +import Voucher from '~/modules/promo/components/Voucher'; +import FlashSale from '../../../modules/promo/components/FlashSale'; +import FlashSaleNonDisplay from '../../../modules/promo/components/FlashSaleNonDisplay'; +const PromoList = dynamic( + () => import('../../../modules/promo/components/PromoList') +); const PromoPage = () => { const [selectedPromo, setSelectedPromo] = useState('Bundling'); @@ -17,22 +18,26 @@ const PromoPage = () => { <Hero /> </LazyLoadComponent> <LazyLoadComponent> - <PromotionProgram - selectedPromo={selectedPromo} - onSelectPromo={setSelectedPromo} - /> + <PromotionProgram + selectedPromo={selectedPromo} + onSelectPromo={setSelectedPromo} + /> <PromoList selectedPromo={selectedPromo} /> </LazyLoadComponent> - + <LazyLoadComponent> <FlashSale /> </LazyLoadComponent> <h1 className='h-1'></h1> <LazyLoadComponent> + <FlashSaleNonDisplay /> + </LazyLoadComponent> + <h1 className='h-1'></h1> + <LazyLoadComponent> <Voucher /> </LazyLoadComponent> </> - ) -} + ); +}; -export default PromoPage
\ No newline at end of file +export default PromoPage; diff --git a/src/lib/address/api/cityApi.js b/src/lib/address/api/cityApi.js index 7873435b..0b0201e6 100644 --- a/src/lib/address/api/cityApi.js +++ b/src/lib/address/api/cityApi.js @@ -1,7 +1,7 @@ import odooApi from '@/core/api/odooApi' -const cityApi = async () => { - const dataCities = await odooApi('GET', '/api/v1/city') +const cityApi = async ({stateId}) => { + const dataCities = await odooApi('GET', '/api/v1/city?state_id='+stateId) return dataCities } diff --git a/src/lib/address/api/stateApi.js b/src/lib/address/api/stateApi.js new file mode 100644 index 00000000..cea49e7e --- /dev/null +++ b/src/lib/address/api/stateApi.js @@ -0,0 +1,8 @@ +import odooApi from '@/core/api/odooApi' + +const stateApi = async () => { + const dataState = await odooApi('GET', '/api/v1/state') + return dataState +} + +export default stateApi
\ No newline at end of file diff --git a/src/lib/address/components/CreateAddress.jsx b/src/lib/address/components/CreateAddress.jsx index e315affe..9d70e8fc 100644 --- a/src/lib/address/components/CreateAddress.jsx +++ b/src/lib/address/components/CreateAddress.jsx @@ -12,6 +12,7 @@ import { toast } from 'react-hot-toast'; import { yupResolver } from '@hookform/resolvers/yup'; import Menu from '@/lib/auth/components/Menu'; import useAddresses from '../hooks/useAddresses'; +import stateApi from '../api/stateApi'; const CreateAddress = () => { const auth = useAuth(); @@ -28,23 +29,40 @@ const CreateAddress = () => { defaultValues, }); const { addresses = [] } = useAddresses(); // Ensure addresses is an array + const [states, setState] = useState([]); const [cities, setCities] = useState([]); const [districts, setDistricts] = useState([]); const [subDistricts, setSubDistricts] = useState([]); const [filteredTypes, setFilteredTypes] = useState(types); // State to manage filtered types useEffect(() => { - const loadCities = async () => { - let dataCities = await cityApi(); - dataCities = dataCities.map((city) => ({ - value: city.id, - label: city.name, + const loadState = async () => { + let dataState = await stateApi(); + dataState = dataState.map((state) => ({ + value: state.id, + label: state.name, })); - setCities(dataCities); + setState(dataState); }; - loadCities(); + loadState(); }, []); + const watchState = watch('state'); + useEffect(() => { + setValue('city', ''); + if (watchState) { + const loadCities = async () => { + let dataCities = await cityApi({stateId: watchState}); + dataCities = dataCities.map((city) => ({ + value: city.id, + label: city.name, + })); + setCities(dataCities); + }; + loadCities(); + } + }, [watchState, setValue]); + useEffect(() => { if (addresses) { let hasContactAddress = false; @@ -100,6 +118,7 @@ const CreateAddress = () => { const onSubmitHandler = async (values) => { const data = { ...values, + state_id: values.state, city_id: values.city, district_id: values.district, sub_district_id: values.subDistrict, @@ -205,12 +224,26 @@ const CreateAddress = () => { </div> <div> + <label className='form-label mb-2'>Provinsi</label> + <Controller + name='state' + control={control} + render={(props) => ( + <HookFormSelect {...props} options={states} /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.state?.message} + </div> + </div> + + <div> <label className='form-label mb-2'>Kota</label> <Controller name='city' control={control} render={(props) => ( - <HookFormSelect {...props} options={cities} /> + <HookFormSelect {...props} options={cities} disabled={!watchState}/> )} /> <div className='text-caption-2 text-danger-500 mt-1'> @@ -270,6 +303,7 @@ const validationSchema = Yup.object().shape({ mobile: Yup.string().required('Harus di-isi'), street: Yup.string().required('Harus di-isi'), zip: Yup.string().required('Harus di-isi'), + state: Yup.string().required('Harus di-pilih'), city: Yup.string().required('Harus di-pilih'), district: Yup.string().required('Harus di-pilih'), }); @@ -280,6 +314,7 @@ const defaultValues = { email: '', mobile: '', street: '', + state: '', city: '', district: '', subDistrict: '', diff --git a/src/lib/address/components/EditAddress.jsx b/src/lib/address/components/EditAddress.jsx index 182c8a31..23cf72a9 100644 --- a/src/lib/address/components/EditAddress.jsx +++ b/src/lib/address/components/EditAddress.jsx @@ -13,6 +13,7 @@ import { toast } from 'react-hot-toast'; import Menu from '@/lib/auth/components/Menu'; import useAuth from '@/core/hooks/useAuth'; import odooApi from '@/core/api/odooApi'; +import stateApi from '../api/stateApi'; const EditAddress = ({ id, defaultValues }) => { const auth = useAuth(); @@ -29,9 +30,11 @@ const EditAddress = ({ id, defaultValues }) => { resolver: yupResolver(validationSchema), defaultValues, }); + + const [states, setStates] = useState([]); const [cities, setCities] = useState([]); const [districts, setDistricts] = useState([]); - const [subDistricts, setSubDistricts] = useState([]); + const [subDistricts, setSubDistricts] = useState([]); useEffect(() => { const loadProfile = async () => { @@ -48,16 +51,38 @@ const EditAddress = ({ id, defaultValues }) => { }, [auth?.parentId]); useEffect(() => { - const loadCities = async () => { - let dataCities = await cityApi(); - dataCities = dataCities.map((city) => ({ - value: city.id, - label: city.name, + const loadStates = async () => { + let dataStates = await stateApi(); + dataStates = dataStates.map((state) => ({ + value: state.id, + label: state.name, })); - setCities(dataCities); + setStates(dataStates); }; - loadCities(); - }, []); + loadStates(); + },[]) + + const watchState = watch('state'); + useEffect(() => { + setValue('city', ''); + if(watchState) { + const loadCities = async () => { + let dataCities = await cityApi({ stateId: watchState }); + dataCities = dataCities.map((city) => ({ + value: city.id, + label: city.name, + })); + setCities(dataCities); + let oldCity = getValues('oldCity'); + if (oldCity) { + setValue('city', oldCity); + setValue('oldCity', ''); + } + }; + loadCities(); + } + + }, [watchState, setValue, getValues]); const watchCity = watch('city'); useEffect(() => { @@ -107,6 +132,7 @@ const EditAddress = ({ id, defaultValues }) => { const data = { ...values, phone: values.mobile, + state_id: values.state, city_id: values.city, district_id: values.district, sub_district_id: values.subDistrict, @@ -242,12 +268,26 @@ const EditAddress = ({ id, defaultValues }) => { </div> <div> + <label className='form-label mb-2'>Provinsi</label> + <Controller + name='state' + control={control} + render={(props) => ( + <HookFormSelect {...props} options={states} /> + )} + /> + <div className='text-caption-2 text-danger-500 mt-1'> + {errors.state?.message} + </div> + </div> + + <div> <label className='form-label mb-2'>Kota</label> <Controller name='city' control={control} render={(props) => ( - <HookFormSelect {...props} options={cities} /> + <HookFormSelect {...props} options={cities} disabled={!watchState} /> )} /> <div className='text-caption-2 text-danger-500 mt-1'> @@ -308,6 +348,7 @@ const validationSchema = Yup.object().shape({ mobile: Yup.string().required('Harus di-isi'), street: Yup.string().required('Harus di-isi'), zip: Yup.string().required('Harus di-isi'), + state : Yup.string().required('Harus di-pilih'), city: Yup.string().required('Harus di-pilih'), district: Yup.string().required('Harus di-pilih'), }); diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 4c7e852f..0e180d9c 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -1664,7 +1664,7 @@ const SectionAddress = ({ address, label, url }) => ( ); const SectionValidation = ({ address }) => - address?.rajaongkirCityId == 0 && ( + address?.stateId == 0 && ( <BottomPopup active={true} title='Update Alamat'> <div className='leading-7 text-gray_r-12/80'> Mohon untuk memperbarui alamat Anda dengan mengklik tombol di bawah ini.{' '} diff --git a/src/lib/checkout/components/FinishCheckout.jsx b/src/lib/checkout/components/FinishCheckout.jsx index 92245e31..4a67b252 100644 --- a/src/lib/checkout/components/FinishCheckout.jsx +++ b/src/lib/checkout/components/FinishCheckout.jsx @@ -1,27 +1,86 @@ -import Link from '@/core/components/elements/Link/Link' +import Link from 'next/link'; +import Image from '~/components/ui/image'; +import whatsappUrl from '@/core/utils/whatsappUrl'; +import { useEffect, useState } from 'react'; +import odooApi from '@/core/api/odooApi'; +import useDevice from '@/core/hooks/useDevice'; +import useAuth from '@/core/hooks/useAuth'; +import axios from 'axios'; +import { toast } from 'react-hot-toast'; const FinishCheckout = ({ query }) => { + const [data, setData] = useState(); + const [transactionData, setTransactionData] = useState(); + const { isDesktop, isMobile } = useDevice(); + const auth = useAuth(); + + const so_order = query?.order_id?.replaceAll('-', '/'); + useEffect(() => { + const fetchData = async () => { + const fetchedData = await odooApi( + 'GET', + `/api/v1/sale_order_number?sale_number=${so_order}` + ); + setData(fetchedData[0]); + }; + fetchData(); + }, [query]); + + // Kirim email ketika komponen ini dimount atau sesuai kondisi + const sendEmail = async () => { + try { + const send = await axios.post( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/finish-checkout?orderName=${query?.order_id}`, + {} + ); + if (send.status === 200) { + toast.success('Berhasil mengirim rincian pesanan'); + } else { + toast.error('Gagal mengirimkan rincian pesanan'); + } + } catch (error) { + console.error(error); + toast.error('Gagal mengirimkan rincian pesanan'); + } + }; + return ( - <div className='mx-auto container p-4 md:p-0 mt-0 md:mt-10'> - <div className='rounded-xl bg-warning-100 text-center border border-warning-300 w-full md:w-1/2 mx-auto'> - <div className='px-4 py-6 text-warning-900'> - <p className='font-semibold mb-2'>Terima Kasih atas Pembelian Anda</p> - <p className='text-warning-800 mb-4 leading-6'> - Rincian belanja sudah kami kirimkan ke email anda. Mohon dicek kembali. jika tidak - menerima email, anda dapat menghubungi kami disini. - </p> - <p className='mb-2 font-medium'>{query?.order_id?.replaceAll('-', '/')}</p> - <p className='text-caption-2 text-warning-800'>No. Transaksi</p> - </div> + <div className='flex flex-col items-center'> + <Image + src='/images/CHECKOUT-PESANAN.svg' + alt='Checkout Pesanan' + width={isMobile ? 300 : 450} + height={isMobile ? 300 : 450} + /> + <div className='text-title-sm md:text-title-lg text-center font-semibold'> + Terima Kasih atas Pembelian Kamu + </div> + <div className='flex flex-col justify-center items-center text-body-2 md:text-body-1 text-center mt-3 px-24 md:px-36 py-4 border-2 gap-y-2 rounded'> + <p className='font-bold'>No. Transaksi</p> + <p className='mb-2 font-medium text-red-500 text-xl'> + {query?.order_id?.replaceAll('-', '/')} + </p> <Link - href='/my/quotations' - className='bg-warning-400 text-warning-900 rounded-b-xl py-4 block' + href={`/my/quotations/${data?.id}`} + className='btn-solid-red rounded-md text-base' > - Lihat detail pembelian Anda disini + Cek Detail Transaksi </Link> </div> + <div className='mt-2 text-center leading-6 text-base p-4 md:p-0 md:max-w-[700px]'> + Rincian pembelian sudah kami kirimkan ke email kamu. Mohon dicek + kembali. jika tidak menerima email, kamu dapat menghubungi kami{' '} + <a className='text-red-500' href={whatsappUrl()}> + di sini + </a>{' '} + atau{' '} + <span onClick={sendEmail} className='text-red-500 cursor-pointer'> + kirim rincian pesanan ulang + </span> + . + </div> </div> - ) -} + ); +}; -export default FinishCheckout +export default FinishCheckout; diff --git a/src/lib/flashSale/components/FlashSale.jsx b/src/lib/flashSale/components/FlashSale.jsx index 5be6d4e3..89c46de4 100644 --- a/src/lib/flashSale/components/FlashSale.jsx +++ b/src/lib/flashSale/components/FlashSale.jsx @@ -26,38 +26,40 @@ const FlashSale = () => { } return ( - flashSales?.length > 0 && ( - <div className='px-4 sm:px-0 grid grid-cols-1 gap-y-8'> - {flashSales.map((flashSale, index) => ( - <div key={index}> - <div className='flex gap-x-3 mb-4 justify-between sm:justify-start'> - <div className='font-medium sm:text-h-lg mt-1.5'> - {flashSale.name} + <div className='sm:mt-4'> + {flashSales?.length > 0 && ( + <div className='px-4 sm:px-0 grid grid-cols-1 gap-y-8 sm:mt-4'> + {flashSales.map((flashSale, index) => ( + <div key={index}> + <div className='flex gap-x-3 mb-4 justify-between sm:justify-start'> + <div className='font-medium sm:text-h-lg mt-1.5'> + {flashSale.name} + </div> + <CountDown initialTime={flashSale.duration} /> </div> - <CountDown initialTime={flashSale.duration} /> - </div> - <div className='relative'> - <Image - src={flashSale.banner} - alt={flashSale.name} - width={1080} - height={192} - className='w-full rounded mb-4 hidden sm:block' - /> - <Image - src={flashSale.bannerMobile} - alt={flashSale.name} - width={256} - height={48} - className='w-full rounded mb-4 block sm:hidden' - /> - <FlashSaleProduct flashSaleId={flashSale.pricelistId} /> + <div className='relative'> + <Image + src={flashSale.banner} + alt={flashSale.name} + width={1080} + height={192} + className='w-full rounded mb-4 hidden sm:block' + /> + <Image + src={flashSale.bannerMobile} + alt={flashSale.name} + width={256} + height={48} + className='w-full rounded mb-4 block sm:hidden' + /> + <FlashSaleProduct flashSaleId={flashSale.pricelistId} /> + </div> </div> - </div> - ))} - </div> - ) + ))} + </div> + )} + </div> ); }; diff --git a/src/lib/flashSale/components/FlashSaleNonDisplay.jsx b/src/lib/flashSale/components/FlashSaleNonDisplay.jsx new file mode 100644 index 00000000..c91de2be --- /dev/null +++ b/src/lib/flashSale/components/FlashSaleNonDisplay.jsx @@ -0,0 +1,68 @@ +import Image from 'next/image'; +import { useEffect, useState } from 'react'; +import CountDown from '@/core/components/elements/CountDown/CountDown'; +import productSearchApi from '@/lib/product/api/productSearchApi'; +import ProductSlider from '@/lib/product/components/ProductSlider'; +import flashSaleApi from '../api/flashSaleApi'; +import { FlashSaleSkeleton } from '../skeleton/FlashSaleSkeleton'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; +const FlashSaleNonDisplay = () => { + const [flashSales, setFlashSales] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const router = useRouter(); + useEffect(() => { + const loadFlashSales = async () => { + const dataFlashSales = await flashSaleApi(); + setFlashSales(dataFlashSales); + setIsLoading(false); + }; + loadFlashSales(); + }, []); + const handleSubmit = () => { + router.push(`/shop/search?penawaran=${flashSales[0]?.pricelistId}`); + }; + if (isLoading) { + return <FlashSaleSkeleton />; + } + + return ( + flashSales?.length > 0 && ( + <div className='px-4 sm:px-0 grid grid-cols-1 gap-y-8'> + {flashSales.map((flashSale, index) => ( + <div key={index}> + <div className='flex items-center mb-4 justify-between '> + <div className='font-medium sm:text-h-lg mt-1.5'> + Penawaran Terbatas + </div> + <div + onClick={handleSubmit} + className='!text-red-500 font-semibold cursor-pointer' + > + Lihat Semua + </div> + </div> + <div className='relative'> + <FlashSaleProduct flashSaleId={flashSale.pricelistId} /> + </div> + </div> + ))} + </div> + ) + ); +}; +const FlashSaleProduct = ({ flashSaleId }) => { + const [products, setProducts] = useState(null); + useEffect(() => { + const loadProducts = async () => { + const dataProducts = await productSearchApi({ + query: `fq=-flashsale_id_i:${flashSaleId}&fq=flashsale_price_f:[1 TO *]&limit=25&orderBy=flashsale-discount-desc`, + operation: 'AND', + }); + setProducts(dataProducts.response); + }; + loadProducts(); + }, [flashSaleId]); + return <ProductSlider products={products} />; +}; +export default FlashSaleNonDisplay; diff --git a/src/lib/home/api/categoryManagementApi.js b/src/lib/home/api/categoryManagementApi.js index 2ff4fdfc..4101f87a 100644 --- a/src/lib/home/api/categoryManagementApi.js +++ b/src/lib/home/api/categoryManagementApi.js @@ -42,3 +42,11 @@ const map = async (promotions) => { return productMapped; }); }; + +export const fetchCategoryManagementVersion = async () => { + const response = await fetch( + '/solr/admin/cores?action=STATUS&core=category_management' + ); + const data = await response.json(); + return data.status.category_management.index.version; +}; diff --git a/src/lib/home/components/BannerSection.jsx b/src/lib/home/components/BannerSection.jsx index f83c36fc..60d38f8f 100644 --- a/src/lib/home/components/BannerSection.jsx +++ b/src/lib/home/components/BannerSection.jsx @@ -1,18 +1,42 @@ import Link from '@/core/components/elements/Link/Link'; import Image from 'next/image'; +import { useEffect, useState } from 'react'; +import { bannerApi } from '../../../api/bannerApi'; const { useQuery } = require('react-query'); const { default: bannerSectionApi } = require('../api/bannerSectionApi'); const BannerSection = () => { - const fetchBannerSection = async () => await bannerSectionApi(); - const bannerSection = useQuery('bannerSection', fetchBannerSection); + const [data, setData] = useState(null); + const [shouldFetch, setShouldFetch] = useState(false); + + useEffect(() => { + const localData = localStorage.getItem('Homepage_bannerSection'); + if (localData) { + setData(JSON.parse(localData)); + }else{ + setShouldFetch(true); + } + }, []); + + // const fetchBannerSection = async () => await bannerSectionApi(); + const getBannerSection = useQuery('bannerSection', bannerApi({ type: 'home-banner' }), { + enabled: shouldFetch, + onSuccess: (data) => { + if (data) { + localStorage.setItem('Homepage_bannerSection', JSON.stringify(data)); + setData(data); + } + }, + }); + + const bannerSection = data; return ( - bannerSection.data && - bannerSection.data?.length > 0 && ( + bannerSection && + bannerSection?.length > 0 && ( <div className='grid grid-cols-1 sm:grid-cols-2 gap-4'> - {bannerSection.data?.map((banner) => ( + {bannerSection?.map((banner) => ( <Link key={banner.id} href={banner.url}> <Image width={1024} diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx index 49a9a93f..e62575f7 100644 --- a/src/lib/home/components/CategoryDynamic.jsx +++ b/src/lib/home/components/CategoryDynamic.jsx @@ -1,5 +1,8 @@ import React, { useEffect, useState, useCallback } from 'react'; -import { fetchCategoryManagementSolr } from '../api/categoryManagementApi'; +import { + fetchCategoryManagementSolr, + fetchCategoryManagementVersion, +} from '../api/categoryManagementApi'; import NextImage from 'next/image'; import Link from 'next/link'; import { createSlug } from '@/core/utils/slug'; @@ -10,48 +13,69 @@ import 'swiper/css/navigation'; import 'swiper/css/pagination'; import { Pagination } from 'swiper'; +const saveToLocalStorage = (key, data, version) => { + const now = new Date(); + const item = { + value: data, + version: version, + lastFetchedTime: now.getTime(), + }; + localStorage.setItem(key, JSON.stringify(item)); +}; + +const getFromLocalStorage = (key) => { + const itemStr = localStorage.getItem(key); + if (!itemStr) return null; + + const item = JSON.parse(itemStr); + return item; +}; + +const getElapsedTime = (lastFetchedTime) => { + const now = new Date(); + return now.getTime() - lastFetchedTime; +}; + const CategoryDynamic = () => { const [categoryManagement, setCategoryManagement] = useState([]); const [isLoading, setIsLoading] = useState(false); + const loadBrand = useCallback(async () => { - setIsLoading(true); - const items = await fetchCategoryManagementSolr(); + const cachedData = getFromLocalStorage('homepage_categoryDynamic'); + + if (cachedData) { + // Hitung selisih waktu antara saat ini dengan waktu terakhir data di-fetch + const elapsedTime = getElapsedTime(cachedData.lastFetchedTime); - setIsLoading(false); - setCategoryManagement(items); + if (elapsedTime < 24 * 60 * 60 * 1000) { + setCategoryManagement(cachedData.value); + return; + } + } + + const latestVersion = await fetchCategoryManagementVersion(); + if (cachedData && cachedData.version === latestVersion) { + // perbarui waktu + saveToLocalStorage( + 'homepage_categoryDynamic', + cachedData.value, + latestVersion + ); + setCategoryManagement(cachedData.value); + } else { + setIsLoading(true); + const items = await fetchCategoryManagementSolr(); + setIsLoading(false); + + saveToLocalStorage('homepage_categoryDynamic', items, latestVersion); + setCategoryManagement(items); + } }, []); useEffect(() => { loadBrand(); }, [loadBrand]); - // const [categoryData, setCategoryData] = useState({}); - // const [subCategoryData, setSubCategoryData] = useState({}); - - // useEffect(() => { - // const fetchCategoryData = async () => { - // if (categoryManagement && categoryManagement.data) { - // const updatedCategoryData = {}; - // const updatedSubCategoryData = {}; - - // for (const category of categoryManagement.data) { - // const countLevel1 = await odooApi('GET', `/api/v1/category/numFound?parent_id=${category.categoryIdI}`); - - // updatedCategoryData[category.categoryIdI] = countLevel1?.numFound; - - // for (const subCategory of countLevel1?.children) { - // updatedSubCategoryData[subCategory.id] = subCategory?.numFound; - // } - // } - - // setCategoryData(updatedCategoryData); - // setSubCategoryData(updatedSubCategoryData); - // } - // }; - - // fetchCategoryData(); - // }, [categoryManagement.isLoading]); - const swiperBanner = { modules: [Pagination], classNames: 'mySwiper', @@ -67,7 +91,6 @@ const CategoryDynamic = () => { <div> {categoryManagement && categoryManagement?.map((category) => { - // const countLevel1 = categoryData[category.categoryIdI] || 0; return ( <Skeleton key={category.id} isLoaded={!isLoading}> <div key={category.id}> @@ -75,9 +98,6 @@ const CategoryDynamic = () => { <h1 className='font-semibold text-[14px] sm:text-h-lg mr-2'> {category.name} </h1> - {/* <Skeleton isLoaded={countLevel1 != 0}> - <p className={`text-gray_r-10 text-sm`}>{countLevel1} Produk tersedia</p> - </Skeleton> */} <Link href={createSlug( '/shop/category/', @@ -93,8 +113,6 @@ const CategoryDynamic = () => { {/* Swiper for SubCategories */} <Swiper {...swiperBanner}> {category.categories.map((subCategory) => { - // const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; - return ( <SwiperSlide key={subCategory.id}> <div className='border rounded justify-start items-start '> @@ -115,11 +133,6 @@ const CategoryDynamic = () => { <h2 className='font-semibold text-lg mr-2'> {subCategory?.name} </h2> - {/* <Skeleton isLoaded={countLevel2 != 0}> - <p className={`text-gray_r-10 text-sm`}> - {countLevel2} Produk tersedia - </p> - </Skeleton> */} <Link href={createSlug( '/shop/category/', diff --git a/src/lib/home/components/CategoryDynamicMobile.jsx b/src/lib/home/components/CategoryDynamicMobile.jsx index 4a8f13cf..55654b0e 100644 --- a/src/lib/home/components/CategoryDynamicMobile.jsx +++ b/src/lib/home/components/CategoryDynamicMobile.jsx @@ -4,52 +4,91 @@ import Link from 'next/link'; import { createSlug } from '@/core/utils/slug'; import { Swiper, SwiperSlide } from 'swiper/react'; import 'swiper/css'; -import { fetchCategoryManagementSolr } from '../api/categoryManagementApi'; +import { + fetchCategoryManagementSolr, + fetchCategoryManagementVersion, +} from '../api/categoryManagementApi'; + +const saveToLocalStorage = (key, data, version) => { + const now = new Date(); + const item = { + value: data, + version: version, + lastFetchedTime: now.getTime(), + }; + localStorage.setItem(key, JSON.stringify(item)); +}; + +const getFromLocalStorage = (key) => { + const itemStr = localStorage.getItem(key); + if (!itemStr) return null; + + const item = JSON.parse(itemStr); + return item; +}; + +const getElapsedTime = (lastFetchedTime) => { + const now = new Date(); + return now.getTime() - lastFetchedTime; +}; const CategoryDynamicMobile = () => { const [selectedCategory, setSelectedCategory] = useState({}); const [categoryManagement, setCategoryManagement] = useState([]); const [isLoading, setIsLoading] = useState(false); - const loadBrand = useCallback(async () => { - setIsLoading(true); - const items = await fetchCategoryManagementSolr(); + const loadCategoryManagement = useCallback(async () => { + const cachedData = getFromLocalStorage('homepage_categoryDynamic'); + + if (cachedData) { + // Hitung selisih waktu antara saat ini dengan waktu terakhir data di-fetch + const elapsedTime = getElapsedTime(cachedData.lastFetchedTime); + + if (elapsedTime < 24 * 60 * 60 * 1000) { + setCategoryManagement(cachedData.value); + return; + } + } - setIsLoading(false); - setCategoryManagement(items); + const latestVersion = await fetchCategoryManagementVersion(); + if (cachedData && cachedData.version === latestVersion) { + // perbarui waktu + saveToLocalStorage( + 'homepage_categoryDynamic', + cachedData.value, + latestVersion + ); + setCategoryManagement(cachedData.value); + } else { + setIsLoading(true); + const items = await fetchCategoryManagementSolr(); + setIsLoading(false); + + saveToLocalStorage('homepage_categoryDynamic', items, latestVersion); + setCategoryManagement(items); + } }, []); useEffect(() => { - loadBrand(); - }, [loadBrand]); + loadCategoryManagement(); + }, [loadCategoryManagement]); useEffect(() => { - const loadPromo = async () => { - try { - if (categoryManagement?.length > 0) { - const initialSelections = categoryManagement.reduce( - (acc, category) => { - if (category.categories.length > 0) { - acc[category.id] = category.categories[0].id_level_2; - } - return acc; - }, - {} - ); - setSelectedCategory(initialSelections); + if (categoryManagement?.length > 0) { + const initialSelections = categoryManagement.reduce((acc, category) => { + if (category.categories.length > 0) { + acc[category.id] = category.categories[0].id_level_2; } - } catch (loadError) { - // console.error("Error loading promo items:", loadError); - } - }; - - loadPromo(); + return acc; + }, {}); + setSelectedCategory(initialSelections); + } }, [categoryManagement]); - const handleCategoryLevel2Click = (categoryIdI, idLevel2) => { + const handleCategoryLevel2Click = (categoryId, idLevel2) => { setSelectedCategory((prev) => ({ ...prev, - [categoryIdI]: idLevel2, + [categoryId]: idLevel2, })); }; diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx index ae06bd4d..7433e7f0 100644 --- a/src/lib/home/components/PromotionProgram.jsx +++ b/src/lib/home/components/PromotionProgram.jsx @@ -4,15 +4,38 @@ import { bannerApi } from '@/api/bannerApi'; import useDevice from '@/core/hooks/useDevice'; import { Swiper, SwiperSlide } from 'swiper/react'; import BannerPromoSkeleton from '../components/Skeleton/BannerPromoSkeleton'; +import { useEffect, useState } from 'react'; const { useQuery } = require('react-query'); const BannerSection = () => { - const promotionProgram = useQuery( + const { isMobile, isDesktop } = useDevice(); + const [data, setData] = useState(null); + const [shouldFetch, setShouldFetch] = useState(false); + + useEffect(() => { + const localData = localStorage.getItem('Homepage_promotionProgram'); + if (localData) { + setData(JSON.parse(localData)); + }else{ + setShouldFetch(true); + } + },[]) + + const getPromotionProgram = useQuery( 'promotionProgram', - bannerApi({ type: 'banner-promotion' }) + bannerApi({ type: 'banner-promotion' }),{ + enabled: shouldFetch, + onSuccess: (data) => { + if (data) { + localStorage.setItem('Homepage_promotionProgram', JSON.stringify(data)); + setData(data); + } + } + } ); - const { isMobile, isDesktop } = useDevice(); - if (promotionProgram.isLoading) { + const promotionProgram = data + + if (getPromotionProgram?.isLoading && !data) { return <BannerPromoSkeleton />; } @@ -40,10 +63,10 @@ const BannerSection = () => { )} </div> {isDesktop && - promotionProgram.data && - promotionProgram.data?.length > 0 && ( + promotionProgram && + promotionProgram?.length > 0 && ( <div className='grid grid-cols-3 sm:grid-cols-3 gap-4 rounded-md'> - {promotionProgram.data?.map((banner) => ( + {promotionProgram?.map((banner) => ( <Link key={banner.id} href={banner.url}> <Image width={439} @@ -60,7 +83,7 @@ const BannerSection = () => { {isMobile && ( <Swiper slidesPerView={1.1} spaceBetween={8} freeMode> - {promotionProgram.data?.map((banner) => ( + {promotionProgram?.map((banner) => ( <SwiperSlide key={banner.id}> <Link key={banner.id} href={banner.url}> <Image diff --git a/src/lib/product/components/Product/ProductDesktopVariant.jsx b/src/lib/product/components/Product/ProductDesktopVariant.jsx index 55effdfb..86b58e23 100644 --- a/src/lib/product/components/Product/ProductDesktopVariant.jsx +++ b/src/lib/product/components/Product/ProductDesktopVariant.jsx @@ -17,6 +17,7 @@ import { updateItemCart } from '@/core/utils/cart'; import currencyFormat from '@/core/utils/currencyFormat'; import { createSlug } from '@/core/utils/slug'; import whatsappUrl from '@/core/utils/whatsappUrl'; +import { getAuth } from '~/libs/auth'; import { RWebShare } from 'react-web-share'; import productSimilarApi from '../../api/productSimilarApi'; @@ -33,11 +34,9 @@ const ProductDesktopVariant = ({ isVariant, }) => { const router = useRouter(); - const auth = useAuth(); + let auth = useAuth(); const { slug } = router.query; - - console.log('ini product variant', product); - + const { srsltid } = router.query; const [lowestPrice, setLowestPrice] = useState(null); const [addCartAlert, setAddCartAlert] = useState(false); @@ -88,7 +87,7 @@ const ProductDesktopVariant = ({ const handleAddToCart = (variant) => { if (!auth) { - router.push(`/login?next=/shop/product/${slug}`); + router.push(`/login?next=/shop/product/${slug}?srsltid=${srsltid}`); return; } const quantity = quantityInput; @@ -105,8 +104,34 @@ const ProductDesktopVariant = ({ setAddCartAlert(true); }; - const handleBuy = (variant) => { - const quantity = quantityInput; + const handleBuy = async (variant) => { + const quantity = variantQuantityRefs?.current[product.id]?.value; + let isLoggedIn = typeof auth === 'object'; + + if (!isLoggedIn) { + const currentUrl = encodeURIComponent(router.asPath); + await router.push(`/login?next=${currentUrl}`); + + // Tunggu login berhasil, misalnya dengan memantau perubahan status auth. + const authCheckInterval = setInterval(() => { + const newAuth = getAuth(); + if (typeof newAuth === 'object') { + isLoggedIn = true; + auth = newAuth; // Update nilai auth setelah login + clearInterval(authCheckInterval); + } + }, 500); // Periksa status login setiap 500ms + + await new Promise((resolve) => { + const checkLogin = setInterval(() => { + if (isLoggedIn) { + clearInterval(checkLogin); + resolve(null); + } + }, 500); + }); + } + if (!validQuantity(quantity)) return; updateItemCart({ @@ -255,7 +280,7 @@ const ProductDesktopVariant = ({ </div> </div> - <div className='p-4 md:p-6 '> + <div className='p-4 md:p-6 w-full'> <ProductPromoSection product={product} productId={product.id} /> <div className='p-4 md:p-6 md:bg-gray-50 rounded-xl'> diff --git a/src/lib/product/components/Product/ProductMobileVariant.jsx b/src/lib/product/components/Product/ProductMobileVariant.jsx index af9e52bb..c1d7ffe0 100644 --- a/src/lib/product/components/Product/ProductMobileVariant.jsx +++ b/src/lib/product/components/Product/ProductMobileVariant.jsx @@ -16,12 +16,15 @@ import currencyFormat from '@/core/utils/currencyFormat'; import { gtagAddToCart } from '@/core/utils/googleTag'; import { createSlug } from '@/core/utils/slug'; import whatsappUrl from '@/core/utils/whatsappUrl'; +import { getAuth } from '~/libs/auth'; import ProductSimilar from '../ProductSimilar'; const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { const router = useRouter(); - + const { slug } = router.query; + const { srsltid } = router.query; + let auth = getAuth(); const [quantity, setQuantity] = useState('1'); const [selectedVariant, setSelectedVariant] = useState(product.id); const [informationTab, setInformationTab] = useState( @@ -73,11 +76,16 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { return isValid; }; - const handleClickCart = () => { + const handleClickCart = async () => { + if (!auth) { + router.push(`/login?next=/shop/product/${slug}?srsltid=${srsltid}`); + return; + } + if (!validAction()) return; gtagAddToCart(activeVariant, quantity); updateItemCart({ - productId: variant, + productId: product.id, quantity, programLineId: null, selected: true, @@ -86,7 +94,33 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { setAddCartAlert(true); }; - const handleClickBuy = () => { + const handleClickBuy = async () => { + let isLoggedIn = typeof auth === 'object'; + + if (!isLoggedIn) { + const currentUrl = encodeURIComponent(router.asPath); + await router.push(`/login?next=${currentUrl}`); + + // Tunggu login berhasil, misalnya dengan memantau perubahan status auth. + const authCheckInterval = setInterval(() => { + const newAuth = getAuth(); + if (typeof newAuth === 'object') { + isLoggedIn = true; + auth = newAuth; // Update nilai auth setelah login + clearInterval(authCheckInterval); + } + }, 500); // Periksa status login setiap 500ms + + await new Promise((resolve) => { + const checkLogin = setInterval(() => { + if (isLoggedIn) { + clearInterval(checkLogin); + resolve(null); + } + }, 500); + }); + } + if (!validAction()) return; updateItemCart({ diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index d52fcb90..947550b7 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -1,88 +1,96 @@ -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import { useRouter } from 'next/router' -import { useState } from 'react' -import _ from 'lodash' -import { toQuery } from 'lodash-contrib' -import { Checkbox } from '@chakra-ui/react' +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import { useRouter } from 'next/router'; +import { useState } from 'react'; +import _ from 'lodash'; +import { toQuery } from 'lodash-contrib'; +import { Checkbox } from '@chakra-ui/react'; const orderOptions = [ { value: 'price-asc', label: 'Harga Terendah' }, { value: 'price-desc', label: 'Harga Tertinggi' }, { value: 'popular', label: 'Populer' }, - { value: 'stock', label: 'Ready Stock' } -] + { value: 'stock', label: 'Ready Stock' }, +]; -const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBrand = null }) => { - const router = useRouter() - const { query } = router - const [order, setOrder] = useState(query?.orderBy || 'popular') - const [brand, setBrand] = useState(query?.brand) - const [category, setCategory] = useState(query?.category) - const [priceFrom, setPriceFrom] = useState(query?.priceFrom) - const [priceTo, setPriceTo] = useState(query?.priceTo) +const ProductFilter = ({ + active, + close, + brands, + categories, + prefixUrl, + defaultBrand = null, +}) => { + const router = useRouter(); + const { query } = router; + const [order, setOrder] = useState(query?.orderBy || 'popular'); + const [brand, setBrand] = useState(query?.brand); + const [category, setCategory] = useState(query?.category); + const [priceFrom, setPriceFrom] = useState(query?.priceFrom); + const [priceTo, setPriceTo] = useState(query?.priceTo); - const [stock, setStock] = useState(query?.stock) + const [stock, setStock] = useState(query?.stock); - const [activeRange, setActiveRange] = useState(null) + const [activeRange, setActiveRange] = useState(null); const priceRange = [ { priceFrom: 100000, - priceTo: 200000 + priceTo: 200000, }, { priceFrom: 200000, - priceTo: 300000 + priceTo: 300000, }, { priceFrom: 300000, - priceTo: 400000 + priceTo: 400000, }, { priceFrom: 400000, - priceTo: 500000 - } - ] + priceTo: 500000, + }, + ]; const handlePriceFromChange = async (priceFromr, priceTor, index) => { - await setPriceFrom(priceFromr) - await setPriceTo(priceTor) - setActiveRange(index) - } + await setPriceFrom(priceFromr); + await setPriceTo(priceTor); + setActiveRange(index); + }; const handleReadyStockChange = (event) => { - const value = event.target.value - const isChecked = event.target.checked + const value = event.target.value; + const isChecked = event.target.checked; if (isChecked) { - setStock(value) + setStock(value); } else { - setStock(null) + setStock(null); } - } + }; const handleSubmit = () => { let params = { + penawaran: router.query.penawaran, q: router.query.q, orderBy: order, brand, category, priceFrom, priceTo, - stock: stock - } - params = _.pickBy(params, _.identity) - params = toQuery(params) - router.push(`${prefixUrl}?${params}`) - } + stock: stock, + }; + params = _.pickBy(params, _.identity); + params = toQuery(params); + router.push(`${prefixUrl}?${params}`); + }; const formatCurrency = (value) => { if (value >= 1000) { - const thousands = Math.floor(value / 1000) // Menghitung ribuan - return `Rp${thousands}k` + const thousands = Math.floor(value / 1000); // Menghitung ribuan + return `Rp${thousands}k`; } else { - return `Rp${value}` + return `Rp${value}`; } - } + }; return ( <BottomPopup active={active} close={close} title='Filter Produk'> @@ -101,7 +109,10 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr <option value=''>Pilih Brand...</option> {brands.map((brand, index) => ( <option value={brand.brand} key={index}> - {brand.brand} <span className='text-sm text-gray-200'>({brand.qty})</span> + {brand.brand}{' '} + <span className='text-sm text-gray-200'> + ({brand.qty}) + </span> </option> ))} </> @@ -125,7 +136,10 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr <option value=''>Pilih Kategori...</option> {categories.map((category, index) => ( <option value={category.name} key={index}> - {category.name} <span className='text-sm text-gray-200'>({category.qty})</span> + {category.name}{' '} + <span className='text-sm text-gray-200'> + ({category.qty}) + </span> </option> ))} </> @@ -141,7 +155,9 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr <button key={orderOption.value} className={`btn-light px-3 font-normal flex-shrink-0 ${ - order == orderOption.value ? 'bg-warning-500' : 'bg-transparent' + order == orderOption.value + ? 'bg-warning-500' + : 'bg-transparent' }`} onClick={() => setOrder(orderOption.value)} > @@ -173,13 +189,16 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr {priceRange.map((price, i) => ( <button key={i} - onClick={() => handlePriceFromChange(price.priceFrom, price.priceTo, i)} + onClick={() => + handlePriceFromChange(price.priceFrom, price.priceTo, i) + } className={`w-full border ${ i === activeRange ? 'border-red-600' : 'border-gray-400' } py-2 p-3 rounded-full text-sm whitespace-nowrap`} > - {formatCurrency(price.priceFrom)} - {formatCurrency(price.priceTo)} + {formatCurrency(price.priceFrom)} -{' '} + {formatCurrency(price.priceTo)} </button> ))} </div> @@ -197,12 +216,16 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr </Checkbox> </div> </div> */} - <button type='button' className='btn-solid-red w-full mt-2' onClick={handleSubmit}> + <button + type='button' + className='btn-solid-red w-full mt-2' + onClick={handleSubmit} + > Terapkan Filter </button> </div> </BottomPopup> - ) -} + ); +}; -export default ProductFilter +export default ProductFilter; diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index 73fecab5..d2ecb4d9 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -1,7 +1,7 @@ -import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' -import _ from 'lodash' -import { toQuery } from 'lodash-contrib' +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import _ from 'lodash'; +import { toQuery } from 'lodash-contrib'; import { Accordion, AccordionButton, @@ -15,110 +15,119 @@ import { InputGroup, InputLeftAddon, Stack, - VStack -} from '@chakra-ui/react' -import Image from '@/core/components/elements/Image/Image' -import { formatCurrency } from '@/core/utils/formatValue' + VStack, +} from '@chakra-ui/react'; +import Image from '@/core/components/elements/Image/Image'; +import { formatCurrency } from '@/core/utils/formatValue'; -const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = null }) => { - - - const router = useRouter() - const { query } = router - const [order, setOrder] = useState(query?.orderBy) - const [brandValues, setBrand] = useState(query?.brand?.split(',') || []) - const [categoryValues, setCategory] = useState(query?.category?.split(',') || []) - const [priceFrom, setPriceFrom] = useState(query?.priceFrom) - const [priceTo, setPriceTo] = useState(query?.priceTo) - const [stock, setStock] = useState(query?.stock) - const [activeRange, setActiveRange] = useState(null) - const [activeIndeces, setActiveIndeces] = useState([]) +const ProductFilterDesktop = ({ + brands, + categories, + prefixUrl, + defaultBrand = null, +}) => { + const router = useRouter(); + const { query } = router; + const [order, setOrder] = useState(query?.orderBy); + const [brandValues, setBrand] = useState(query?.brand?.split(',') || []); + const [categoryValues, setCategory] = useState( + query?.category?.split(',') || [] + ); + const [priceFrom, setPriceFrom] = useState(query?.priceFrom); + const [priceTo, setPriceTo] = useState(query?.priceTo); + const [stock, setStock] = useState(query?.stock); + const [activeRange, setActiveRange] = useState(null); + const [activeIndeces, setActiveIndeces] = useState([]); const priceRange = [ { priceFrom: 100000, - priceTo: 200000 + priceTo: 200000, }, { priceFrom: 200000, - priceTo: 300000 + priceTo: 300000, }, { priceFrom: 300000, - priceTo: 400000 + priceTo: 400000, }, { priceFrom: 400000, - priceTo: 500000 - } - ] + priceTo: 500000, + }, + ]; const indexRange = priceRange.findIndex((range) => { - return range.priceFrom === parseInt(priceFrom) && range.priceTo == parseInt(priceTo) - }) + return ( + range.priceFrom === parseInt(priceFrom) && + range.priceTo == parseInt(priceTo) + ); + }); const handleCategoriesChange = (event) => { - const value = event.target.value - const isChecked = event.target.checked + const value = event.target.value; + const isChecked = event.target.checked; if (isChecked) { - setCategory([...categoryValues, value]) + setCategory([...categoryValues, value]); } else { - setCategory(categoryValues.filter((val) => val !== value)) + setCategory(categoryValues.filter((val) => val !== value)); } - } + }; const handleBrandsChange = (event) => { - const value = event.target.value - const isChecked = event.target.checked + const value = event.target.value; + const isChecked = event.target.checked; if (isChecked) { - setBrand([...brandValues, value]) + setBrand([...brandValues, value]); } else { - setBrand(brandValues.filter((val) => val !== value)) + setBrand(brandValues.filter((val) => val !== value)); } - } + }; const handleReadyStockChange = (event) => { - const value = event.target.value - const isChecked = event.target.checked + const value = event.target.value; + const isChecked = event.target.checked; if (isChecked) { - setStock(value) + setStock(value); } else { - setStock(null) + setStock(null); } - } + }; const handlePriceFromChange = async (priceFromr, priceTor, index) => { - await setPriceFrom(priceFromr) - await setPriceTo(priceTor) - setActiveRange(index) - } + await setPriceFrom(priceFromr); + await setPriceTo(priceTor); + setActiveRange(index); + }; const handleSubmit = () => { let params = { + penawaran: router.query.penawaran, q: router.query.q, orderBy: order, brand: brandValues.join(','), category: categoryValues.join(','), priceFrom, priceTo, - stock: stock - } - params = _.pickBy(params, _.identity) - params = toQuery(params) + stock: stock, + }; + params = _.pickBy(params, _.identity); + params = toQuery(params); - const slug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug; + const slug = Array.isArray(router.query.slug) + ? router.query.slug[0] + : router.query.slug; if (slug) { - if(prefixUrl.includes('category') || prefixUrl.includes('lob')){ - router.push(`${prefixUrl}?${params}`) - }else{ - router.push(`${prefixUrl}/${slug}?${params}`) + if (prefixUrl.includes('category') || prefixUrl.includes('lob')) { + router.push(`${prefixUrl}?${params}`); + } else { + router.push(`${prefixUrl}/${slug}?${params}`); } } else { - router.push(`${prefixUrl}?${params}`) + router.push(`${prefixUrl}?${params}`); } - } - - + }; /*const handleIndexAccordion = async () => { if (brandValues) { @@ -136,9 +145,8 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu }*/ useEffect(() => { - setActiveRange(indexRange) - }, []) - + setActiveRange(indexRange); + }, []); return ( <> @@ -165,13 +173,17 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu > <div className='flex items-center gap-2'> <span>{brand.brand} </span> - <span className='text-sm text-gray-600'>({brand.qty})</span> + <span className='text-sm text-gray-600'> + ({brand.qty}) + </span> </div> </Checkbox> </div> )) ) : ( - <div className='flex items-center gap-2'>Brands tidak tersedia</div> + <div className='flex items-center gap-2'> + Brands tidak tersedia + </div> )} </Stack> </AccordionPanel> @@ -199,13 +211,17 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu > <div className='flex items-center gap-2'> <span>{category.name} </span> - <span className='text-sm text-gray-600'>({category.qty})</span> + <span className='text-sm text-gray-600'> + ({category.qty}) + </span> </div> </Checkbox> </div> )) ) : ( - <div className='flex items-center gap-2'>Kategori tidak tersedia</div> + <div className='flex items-center gap-2'> + Kategori tidak tersedia + </div> )} </Stack> </AccordionPanel> @@ -243,13 +259,16 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu {priceRange.map((price, i) => ( <button key={i} - onClick={() => handlePriceFromChange(price.priceFrom, price.priceTo, i)} + onClick={() => + handlePriceFromChange(price.priceFrom, price.priceTo, i) + } className={`w-full border ${ i === activeRange ? 'border-red-600' : 'border-gray-400' } py-2 p-3 rounded-full text-sm whitespace-nowrap`} > - {formatCurrency(price.priceFrom)} - {formatCurrency(price.priceTo)} + {formatCurrency(price.priceFrom)} -{' '} + {formatCurrency(price.priceTo)} </button> ))} </div> @@ -282,7 +301,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu Terapkan </Button> </> - ) -} + ); +}; -export default ProductFilterDesktop +export default ProductFilterDesktop; diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index 26114acf..f7b044aa 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -79,6 +79,24 @@ const ProductSearch = ({ } }, [categoryId]); + useEffect(() => { + const checkIfPenawaran = async () => { + if (router.asPath.includes('penawaran')) { + query = { + ...query, + fq: [ + `-flashsale_id_i:${router.query.penawaran}`, + `flashsale_price_f:[1 TO *]`, + ], + orderBy: 'flashsale-discount-desc', + }; + setFinalQuery(query); + setOrderBy('flashsale-discount-desc'); + } + }; + checkIfPenawaran(); + }, [router.query]); + const collectIds = (category) => { const ids = []; function recurse(cat) { @@ -337,6 +355,7 @@ const ProductSearch = ({ const handleDeleteFilter = async (source, value) => { let params = { + penawaran: router.query.penawaran, q: router.query.q, orderBy: orderBy, brand: brandValues.join(','), @@ -364,6 +383,7 @@ const ProductSearch = ({ break; case 'delete': params = { + penawaran: router.query.penawaran, q: router.query.q, orderBy: orderBy, }; diff --git a/src/lib/review/components/CustomerReviews.jsx b/src/lib/review/components/CustomerReviews.jsx index a6e697f0..6ca0fa7b 100644 --- a/src/lib/review/components/CustomerReviews.jsx +++ b/src/lib/review/components/CustomerReviews.jsx @@ -3,16 +3,37 @@ import MobileView from '@/core/components/views/MobileView'; import Image from 'next/image'; import { Swiper, SwiperSlide } from 'swiper/react'; import { Autoplay } from 'swiper'; +import { useEffect, useState } from 'react'; const { useQuery } = require('react-query'); const { getCustomerReviews } = require('../api/customerReviewsApi'); const CustomerReviews = () => { - const { data: customerReviews } = useQuery( + const [data, setData] = useState(null); + + useEffect(() => { + const localData = localStorage.getItem('Homepage_customerReviews'); + if (localData) { + setData(JSON.parse(localData)); + } + },[]) + + + const { data: fetchCustomerReviews } = useQuery( 'customerReviews', - getCustomerReviews + getCustomerReviews,{ + enabled: !data, + onSuccess: (data) => { + if (data) { + localStorage.setItem('Homepage_customerReviews', JSON.stringify(data)); + setData(data); + } + } + } ); + const customerReviews = data + return ( <div className='px-4 sm:px-0'> <h1 className='font-semibold text-[14px] sm:text-h-lg mb-4'> diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index 6269d3ed..49a5fe69 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -23,6 +23,9 @@ export default async function handler(req, res) { let paramOrderBy = ''; switch (orderBy) { + case 'flashsale-discount-desc': + paramOrderBy += 'flashsale_discount_f DESC'; + break; case 'price-asc': paramOrderBy += 'price_tier1_v2_f ASC'; break; @@ -68,15 +71,23 @@ export default async function handler(req, res) { let checkQ = q.trim().split(/[\s\+\-\!\(\)\{\}\[\]\^"~\*\?:\\\/]+/); let newQ = escapeSolrQuery(q); - const formattedQuery = `(${newQ.split(' ').map(term => `${term}*`).join(' ') })`; - const mm = checkQ.length > 2 ? checkQ.length > 5 ? '55%' : '85%' : `${checkQ.length}`; + const formattedQuery = `(${newQ + .split(' ') + .map((term) => `${term}*`) + .join(' ')})`; + const mm = + checkQ.length > 2 + ? checkQ.length > 5 + ? '55%' + : '85%' + : `${checkQ.length}`; const filterQueries = [ '-publish_b:false', 'product_rating_f:[8 TO *]', - 'price_tier1_v2_f:[1 TO *]' + 'price_tier1_v2_f:[1 TO *]', ]; - + const fq_ = filterQueries.join('AND '); let offset = (page - 1) * limit; @@ -87,7 +98,13 @@ export default async function handler(req, res) { 'indent=true', `facet.query=${escapeSolrQuery(q)}`, `q.op=OR`, - `q=${source == 'similar' || checkQ.length < 3 ? checkQ.length < 2 ? newQ : newQ + '*' : formattedQuery }`, + `q=${ + source == 'similar' || checkQ.length < 3 + ? checkQ.length < 2 + ? newQ + : newQ + '*' + : formattedQuery + }`, `defType=edismax`, 'qf=name_s description_clean_t category_name manufacture_name_s variants_code_t variants_name_t category_id_ids default_code_s', `start=${parseInt(offset)}`, @@ -135,12 +152,14 @@ export default async function handler(req, res) { if (typeof fq === 'string') parameter.push(`fq=${encodeURIComponent(fq)}`); // Multi fq in url params if (Array.isArray(fq)) - parameter = parameter.concat(fq.map((val) => `fq=${encodeURIComponent(val)}`)); - + parameter = parameter.concat( + fq.map((val) => `fq=${encodeURIComponent(val)}`) + ); + let result = await axios( process.env.SOLR_HOST + '/solr/product/select?' + parameter.join('&') ); - + try { result.data.response.products = productMappingSolr( result.data.response.docs, diff --git a/src/pages/index.jsx b/src/pages/index.jsx index ac925b4e..cc4d68db 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -60,11 +60,11 @@ const CategoryHomeId = dynamic(() => ); const CategoryDynamic = dynamic(() => - import('@/lib/home/components/CategoryDynamic'), {ssr : false} + import('@/lib/home/components/CategoryDynamic') ); const CategoryDynamicMobile = dynamic(() => -import('@/lib/home/components/CategoryDynamicMobile'), {ssr: false} +import('@/lib/home/components/CategoryDynamicMobile') ); const CustomerReviews = dynamic(() => diff --git a/src/pages/my/address/[id]/edit.jsx b/src/pages/my/address/[id]/edit.jsx index c552659b..19d7af41 100644 --- a/src/pages/my/address/[id]/edit.jsx +++ b/src/pages/my/address/[id]/edit.jsx @@ -37,12 +37,15 @@ export async function getServerSideProps(context) { mobile: address.mobile, street: address.street, zip: address.zip, - city: address.city?.id || '', + state: address.stateId?.id || '', + oldCity: address.city?.id || '', + city: '', oldDistrict: address.district?.id || '', district: '', oldSubDistrict: address.subDistrict?.id || '', subDistrict: '', business_name: '', }; + // console.log('ini default',defaultValues); return { props: { id, defaultValues } }; } diff --git a/src/pages/shop/checkout/[status].jsx b/src/pages/shop/checkout/[status].jsx index 2c3bebcf..0d5cffe8 100644 --- a/src/pages/shop/checkout/[status].jsx +++ b/src/pages/shop/checkout/[status].jsx @@ -1,22 +1,22 @@ -import BasicLayout from '@/core/components/layouts/BasicLayout' -import IsAuth from '@/lib/auth/components/IsAuth' -import FinishCheckoutComponent from '@/lib/checkout/components/FinishCheckout' -import { useRouter } from 'next/router' -import axios from 'axios' -import Seo from '@/core/components/Seo' +import BasicLayout from '@/core/components/layouts/BasicLayout'; +import IsAuth from '@/lib/auth/components/IsAuth'; +import FinishCheckoutComponent from '@/lib/checkout/components/FinishCheckout'; +import { useRouter } from 'next/router'; +import axios from 'axios'; +import Seo from '@/core/components/Seo'; export async function getServerSideProps(context) { - const { order_id } = context.query + const { order_id } = context.query; await axios.post( `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/finish-checkout?orderName=${order_id}`, {}, { headers: context.req.headers } - ) - return { props: {} } + ); + return { props: {} }; } export default function Finish() { - const router = useRouter() + const router = useRouter(); return ( <> @@ -28,5 +28,5 @@ export default function Finish() { </BasicLayout> </IsAuth> </> - ) + ); } |
