summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2024-10-24 11:01:08 +0700
committerit-fixcomart <it@fixcomart.co.id>2024-10-24 11:01:08 +0700
commit9abd621285d739a9c502d661013db5ce96edec33 (patch)
tree98ff4ae0bf8adcced77699de33aebe50616233dc
parentca30c28dd0b19977eb771fc32ff5e520cdef1068 (diff)
parente0aa9e04a473a4f7a21b389b42314d3fed06b43e (diff)
Merge branch 'new-release' into CR/new_product_detail
-rw-r--r--public/images/CHECKOUT-PESANAN.svg958
-rw-r--r--src-migrate/modules/page-content/index.tsx30
-rw-r--r--src-migrate/modules/product-detail/components/AddToCart.tsx312
-rw-r--r--src-migrate/modules/promo/components/FlashSaleNonDisplay.tsx17
-rw-r--r--src-migrate/modules/promo/components/PromoList.tsx79
-rw-r--r--src-migrate/pages/shop/promo/index.tsx41
-rw-r--r--src/lib/address/api/cityApi.js4
-rw-r--r--src/lib/address/api/stateApi.js8
-rw-r--r--src/lib/address/components/CreateAddress.jsx51
-rw-r--r--src/lib/address/components/EditAddress.jsx61
-rw-r--r--src/lib/checkout/components/Checkout.jsx2
-rw-r--r--src/lib/checkout/components/FinishCheckout.jsx95
-rw-r--r--src/lib/flashSale/components/FlashSale.jsx60
-rw-r--r--src/lib/flashSale/components/FlashSaleNonDisplay.jsx68
-rw-r--r--src/lib/home/api/categoryManagementApi.js8
-rw-r--r--src/lib/home/components/BannerSection.jsx34
-rw-r--r--src/lib/home/components/CategoryDynamic.jsx99
-rw-r--r--src/lib/home/components/CategoryDynamicMobile.jsx97
-rw-r--r--src/lib/home/components/PromotionProgram.jsx39
-rw-r--r--src/lib/product/components/Product/ProductDesktopVariant.jsx41
-rw-r--r--src/lib/product/components/Product/ProductMobileVariant.jsx42
-rw-r--r--src/lib/product/components/ProductFilter.jsx127
-rw-r--r--src/lib/product/components/ProductFilterDesktop.jsx165
-rw-r--r--src/lib/product/components/ProductSearch.jsx20
-rw-r--r--src/lib/review/components/CustomerReviews.jsx25
-rw-r--r--src/pages/api/shop/search.js35
-rw-r--r--src/pages/index.jsx4
-rw-r--r--src/pages/my/address/[id]/edit.jsx5
-rw-r--r--src/pages/shop/checkout/[status].jsx22
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>
</>
- )
+ );
}