@akinon/projectzero 2.0.0-beta.9 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/CHANGELOG.md +191 -17
  2. package/app-template/.env.example +3 -0
  3. package/app-template/.github/instructions/account.instructions.md +749 -0
  4. package/app-template/.github/instructions/checkout.instructions.md +678 -0
  5. package/app-template/.github/instructions/default.instructions.md +279 -0
  6. package/app-template/.github/instructions/edge-cases.instructions.md +73 -0
  7. package/app-template/.github/instructions/routing.instructions.md +603 -0
  8. package/app-template/.github/instructions/settings.instructions.md +338 -0
  9. package/app-template/.gitignore +3 -0
  10. package/app-template/AGENTS.md +7 -0
  11. package/app-template/CHANGELOG.md +2065 -232
  12. package/app-template/Procfile +1 -1
  13. package/app-template/akinon.json +1 -4
  14. package/app-template/build.sh +10 -0
  15. package/app-template/docs/advanced-usage.md +111 -0
  16. package/app-template/docs/plugins.md +60 -25
  17. package/app-template/docs/sentry-usage.md +35 -0
  18. package/app-template/jest.config.ts +2 -2
  19. package/app-template/next-env.d.ts +1 -0
  20. package/app-template/{next.config.ts → next.config.mjs} +6 -7
  21. package/app-template/package.json +58 -50
  22. package/app-template/postcss.config.mjs +1 -4
  23. package/app-template/public/amex.svg +12 -0
  24. package/app-template/public/apple-pay.svg +16 -0
  25. package/app-template/public/assets/images/product-placeholder-1.jpg +0 -0
  26. package/app-template/public/assets/images/product-placeholder-2.jpg +0 -0
  27. package/app-template/public/assets/images/product-placeholder-3.jpg +0 -0
  28. package/app-template/public/assets/images/product-placeholder-4.jpg +0 -0
  29. package/app-template/public/google-pay.svg +16 -0
  30. package/app-template/public/locales/en/account.json +9 -4
  31. package/app-template/public/locales/en/auth.json +6 -7
  32. package/app-template/public/locales/en/basket.json +6 -6
  33. package/app-template/public/locales/en/blog.json +7 -0
  34. package/app-template/public/locales/en/category.json +3 -1
  35. package/app-template/public/locales/en/checkout.json +17 -4
  36. package/app-template/public/locales/en/common.json +61 -3
  37. package/app-template/public/locales/en/forgot_password.json +6 -7
  38. package/app-template/public/locales/en/product.json +84 -4
  39. package/app-template/public/locales/tr/account.json +9 -4
  40. package/app-template/public/locales/tr/auth.json +16 -17
  41. package/app-template/public/locales/tr/basket.json +4 -4
  42. package/app-template/public/locales/tr/blog.json +7 -0
  43. package/app-template/public/locales/tr/category.json +3 -1
  44. package/app-template/public/locales/tr/checkout.json +48 -36
  45. package/app-template/public/locales/tr/common.json +60 -2
  46. package/app-template/public/locales/tr/forgot_password.json +12 -13
  47. package/app-template/public/locales/tr/product.json +82 -0
  48. package/app-template/public/logo.svg +3 -27
  49. package/app-template/public/mastercard.svg +14 -0
  50. package/app-template/public/masterpass-javascript-sdk-web.min.js +1 -0
  51. package/app-template/public/promotion-banner.jpg +0 -0
  52. package/app-template/public/shop-pay.svg +12 -0
  53. package/app-template/public/visa.svg +12 -0
  54. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/[...prettyurl]/page.tsx +11 -11
  55. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/layout.tsx +4 -3
  56. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/cancellation/page.tsx +13 -10
  57. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/page.tsx +73 -51
  58. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/page.tsx +1 -1
  59. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/profile/page.tsx +2 -2
  60. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/address/stores/page.tsx +2 -2
  61. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/page.tsx +1 -1
  62. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket/page.tsx +2 -2
  63. package/app-template/src/app/[pz]/blog/[slug]/page.tsx +120 -0
  64. package/app-template/src/app/[pz]/category/[pk]/page.tsx +37 -0
  65. package/app-template/src/app/[pz]/flat-page/[pk]/page.tsx +23 -0
  66. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/forms/[pk]/generate/page.tsx +2 -3
  67. package/app-template/src/app/[pz]/group-product/[pk]/page.tsx +93 -0
  68. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/page.tsx +2 -4
  69. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/layout.tsx +6 -11
  70. package/app-template/src/app/[pz]/list/page.tsx +26 -0
  71. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/not-found.tsx +5 -7
  72. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/page.tsx +6 -4
  73. package/app-template/src/app/[pz]/page.tsx +28 -0
  74. package/app-template/src/app/[pz]/pages/[slug]/page.tsx +19 -0
  75. package/app-template/src/app/[pz]/product/[pk]/page.tsx +102 -0
  76. package/app-template/src/app/[pz]/special-page/[pk]/page.tsx +35 -0
  77. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/email-set-primary/[[...id]]/page.tsx +3 -4
  78. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/registration/account-confirm-email/[[...id]]/page.tsx +3 -3
  79. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/reset/[[...id]]/page.tsx +41 -5
  80. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/[node]/route.ts +8 -6
  81. package/app-template/src/app/api/auth/[...nextauth]/route.ts +3 -0
  82. package/app-template/src/app/api/barcode-search/route.ts +1 -0
  83. package/app-template/src/app/api/cache/route.ts +1 -1
  84. package/app-template/src/app/api/form/[...id]/route.ts +1 -7
  85. package/app-template/src/app/api/image-proxy/route.ts +1 -0
  86. package/app-template/src/app/api/logout/route.ts +1 -1
  87. package/app-template/src/app/api/product-categories/route.ts +1 -0
  88. package/app-template/src/app/api/similar-product-list/route.ts +1 -0
  89. package/app-template/src/app/api/similar-products/route.ts +1 -0
  90. package/app-template/src/app/api/theme-settings/route.ts +12 -0
  91. package/app-template/src/app/api/virtual-try-on/limited-categories/route.ts +1 -0
  92. package/app-template/src/app/api/virtual-try-on/route.ts +1 -0
  93. package/app-template/src/app/api/web-vitals/route.ts +1 -1
  94. package/app-template/src/assets/fonts/pz-icon.css +211 -49
  95. package/app-template/src/assets/fonts/pz-icon.eot +0 -0
  96. package/app-template/src/assets/fonts/pz-icon.html +486 -0
  97. package/app-template/src/assets/fonts/pz-icon.scss +373 -49
  98. package/app-template/src/assets/fonts/pz-icon.svg +215 -53
  99. package/app-template/src/assets/fonts/pz-icon.ttf +0 -0
  100. package/app-template/src/assets/fonts/pz-icon.woff +0 -0
  101. package/app-template/src/assets/fonts/pz-icon.woff2 +0 -0
  102. package/app-template/src/assets/globals.scss +8 -133
  103. package/app-template/src/assets/icons/arrow-right.svg +3 -0
  104. package/app-template/src/assets/icons/cart.svg +4 -12
  105. package/app-template/src/assets/icons/check.svg +2 -18
  106. package/app-template/src/assets/icons/chevron-down.svg +2 -7
  107. package/app-template/src/assets/icons/delete.svg +3 -0
  108. package/app-template/src/assets/icons/facebook.svg +2 -8
  109. package/app-template/src/assets/icons/fav-off.svg +5 -0
  110. package/app-template/src/assets/icons/fav-on.svg +5 -0
  111. package/app-template/src/assets/icons/filter-and-sort.svg +3 -0
  112. package/app-template/src/assets/icons/heart.svg +3 -0
  113. package/app-template/src/assets/icons/instagram.svg +2 -13
  114. package/app-template/src/assets/icons/materials.svg +3 -0
  115. package/app-template/src/assets/icons/person.svg +4 -0
  116. package/app-template/src/assets/icons/pinterest.svg +5 -11
  117. package/app-template/src/assets/icons/ruler.svg +3 -0
  118. package/app-template/src/assets/icons/search.svg +8 -11
  119. package/app-template/src/assets/icons/share.svg +2 -9
  120. package/app-template/src/assets/icons/snapchat.svg +3 -0
  121. package/app-template/src/assets/icons/tiktok.svg +3 -0
  122. package/app-template/src/assets/icons/tumblr.svg +6 -0
  123. package/app-template/src/assets/icons/twitter.svg +2 -10
  124. package/app-template/src/assets/icons/vimeo.svg +3 -0
  125. package/app-template/src/assets/icons/youtube.svg +3 -0
  126. package/app-template/src/assets/icons/zoom.svg +8 -0
  127. package/app-template/src/auth.ts +3 -0
  128. package/app-template/src/components/__tests__/badge.test.tsx +2 -2
  129. package/app-template/src/components/__tests__/link.test.tsx +2 -0
  130. package/app-template/src/components/accordion.tsx +48 -23
  131. package/app-template/src/components/action-tooltip.tsx +160 -0
  132. package/app-template/src/components/button.tsx +1 -1
  133. package/app-template/src/components/carousel-core.tsx +4 -11
  134. package/app-template/src/components/checkbox.tsx +2 -1
  135. package/app-template/src/components/currency-select.tsx +150 -4
  136. package/app-template/src/components/file-input.tsx +27 -7
  137. package/app-template/src/components/generate-form-fields.tsx +49 -10
  138. package/app-template/src/components/icon.tsx +5 -6
  139. package/app-template/src/components/index.ts +4 -1
  140. package/app-template/src/components/input.tsx +11 -5
  141. package/app-template/src/components/language-select.tsx +88 -2
  142. package/app-template/src/components/modal.tsx +34 -16
  143. package/app-template/src/components/pagination.tsx +133 -20
  144. package/app-template/src/components/price.tsx +1 -1
  145. package/app-template/src/components/pwa-tags.tsx +1 -0
  146. package/app-template/src/components/quantity-input.tsx +63 -0
  147. package/app-template/src/components/quantity-selector.tsx +215 -0
  148. package/app-template/src/components/route-handler.tsx +50 -0
  149. package/app-template/src/components/select.tsx +86 -54
  150. package/app-template/src/components/shimmer.tsx +1 -1
  151. package/app-template/src/components/types/index.ts +51 -1
  152. package/app-template/src/components/widget-content.tsx +323 -0
  153. package/app-template/src/data/server/theme.ts +70 -0
  154. package/app-template/src/hooks/use-fav-button.tsx +9 -10
  155. package/app-template/src/hooks/use-product-cart.ts +80 -0
  156. package/app-template/src/hooks/use-stock-alert.ts +74 -0
  157. package/app-template/src/hooks/use-theme-settings.ts +42 -0
  158. package/app-template/src/lib/fonts.ts +149 -0
  159. package/app-template/src/plugins.js +12 -2
  160. package/app-template/src/{middleware.ts → proxy.ts} +3 -3
  161. package/app-template/src/redux/middlewares/category.ts +5 -4
  162. package/app-template/src/redux/store.ts +21 -1
  163. package/app-template/src/routes/index.ts +8 -7
  164. package/app-template/src/settings.js +6 -3
  165. package/app-template/src/types/hookform-resolvers-yup.d.ts +28 -0
  166. package/app-template/src/types/index.ts +74 -3
  167. package/app-template/src/types/next-auth.d.ts +2 -2
  168. package/app-template/src/types/widget.ts +169 -0
  169. package/app-template/src/utils/__tests__/theme-page-context.test.ts +145 -0
  170. package/app-template/src/utils/formatDate.ts +48 -0
  171. package/app-template/src/utils/styles.ts +71 -0
  172. package/app-template/src/utils/theme-page-context.ts +309 -0
  173. package/app-template/src/utils/variant-validation.ts +41 -0
  174. package/app-template/src/views/account/address-form.tsx +8 -4
  175. package/app-template/src/views/account/contact-form.tsx +148 -131
  176. package/app-template/src/views/account/content-header.tsx +4 -3
  177. package/app-template/src/views/account/faq/faq-tabs.tsx +8 -2
  178. package/app-template/src/views/account/favorite-item.tsx +1 -1
  179. package/app-template/src/views/account/order.tsx +11 -9
  180. package/app-template/src/views/account/orders/order-cancellation-item.tsx +1 -1
  181. package/app-template/src/views/account/orders/order-detail-header.tsx +1 -1
  182. package/app-template/src/views/anonymous-tracking/order-detail/index.tsx +45 -38
  183. package/app-template/src/views/basket/basket-item.tsx +6 -1
  184. package/app-template/src/views/basket/summary.tsx +16 -0
  185. package/app-template/src/views/breadcrumb.tsx +2 -2
  186. package/app-template/src/views/category/category-banner.tsx +4 -23
  187. package/app-template/src/views/category/category-info.tsx +2 -1
  188. package/app-template/src/views/category/filters/filter-item.tsx +138 -42
  189. package/app-template/src/views/category/filters/index.tsx +1 -1
  190. package/app-template/src/views/category/layout.tsx +1 -0
  191. package/app-template/src/views/checkout/auth.tsx +64 -40
  192. package/app-template/src/views/checkout/layout/header.tsx +10 -6
  193. package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +22 -6
  194. package/app-template/src/views/checkout/steps/payment/options/funds-transfer.tsx +25 -5
  195. package/app-template/src/views/checkout/steps/payment/options/loyalty.tsx +21 -2
  196. package/app-template/src/views/checkout/steps/payment/options/redirection.tsx +27 -5
  197. package/app-template/src/views/checkout/steps/payment/options/store-credit.tsx +464 -0
  198. package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +4 -4
  199. package/app-template/src/views/checkout/steps/shipping/address-box.tsx +33 -20
  200. package/app-template/src/views/checkout/steps/shipping/addresses.tsx +2 -2
  201. package/app-template/src/views/checkout/summary.tsx +12 -2
  202. package/app-template/src/views/find-in-store/index.tsx +2 -2
  203. package/app-template/src/views/guest-login/index.tsx +62 -58
  204. package/app-template/src/views/header/action-menu.tsx +1 -1
  205. package/app-template/src/views/header/band.tsx +2 -2
  206. package/app-template/src/views/header/index.tsx +1 -1
  207. package/app-template/src/views/header/mini-basket.tsx +3 -3
  208. package/app-template/src/views/header/mobile-hamburger-button.tsx +5 -8
  209. package/app-template/src/views/header/mobile-menu.tsx +18 -6
  210. package/app-template/src/views/header/navbar.tsx +1 -1
  211. package/app-template/src/views/header/pwa-back-button.tsx +1 -1
  212. package/app-template/src/views/header/search/index.tsx +13 -3
  213. package/app-template/src/views/header/search/results.tsx +1 -1
  214. package/app-template/src/views/header/user-menu.tsx +1 -3
  215. package/app-template/src/views/login/index.tsx +66 -57
  216. package/app-template/src/views/otp-login/index.tsx +11 -6
  217. package/app-template/src/views/product/index.ts +1 -0
  218. package/app-template/src/views/product/layout.tsx +26 -6
  219. package/app-template/src/views/product/price-wrapper.tsx +3 -24
  220. package/app-template/src/views/product/product-actions.tsx +165 -0
  221. package/app-template/src/views/product/product-info.tsx +76 -238
  222. package/app-template/src/views/product/product-share.tsx +58 -0
  223. package/app-template/src/views/product/product-variants.tsx +26 -0
  224. package/app-template/src/views/product/slider.tsx +22 -1
  225. package/app-template/src/views/product/variant.tsx +69 -41
  226. package/app-template/src/views/product-pointer-banner-item.tsx +1 -1
  227. package/app-template/src/views/register/index.tsx +31 -46
  228. package/app-template/src/views/sales-contract-modal/index.tsx +17 -17
  229. package/app-template/src/views/share/index.tsx +9 -6
  230. package/app-template/src/views/widgets/home-hero-slider-content.tsx +41 -39
  231. package/app-template/src/widgets/flatpages/about-us/index.tsx +78 -0
  232. package/app-template/src/widgets/flatpages/blog-list/index.tsx +129 -0
  233. package/app-template/src/widgets/footer-info.tsx +1 -1
  234. package/app-template/src/widgets/footer-menu.tsx +7 -3
  235. package/app-template/src/widgets/footer-subscription/footer-subscription-form.tsx +17 -14
  236. package/app-template/src/widgets/footer-subscription/index.tsx +1 -1
  237. package/app-template/src/widgets/home-stories-eng.tsx +43 -35
  238. package/app-template/src/widgets/index.ts +7 -0
  239. package/app-template/src/widgets/schemas/about-us.json +46 -0
  240. package/app-template/src/widgets/schemas/blog-list.json +37 -0
  241. package/app-template/src/widgets/schemas/blog.json +29 -0
  242. package/app-template/tailwind.config.js +155 -7
  243. package/app-template/tsconfig.json +29 -11
  244. package/codemods/migrate-auth-v5/index.js +339 -0
  245. package/codemods/migrate-auth-v5/transform.js +86 -0
  246. package/codemods/migrate-segments/index.js +591 -0
  247. package/codemods/update-tailwind-config/index.js +30 -0
  248. package/codemods/update-tailwind-config/transform.js +102 -0
  249. package/codemods/upgrade-to-2/index.js +549 -0
  250. package/commands/codemod.ts +0 -1
  251. package/commands/plugins.ts +111 -46
  252. package/dist/commands/codemod.js +0 -1
  253. package/dist/commands/plugins.js +104 -36
  254. package/package.json +3 -2
  255. package/app-template/src/app/[commerce]/[locale]/[currency]/category/[pk]/page.tsx +0 -22
  256. package/app-template/src/app/[commerce]/[locale]/[currency]/flat-page/[pk]/page.tsx +0 -20
  257. package/app-template/src/app/[commerce]/[locale]/[currency]/group-product/[pk]/page.tsx +0 -74
  258. package/app-template/src/app/[commerce]/[locale]/[currency]/list/page.tsx +0 -18
  259. package/app-template/src/app/[commerce]/[locale]/[currency]/page.tsx +0 -50
  260. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/page.tsx +0 -84
  261. package/app-template/src/app/[commerce]/[locale]/[currency]/special-page/[pk]/page.tsx +0 -27
  262. package/app-template/src/pages/api/auth/[...nextauth].ts +0 -3
  263. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/address/page.tsx +0 -0
  264. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-email/page.tsx +0 -0
  265. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-password/page.tsx +0 -0
  266. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/contact/page.tsx +0 -0
  267. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/coupons/page.tsx +0 -0
  268. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/email-verification/page.tsx +0 -0
  269. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/faq/page.tsx +0 -0
  270. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/favourite-products/page.tsx +0 -0
  271. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/my-quotations/page.tsx +0 -0
  272. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/layout.tsx +0 -0
  273. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/page.tsx +0 -0
  274. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/anonymous-tracking/page.tsx +0 -0
  275. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/oauth-login/page.tsx +0 -0
  276. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket-b2b/page.tsx +0 -0
  277. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/category/[pk]/loading.tsx +0 -0
  278. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/client-root.tsx +0 -0
  279. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/contact-us/page.tsx +0 -0
  280. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/error.tsx +0 -0
  281. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/flat-page/[pk]/loading.tsx +0 -0
  282. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/group-product/[pk]/loading.tsx +0 -0
  283. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/loading.tsx +0 -0
  284. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/list/loading.tsx +0 -0
  285. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/checkout/page.tsx +0 -0
  286. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/layout.tsx +0 -0
  287. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/special-page/[pk]/loading.tsx +0 -0
  288. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/template.tsx +0 -0
  289. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/password/reset/page.tsx +0 -0
  290. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/route.ts +0 -0
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+
3
+ import React, { useState, useEffect } from 'react';
4
+ import Share from '@theme/views/share';
5
+ import { useLocalization } from '@akinon/next/hooks';
6
+
7
+ interface ProductShareProps {
8
+ productName: string;
9
+ className?: string;
10
+ }
11
+
12
+ export const ProductShare: React.FC<ProductShareProps> = ({
13
+ productName,
14
+ className
15
+ }) => {
16
+ const { t } = useLocalization();
17
+ const [currentUrl, setCurrentUrl] = useState<string | null>(null);
18
+
19
+ useEffect(() => {
20
+ setCurrentUrl(window.location.href);
21
+ }, []);
22
+
23
+ if (!currentUrl) {
24
+ return null;
25
+ }
26
+
27
+ const shareItems = [
28
+ {
29
+ href: `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(
30
+ currentUrl
31
+ )}`,
32
+ iconName: 'facebook' as const,
33
+ iconSize: 22
34
+ },
35
+ {
36
+ href: `https://twitter.com/intent/tweet?text=${encodeURIComponent(
37
+ currentUrl
38
+ )}`,
39
+ iconName: 'twitter' as const,
40
+ iconSize: 22
41
+ },
42
+ {
43
+ href: `https://api.whatsapp.com/send?text=${productName}%20${encodeURIComponent(
44
+ currentUrl
45
+ )}`,
46
+ iconName: 'whatsapp' as const,
47
+ iconSize: 22
48
+ }
49
+ ];
50
+
51
+ return (
52
+ <Share
53
+ className={className}
54
+ buttonText={t('product.share')}
55
+ items={shareItems}
56
+ />
57
+ );
58
+ };
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { Variant } from '@theme/views/product';
3
+ import { VariantType } from '@akinon/next/types';
4
+
5
+ interface ProductVariantsProps {
6
+ variants: VariantType[];
7
+ onVariantChange: () => void;
8
+ }
9
+
10
+ export const ProductVariants: React.FC<ProductVariantsProps> = ({
11
+ variants,
12
+ onVariantChange
13
+ }) => {
14
+ return (
15
+ <div className="flex flex-col">
16
+ {variants.map((variant) => (
17
+ <Variant
18
+ key={variant.attribute_key}
19
+ {...variant}
20
+ className="mb-4"
21
+ onChange={onVariantChange}
22
+ />
23
+ ))}
24
+ </div>
25
+ );
26
+ };
@@ -7,6 +7,7 @@ import { Product } from '@akinon/next/types';
7
7
  import { Image } from '@akinon/next/components/image';
8
8
  import useFavButton from '../../hooks/use-fav-button';
9
9
  import { twMerge } from 'tailwind-merge';
10
+ import PluginModule, { Component } from '@akinon/next/components/plugin-module';
10
11
 
11
12
  type ProductSliderItem = {
12
13
  product: Product;
@@ -86,7 +87,27 @@ export default function ProductInfoSlider({ product }: ProductSliderItem) {
86
87
  </div>
87
88
 
88
89
  <div className="relative lg:col-span-5">
89
- <FavButton className="absolute right-8 top-6 z-20 sm:hidden" />
90
+ <FavButton className="absolute right-8 top-6 z-[20] sm:hidden" />
91
+
92
+ <PluginModule
93
+ component={Component.ProductImageSearchFeature}
94
+ props={{
95
+ product,
96
+ activeIndex,
97
+ showResetButton: true,
98
+ enableTextSearch: true,
99
+ isEnabled: true
100
+ }}
101
+ />
102
+
103
+ <PluginModule
104
+ component={Component.VirtualTryOnPlugin}
105
+ props={{
106
+ product,
107
+ className:
108
+ 'sm:hidden absolute bottom-[70px] right-[5px] z-[30] w-auto px-4 text-xs mt-0'
109
+ }}
110
+ />
90
111
 
91
112
  <CarouselCore
92
113
  responsive={{
@@ -4,7 +4,7 @@ import React, { useMemo, useCallback } from 'react';
4
4
  import { VariantOption, VariantType } from '@akinon/next/types';
5
5
  import { usePathname, useSearchParams } from 'next/navigation';
6
6
  import clsx from 'clsx';
7
- import { useRouter, useLocalization } from '@akinon/next/hooks';
7
+ import { useRouter } from '@akinon/next/hooks';
8
8
 
9
9
  type VariantProps = {
10
10
  className?: string;
@@ -20,7 +20,6 @@ export const Variant = ({
20
20
  onChange,
21
21
  className
22
22
  }: VariantProps) => {
23
- const { t } = useLocalization();
24
23
  const router = useRouter();
25
24
  const pathname = usePathname();
26
25
  const searchParams = useSearchParams();
@@ -30,16 +29,6 @@ export const Variant = ({
30
29
  [searchParams]
31
30
  );
32
31
 
33
- const hasSelected = useMemo(
34
- () => options.some((option) => option.is_selected),
35
- [options]
36
- );
37
-
38
- const selectedVariant = useMemo(
39
- () => options.find((option) => option.is_selected),
40
- [options]
41
- );
42
-
43
32
  const handleClick = useCallback(
44
33
  (option: VariantOption) => {
45
34
  if (onChange) {
@@ -54,44 +43,83 @@ export const Variant = ({
54
43
  [onChange, preventDefaultClick, params, attribute_key, pathname, router]
55
44
  );
56
45
 
46
+ // Base button classes that don't change with theme editor
47
+ const baseButtonClasses = 'transition-colors duration-200 tracking-[0.39px]';
48
+
57
49
  return (
58
50
  <div
59
- className={clsx('flex flex-col gap-2', className)}
51
+ className={clsx('flex flex-col gap-2.5', className)}
60
52
  data-testid={`product-variant-${attribute_name}`}
61
53
  >
62
- <p className="flex gap-2 text-xs leading-4">
63
- <span>
64
- {hasSelected
65
- ? `${t('product.selected')} ${attribute_name}:`
66
- : attribute_name}
67
- </span>
68
- {hasSelected && (
69
- <span
70
- className="font-bold"
71
- data-testid={`product-variant-${attribute_name}-value`}
72
- >
73
- {selectedVariant?.value}
74
- </span>
75
- )}
54
+ <p
55
+ style={{
56
+ fontSize: 'var(--variant-label-font-size, 13px)',
57
+ fontWeight: 'var(--variant-label-font-weight, 400)',
58
+ color: 'var(--variant-label-color, #030712)'
59
+ }}
60
+ >
61
+ <span>{attribute_name}</span>
76
62
  </p>
77
- <div className="flex gap-3 flex-wrap justify-center">
63
+
64
+ <div className="flex gap-1.5 flex-wrap">
78
65
  {options.map((option, i) => (
79
66
  <button
80
67
  key={`${i}-${option.value}`}
81
- className={clsx(
82
- 'h-10 px-4 transition-colors duration-200 text-xs',
83
- {
84
- 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground pointer-events-none':
85
- option.is_selected,
86
- 'bg-gray-200 hover:bg-gray-400':
87
- option.is_selectable && !option.is_selected,
88
- 'border border-gray-300 text-gray-600': !option.is_selectable,
89
- 'cursor-not-allowed':
90
- !option.is_selectable && !option.is_selectable_without_stock,
91
- 'border border-dashed border-black bg-white text-gray-600 overflow-hidden relative':
92
- !option.is_selectable && option.is_selected
68
+ className={clsx(baseButtonClasses, {
69
+ 'pointer-events-none': option.is_selected,
70
+ 'cursor-not-allowed':
71
+ !option.is_selectable && !option.is_selectable_without_stock
72
+ })}
73
+ style={{
74
+ fontSize: 'var(--variant-button-font-size, 13px)',
75
+ fontWeight: 'var(--variant-button-font-weight, 400)',
76
+ height: 'var(--variant-button-height, 36px)',
77
+ paddingLeft: 'var(--variant-button-padding-x, 12px)',
78
+ paddingRight: 'var(--variant-button-padding-x, 12px)',
79
+ borderRadius: 'var(--variant-button-border-radius)',
80
+ borderWidth: 'var(--variant-button-border-width, 1px)',
81
+ borderStyle: 'solid',
82
+ ...(option.is_selected
83
+ ? {
84
+ color: 'var(--variant-selected-color, #ffffff)',
85
+ backgroundColor:
86
+ 'var(--variant-selected-background-color, #030712)',
87
+ borderColor: 'var(--variant-selected-border-color, #030712)'
88
+ }
89
+ : option.is_selectable
90
+ ? {
91
+ color: 'var(--variant-button-color, #1f2937)',
92
+ backgroundColor:
93
+ 'var(--variant-button-background-color, transparent)',
94
+ borderColor: 'var(--variant-button-border-color, #9ca3af)'
95
+ }
96
+ : {
97
+ color: 'var(--variant-disabled-color, #9ca3af)',
98
+ backgroundColor:
99
+ 'var(--variant-disabled-background-color, transparent)',
100
+ borderColor: 'var(--variant-disabled-border-color, #d1d5db)'
101
+ })
102
+ }}
103
+ onMouseEnter={(e) => {
104
+ if (option.is_selectable && !option.is_selected) {
105
+ e.currentTarget.style.color =
106
+ 'var(--variant-hover-color, #ffffff)';
107
+ e.currentTarget.style.backgroundColor =
108
+ 'var(--variant-hover-background-color, #030712)';
109
+ e.currentTarget.style.borderColor =
110
+ 'var(--variant-hover-border-color, #030712)';
111
+ }
112
+ }}
113
+ onMouseLeave={(e) => {
114
+ if (option.is_selectable && !option.is_selected) {
115
+ e.currentTarget.style.color =
116
+ 'var(--variant-button-color, #1f2937)';
117
+ e.currentTarget.style.backgroundColor =
118
+ 'var(--variant-button-background-color, transparent)';
119
+ e.currentTarget.style.borderColor =
120
+ 'var(--variant-button-border-color, #9ca3af)';
93
121
  }
94
- )}
122
+ }}
95
123
  onClick={() => handleClick(option)}
96
124
  >
97
125
  {option.value}
@@ -109,7 +109,7 @@ const ProductPointerWidget = (props: ProductPointerWidgetProps) => {
109
109
  hidden: buttonStatus
110
110
  })}
111
111
  >
112
- <div className="w-full h-full flex items-center gap-2 shrink-0">
112
+ <div className="w-full h-full flex items-center gap-2 flex-shrink-0">
113
113
  <Image
114
114
  src={productItem?.kwargs?.value?.card_image?.url}
115
115
  alt={productItem?.value?.alt}
@@ -2,11 +2,11 @@
2
2
 
3
3
  import { yupResolver } from '@hookform/resolvers/yup';
4
4
  import clsx from 'clsx';
5
- import { signIn, SignInOptions } from 'next-auth/react';
5
+ import { signIn } from 'next-auth/react';
6
6
  import { useState } from 'react';
7
7
  import { SubmitHandler, useForm } from 'react-hook-form';
8
8
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
9
- import { RegisterFormType } from '@theme/types';
9
+ import { RegisterFormType, FormType, PzSignInOptions } from '@theme/types';
10
10
  import { Button, Checkbox, Icon, Input, Modal } from '@theme/components';
11
11
  import * as yup from 'yup';
12
12
  import { useCaptcha, useLocalization, useRouter } from '@akinon/next/hooks';
@@ -120,29 +120,21 @@ export const Register = () => {
120
120
  const [showPassword, setShowPassword] = useState(false);
121
121
  const { user_phone_format } = useAppSelector((state) => state.config);
122
122
 
123
- const registerHandler: SubmitHandler<RegisterFormType> = async (data) => {
123
+ const registerHandler = async (data: RegisterFormType) => {
124
124
  return await signIn('default', {
125
125
  redirect: false,
126
126
  callbackUrl: '/',
127
127
  captchaValidated,
128
- ...data
129
- } as SignInOptions);
128
+ ...data,
129
+ formType: FormType.register
130
+ } as PzSignInOptions & { redirect: false });
130
131
  };
131
132
 
132
133
  const onSubmit: SubmitHandler<RegisterFormType> = async (data) => {
133
134
  const registerResponse = await registerHandler(data);
134
135
 
135
- if (registerResponse.error === 'Captcha') {
136
- if (await validateCaptcha()) {
137
- onSubmit(data);
138
- }
139
-
140
- return;
141
- }
142
-
143
136
  if (registerResponse.error) {
144
- const errors: AuthError[] = JSON.parse(registerResponse.error);
145
-
137
+ const errors: AuthError[] = JSON.parse(registerResponse.code);
146
138
 
147
139
  if (errors.find((error) => error.type === 'captcha')) {
148
140
  if (await validateCaptcha()) {
@@ -171,25 +163,25 @@ export const Register = () => {
171
163
  try {
172
164
  parsedValue = JSON.parse(item.value);
173
165
  } catch {
174
- parsedValue = [item.value];
166
+ parsedValue = [item.value];
175
167
  }
176
168
  } else {
177
- parsedValue = item.value;
169
+ parsedValue = item.value;
178
170
  }
179
171
 
180
172
  if (Array.isArray(parsedValue)) {
181
173
  setError(item.name as keyof RegisterFormType, {
182
174
  type: 'custom',
183
- message: parsedValue.join(', '),
175
+ message: parsedValue.join(', ')
184
176
  });
185
177
  } else {
186
178
  Object.keys(parsedValue).forEach((key) => {
187
179
  const fieldName = key as keyof RegisterFormType;
188
180
  const errorMessages = parsedValue[key] as string[];
189
-
181
+
190
182
  setError(fieldName, {
191
183
  type: 'custom',
192
- message: errorMessages.join(', '),
184
+ message: errorMessages.join(', ')
193
185
  });
194
186
  });
195
187
  }
@@ -217,7 +209,7 @@ export const Register = () => {
217
209
  };
218
210
 
219
211
  return (
220
- <section className="w-full py-10 px-5 md:py-0 md:block md:px-8 md:mx-auto lg:px-16">
212
+ <section className="w-full mt-6 lg:mt-8">
221
213
  <Modal
222
214
  title={contentModal.title}
223
215
  portalId="portal-modal-container"
@@ -238,23 +230,19 @@ export const Register = () => {
238
230
  }}
239
231
  />
240
232
  )}
241
- <h2 className="mb-3 text-lg text-start text-black-800 font-light md:mb-9 md:text-2xl">
242
- {t('auth.register.title')}
243
- </h2>
244
-
245
- <p className="mb-3 text-xs leading-4 text-primary-400">
246
- {t('auth.register.subtitle')}
247
- </p>
248
-
249
233
  <form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-4">
250
- <input type="hidden" value="register" {...register('formType')} />
234
+ <input
235
+ type="hidden"
236
+ value={FormType.register}
237
+ {...register('formType')}
238
+ />
251
239
  <input type="hidden" value={locale} {...register('locale')} />
252
240
 
253
- <div className={clsx({ 'mb-4': errors.email })}>
241
+ <div>
254
242
  <Input
255
243
  labelStyle="floating"
256
244
  label={t('auth.register.form.email.placeholder')}
257
- className="h-14"
245
+ className="h-12"
258
246
  {...register('email')}
259
247
  error={errors.email}
260
248
  data-testid="register-email"
@@ -263,15 +251,13 @@ export const Register = () => {
263
251
  </div>
264
252
 
265
253
  <div
266
- className={clsx('lg:flex', {
267
- 'mb-4': errors.first_name || errors.last_name
268
- })}
254
+ className="lg:flex"
269
255
  >
270
256
  <div className="w-full lg:pr-2">
271
257
  <Input
272
258
  labelStyle="floating"
273
259
  label={t('auth.register.form.name.placeholder')}
274
- className="block h-14"
260
+ className="block h-12"
275
261
  {...register('first_name')}
276
262
  error={errors.first_name}
277
263
  data-testid="register-name"
@@ -283,7 +269,7 @@ export const Register = () => {
283
269
  <Input
284
270
  labelStyle="floating"
285
271
  label={t('auth.register.form.surname.placeholder')}
286
- className="block h-14"
272
+ className="block h-12"
287
273
  {...register('last_name')}
288
274
  error={errors.last_name}
289
275
  data-testid="register-surname"
@@ -292,12 +278,12 @@ export const Register = () => {
292
278
  </div>
293
279
  </div>
294
280
 
295
- <div className={clsx('relative', { 'mb-4': errors.password })}>
281
+ <div className="relative">
296
282
  <div className="relative">
297
283
  <Input
298
284
  labelStyle="floating"
299
285
  label={t('auth.register.form.password.placeholder')}
300
- className="h-14 pr-16"
286
+ className="h-12 pr-16"
301
287
  type={showPassword ? 'text' : 'password'}
302
288
  {...register('password')}
303
289
  data-testid="register-password"
@@ -323,11 +309,11 @@ export const Register = () => {
323
309
  />
324
310
  </div>
325
311
 
326
- <div className={clsx({ 'mb-4': errors.phone })}>
312
+ <div>
327
313
  <Input
328
314
  labelStyle="floating"
329
315
  label={t('auth.register.form.phone.placeholder')}
330
- className="h-14"
316
+ className="h-12"
331
317
  format={user_phone_format.replace(/9/g, '#')}
332
318
  allowEmptyFormatting
333
319
  mask="_"
@@ -343,7 +329,6 @@ export const Register = () => {
343
329
  <p className="mb-4">{t('auth.register.form.agreements.title')}:</p>
344
330
 
345
331
  <Checkbox
346
- className={clsx(errors.confirm ? 'mb-8' : 'mb-4')}
347
332
  {...register('confirm')}
348
333
  error={errors.confirm}
349
334
  data-testid="register-agreement-1"
@@ -362,7 +347,7 @@ export const Register = () => {
362
347
  </Checkbox>
363
348
 
364
349
  <Checkbox
365
- className={clsx(errors.kvkk_confirm ? 'mb-8' : 'mb-4')}
350
+ className="mt-4"
366
351
  {...register('kvkk_confirm')}
367
352
  error={errors.kvkk_confirm}
368
353
  data-testid="register-agreement-2"
@@ -381,7 +366,7 @@ export const Register = () => {
381
366
  </Checkbox>
382
367
 
383
368
  <Checkbox
384
- className="mb-4"
369
+ className="mt-4"
385
370
  {...register('email_allowed')}
386
371
  data-testid="register-agreement-3"
387
372
  >
@@ -399,7 +384,7 @@ export const Register = () => {
399
384
  </Checkbox>
400
385
 
401
386
  <Checkbox
402
- className="mb-4"
387
+ className="mt-4"
403
388
  {...register('sms_allowed')}
404
389
  data-testid="register-agreement-4"
405
390
  >
@@ -425,7 +410,7 @@ export const Register = () => {
425
410
  </div>
426
411
 
427
412
  <Button
428
- className="text-xs font-semibold uppercase w-full h-14"
413
+ className="w-full h-12 text-sm font-normal"
429
414
  type="submit"
430
415
  disabled={isCaptchaVisible && !captchaValidated}
431
416
  data-testid="register-submit"
@@ -169,19 +169,19 @@ export const SalesContractModal = ({ data }: Props) => {
169
169
  </div>
170
170
  </div>
171
171
 
172
- <table className="w-full border border-gray-200">
172
+ <table className="w-full border">
173
173
  <thead className="text-sm">
174
174
  <tr>
175
- <th className="border border-gray-200 font-normal text-left py-2 px-3">
175
+ <th className="border font-normal text-left py-2 px-3">
176
176
  {t('account.sales_contract.product')}
177
177
  </th>
178
- <th className="border border-gray-200 font-normal py-2 px-3">
178
+ <th className="border font-normal py-2 px-3">
179
179
  {t('account.sales_contract.quantity')}
180
180
  </th>
181
- <th className="border border-gray-200 font-normal text-left py-2 px-3">
181
+ <th className="border font-normal text-left py-2 px-3">
182
182
  {t('account.sales_contract.product_price')}
183
183
  </th>
184
- <th className="border border-gray-200 font-normal text-left py-2 px-3">
184
+ <th className="border font-normal text-left py-2 px-3">
185
185
  {t('account.sales_contract.total_price')}
186
186
  </th>
187
187
  </tr>
@@ -191,20 +191,20 @@ export const SalesContractModal = ({ data }: Props) => {
191
191
  {data.orderitem_set.map((value, index) => {
192
192
  return (
193
193
  <tr key={index.toString()}>
194
- <td className="border border-gray-200 font-light text-left py-2 px-3">
194
+ <td className="border font-light text-left py-2 px-3">
195
195
  {value.product.name}
196
196
  </td>
197
- <td className="border border-gray-200 font-light text-center py-2 px-3">
197
+ <td className="border font-light text-center py-2 px-3">
198
198
  {value.quantity ? value.quantity : '1'}
199
199
  </td>
200
- <td className="border border-gray-200 font-light text-center py-2 px-3">
200
+ <td className="border font-light text-center py-2 px-3">
201
201
  <Price
202
202
  value={
203
203
  value.unit_price ? value.unit_price : value.price
204
204
  }
205
205
  />
206
206
  </td>
207
- <td className="border border-gray-200 font-light text-right py-2 px-3">
207
+ <td className="border font-light text-right py-2 px-3">
208
208
  <Price
209
209
  value={
210
210
  value.total_amount
@@ -222,12 +222,12 @@ export const SalesContractModal = ({ data }: Props) => {
222
222
  <tr>
223
223
  <th
224
224
  colSpan={3}
225
- className="border border-gray-200 text-left py-2 px-3 font-normal"
225
+ className="border text-left py-2 px-3 font-normal"
226
226
  >
227
227
  {t('account.sales_contract.products_total')}
228
228
  </th>
229
229
  <td
230
- className="border border-gray-200 text-right py-2 px-3 font-light"
230
+ className="border text-right py-2 px-3 font-light"
231
231
  colSpan={1}
232
232
  >
233
233
  <Price value={data.discount_amount} />
@@ -237,12 +237,12 @@ export const SalesContractModal = ({ data }: Props) => {
237
237
  <tr>
238
238
  <th
239
239
  colSpan={3}
240
- className="border border-gray-200 text-left py-2 px-3 font-normal"
240
+ className="border text-left py-2 px-3 font-normal"
241
241
  >
242
242
  {t('account.sales_contract.shipping_price')}
243
243
  </th>
244
244
  <td
245
- className="border border-gray-200 text-right py-2 px-3 font-light"
245
+ className="border text-right py-2 px-3 font-light"
246
246
  colSpan={1}
247
247
  >
248
248
  <Price value={data.shipping_amount} />
@@ -252,12 +252,12 @@ export const SalesContractModal = ({ data }: Props) => {
252
252
  <tr>
253
253
  <th
254
254
  colSpan={3}
255
- className="border border-gray-200 text-left py-2 px-3 font-normal"
255
+ className="border text-left py-2 px-3 font-normal"
256
256
  >
257
257
  {t('account.sales_contract.payment_type')}
258
258
  </th>
259
259
  <td
260
- className="border border-gray-200 text-right py-2 px-3 font-light"
260
+ className="border text-right py-2 px-3 font-light"
261
261
  colSpan={1}
262
262
  >
263
263
  {data.payment_option_slug}
@@ -267,12 +267,12 @@ export const SalesContractModal = ({ data }: Props) => {
267
267
  <tr>
268
268
  <th
269
269
  colSpan={3}
270
- className="border border-gray-200 text-left py-2 px-3 font-normal"
270
+ className="border text-left py-2 px-3 font-normal"
271
271
  >
272
272
  {t('account.sales_contract.order_total')}
273
273
  </th>
274
274
  <td
275
- className="border border-gray-200 text-right py-2 px-3 font-light"
275
+ className="border text-right py-2 px-3 font-light"
276
276
  colSpan={1}
277
277
  >
278
278
  <Price value={data.amount} />
@@ -4,7 +4,7 @@ import React, { useState } from 'react';
4
4
  import { Button, Icon } from '@theme/components';
5
5
  // eslint-disable-next-line @akinon/projectzero/link-import
6
6
  import Link from 'next/link';
7
- import { ShareProps } from '@theme/components/types';
7
+ import { ShareProps } from '@theme/components/types/index';
8
8
  import clsx from 'clsx';
9
9
 
10
10
  const Share = ({
@@ -13,18 +13,21 @@ const Share = ({
13
13
  buttonAppearance = 'ghost',
14
14
  className,
15
15
  buttonIconName = 'share',
16
- buttonIconSize = 16,
16
+ buttonIconSize = 24,
17
17
  buttonIconProps = {},
18
18
  items
19
19
  }: ShareProps) => {
20
20
  const [open, setOpen] = useState(false);
21
21
 
22
22
  return (
23
- <div className={clsx('flex items-center', className)}>
23
+ <div className={clsx('flex items-center gap-4 border-t', className)}>
24
24
  <Button
25
25
  onClick={() => setOpen(!open)}
26
26
  appearance={buttonAppearance}
27
- className={clsx('text-base', buttonClassName)}
27
+ className={clsx(
28
+ 'text-base p-0 bg-transparent hover:bg-transparent hover:text-primary',
29
+ buttonClassName
30
+ )}
28
31
  aria-label="Share"
29
32
  >
30
33
  <div className="flex items-center gap-2">
@@ -53,12 +56,12 @@ const Share = ({
53
56
  className={
54
57
  item.className
55
58
  ? item.className
56
- : 'px-6 py-2 h-10 flex items-center hover:bg-gray-100'
59
+ : 'p-4 h-auto flex items-center hover:bg-gray-100'
57
60
  }
58
61
  >
59
62
  <Icon
60
63
  name={item.iconName}
61
- size={item.iconSize ? item.iconSize : 16}
64
+ size={item.iconSize ? item.iconSize : 12}
62
65
  />
63
66
  </Link>
64
67
  </div>