@akinon/projectzero 2.0.0-beta.2 → 2.0.0-beta.21

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 (300) hide show
  1. package/CHANGELOG.md +155 -6
  2. package/app-template/.env.example +8 -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 +5 -0
  10. package/app-template/AGENTS.md +7 -0
  11. package/app-template/CHANGELOG.md +1783 -61
  12. package/app-template/Procfile +1 -1
  13. package/app-template/README.md +6 -0
  14. package/app-template/akinon.json +1 -4
  15. package/app-template/build.sh +10 -0
  16. package/app-template/config/prebuild-tests.json +5 -0
  17. package/app-template/docs/advanced-usage.md +111 -0
  18. package/app-template/docs/plugins.md +60 -25
  19. package/app-template/docs/sentry-usage.md +35 -0
  20. package/app-template/jest.config.ts +2 -2
  21. package/app-template/next-env.d.ts +1 -0
  22. package/app-template/next.config.mjs +8 -6
  23. package/app-template/package.json +61 -50
  24. package/app-template/postcss.config.mjs +5 -0
  25. package/app-template/public/amex.svg +12 -0
  26. package/app-template/public/apple-pay.svg +16 -0
  27. package/app-template/public/assets/images/product-placeholder-1.jpg +0 -0
  28. package/app-template/public/assets/images/product-placeholder-2.jpg +0 -0
  29. package/app-template/public/assets/images/product-placeholder-3.jpg +0 -0
  30. package/app-template/public/assets/images/product-placeholder-4.jpg +0 -0
  31. package/app-template/public/google-pay.svg +16 -0
  32. package/app-template/public/locales/en/account.json +13 -4
  33. package/app-template/public/locales/en/auth.json +6 -7
  34. package/app-template/public/locales/en/basket.json +6 -6
  35. package/app-template/public/locales/en/blog.json +7 -0
  36. package/app-template/public/locales/en/category.json +3 -1
  37. package/app-template/public/locales/en/checkout.json +17 -4
  38. package/app-template/public/locales/en/common.json +71 -3
  39. package/app-template/public/locales/en/forgot_password.json +6 -7
  40. package/app-template/public/locales/en/product.json +84 -4
  41. package/app-template/public/locales/tr/account.json +13 -4
  42. package/app-template/public/locales/tr/auth.json +16 -17
  43. package/app-template/public/locales/tr/basket.json +4 -4
  44. package/app-template/public/locales/tr/blog.json +7 -0
  45. package/app-template/public/locales/tr/category.json +3 -1
  46. package/app-template/public/locales/tr/checkout.json +48 -36
  47. package/app-template/public/locales/tr/common.json +70 -2
  48. package/app-template/public/locales/tr/forgot_password.json +12 -13
  49. package/app-template/public/locales/tr/product.json +82 -0
  50. package/app-template/public/logo.svg +3 -27
  51. package/app-template/public/mastercard.svg +14 -0
  52. package/app-template/public/masterpass-javascript-sdk-web.min.js +1 -0
  53. package/app-template/public/promotion-banner.jpg +0 -0
  54. package/app-template/public/shop-pay.svg +12 -0
  55. package/app-template/public/visa.svg +12 -0
  56. package/app-template/src/__tests__/middleware-matcher.test.ts +135 -0
  57. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/[...prettyurl]/page.tsx +11 -11
  58. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/layout.tsx +4 -3
  59. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/cancellation/page.tsx +105 -13
  60. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/page.tsx +136 -52
  61. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/profile/page.tsx +2 -2
  62. package/app-template/src/app/[pz]/blog/[slug]/page.tsx +120 -0
  63. package/app-template/src/app/[pz]/category/[pk]/page.tsx +37 -0
  64. package/app-template/src/app/[pz]/error.tsx +17 -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 +1 -2
  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/page.tsx → [pz]/not-found.tsx} +5 -7
  72. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/checkout/page.tsx +7 -4
  73. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/page.tsx +6 -4
  74. package/app-template/src/app/[pz]/page.tsx +28 -0
  75. package/app-template/src/app/[pz]/pages/[slug]/page.tsx +19 -0
  76. package/app-template/src/app/[pz]/product/[pk]/page.tsx +102 -0
  77. package/app-template/src/app/[pz]/special-page/[pk]/page.tsx +35 -0
  78. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/email-set-primary/[[...id]]/page.tsx +3 -4
  79. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/registration/account-confirm-email/[[...id]]/page.tsx +3 -3
  80. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/reset/[[...id]]/page.tsx +41 -5
  81. package/app-template/src/app/[pz]/xml-sitemap/[node]/route.ts +73 -0
  82. package/app-template/src/app/api/auth/[...nextauth]/route.ts +3 -0
  83. package/app-template/src/app/api/barcode-search/route.ts +1 -0
  84. package/app-template/src/app/api/cache/route.ts +1 -1
  85. package/app-template/src/app/api/form/[...id]/route.ts +1 -7
  86. package/app-template/src/app/api/image-proxy/route.ts +1 -0
  87. package/app-template/src/app/api/logout/route.ts +1 -1
  88. package/app-template/src/app/api/product-categories/route.ts +1 -0
  89. package/app-template/src/app/api/similar-product-list/route.ts +1 -0
  90. package/app-template/src/app/api/similar-products/route.ts +1 -0
  91. package/app-template/src/app/api/theme-settings/route.ts +12 -0
  92. package/app-template/src/app/api/virtual-try-on/limited-categories/route.ts +1 -0
  93. package/app-template/src/app/api/virtual-try-on/route.ts +1 -0
  94. package/app-template/src/app/api/web-vitals/route.ts +1 -1
  95. package/app-template/src/assets/fonts/pz-icon.css +211 -49
  96. package/app-template/src/assets/fonts/pz-icon.eot +0 -0
  97. package/app-template/src/assets/fonts/pz-icon.html +486 -0
  98. package/app-template/src/assets/fonts/pz-icon.scss +373 -49
  99. package/app-template/src/assets/fonts/pz-icon.svg +215 -53
  100. package/app-template/src/assets/fonts/pz-icon.ttf +0 -0
  101. package/app-template/src/assets/fonts/pz-icon.woff +0 -0
  102. package/app-template/src/assets/fonts/pz-icon.woff2 +0 -0
  103. package/app-template/src/assets/globals.scss +37 -34
  104. package/app-template/src/assets/icons/arrow-right.svg +3 -0
  105. package/app-template/src/assets/icons/cart.svg +4 -12
  106. package/app-template/src/assets/icons/check.svg +2 -18
  107. package/app-template/src/assets/icons/chevron-down.svg +2 -7
  108. package/app-template/src/assets/icons/delete.svg +3 -0
  109. package/app-template/src/assets/icons/facebook.svg +2 -8
  110. package/app-template/src/assets/icons/fav-off.svg +5 -0
  111. package/app-template/src/assets/icons/fav-on.svg +5 -0
  112. package/app-template/src/assets/icons/filter-and-sort.svg +3 -0
  113. package/app-template/src/assets/icons/heart.svg +3 -0
  114. package/app-template/src/assets/icons/instagram.svg +2 -13
  115. package/app-template/src/assets/icons/materials.svg +3 -0
  116. package/app-template/src/assets/icons/person.svg +4 -0
  117. package/app-template/src/assets/icons/pinterest.svg +5 -11
  118. package/app-template/src/assets/icons/ruler.svg +3 -0
  119. package/app-template/src/assets/icons/search.svg +8 -11
  120. package/app-template/src/assets/icons/share.svg +2 -9
  121. package/app-template/src/assets/icons/snapchat.svg +3 -0
  122. package/app-template/src/assets/icons/tiktok.svg +3 -0
  123. package/app-template/src/assets/icons/tumblr.svg +6 -0
  124. package/app-template/src/assets/icons/twitter.svg +2 -10
  125. package/app-template/src/assets/icons/vimeo.svg +3 -0
  126. package/app-template/src/assets/icons/youtube.svg +3 -0
  127. package/app-template/src/assets/icons/zoom.svg +8 -0
  128. package/app-template/src/auth.ts +3 -0
  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 +50 -35
  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 +64 -2
  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 +8 -2
  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/tabs.tsx +2 -2
  151. package/app-template/src/components/types/index.ts +55 -2
  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/middleware.ts +1 -0
  160. package/app-template/src/plugins.js +13 -2
  161. package/app-template/src/redux/middlewares/category.ts +6 -5
  162. package/app-template/src/redux/reducers/category.ts +1 -1
  163. package/app-template/src/redux/store.ts +21 -1
  164. package/app-template/src/routes/index.ts +8 -7
  165. package/app-template/src/settings.js +5 -3
  166. package/app-template/src/types/hookform-resolvers-yup.d.ts +28 -0
  167. package/app-template/src/types/index.ts +74 -3
  168. package/app-template/src/types/next-auth.d.ts +2 -2
  169. package/app-template/src/types/widget.ts +169 -0
  170. package/app-template/src/utils/__tests__/theme-page-context.test.ts +145 -0
  171. package/app-template/src/utils/convert-facet-search-params.ts +1 -1
  172. package/app-template/src/utils/formatDate.ts +48 -0
  173. package/app-template/src/utils/styles.ts +71 -0
  174. package/app-template/src/utils/theme-page-context.ts +309 -0
  175. package/app-template/src/utils/variant-validation.ts +41 -0
  176. package/app-template/src/views/account/address-form.tsx +8 -4
  177. package/app-template/src/views/account/contact-form.tsx +148 -136
  178. package/app-template/src/views/account/content-header.tsx +2 -2
  179. package/app-template/src/views/account/faq/faq-tabs.tsx +8 -2
  180. package/app-template/src/views/account/favorite-item.tsx +1 -1
  181. package/app-template/src/views/account/order.tsx +10 -8
  182. package/app-template/src/views/account/orders/order-cancellation-item.tsx +4 -3
  183. package/app-template/src/views/account/orders/order-detail-header.tsx +1 -1
  184. package/app-template/src/views/anonymous-tracking/order-detail/index.tsx +44 -37
  185. package/app-template/src/views/basket/basket-item.tsx +7 -1
  186. package/app-template/src/views/basket/summary.tsx +16 -0
  187. package/app-template/src/views/breadcrumb.tsx +2 -2
  188. package/app-template/src/views/category/category-active-filters.tsx +1 -1
  189. package/app-template/src/views/category/category-banner.tsx +4 -23
  190. package/app-template/src/views/category/category-header.tsx +12 -6
  191. package/app-template/src/views/category/category-info.tsx +4 -3
  192. package/app-template/src/views/category/filters/filter-item.tsx +138 -42
  193. package/app-template/src/views/category/filters/index.tsx +3 -3
  194. package/app-template/src/views/category/layout.tsx +1 -0
  195. package/app-template/src/views/checkout/auth.tsx +64 -40
  196. package/app-template/src/views/checkout/layout/header.tsx +9 -5
  197. package/app-template/src/views/checkout/steps/payment/index.tsx +1 -1
  198. package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +21 -5
  199. package/app-template/src/views/checkout/steps/payment/options/funds-transfer.tsx +25 -5
  200. package/app-template/src/views/checkout/steps/payment/options/loyalty.tsx +21 -2
  201. package/app-template/src/views/checkout/steps/payment/options/redirection.tsx +27 -5
  202. package/app-template/src/views/checkout/steps/payment/options/store-credit.tsx +464 -0
  203. package/app-template/src/views/checkout/steps/shipping/address-box.tsx +30 -17
  204. package/app-template/src/views/checkout/steps/shipping/addresses.tsx +1 -1
  205. package/app-template/src/views/checkout/summary.tsx +10 -0
  206. package/app-template/src/views/find-in-store/index.tsx +2 -2
  207. package/app-template/src/views/guest-login/index.tsx +62 -58
  208. package/app-template/src/views/header/action-menu.tsx +7 -4
  209. package/app-template/src/views/header/index.tsx +1 -1
  210. package/app-template/src/views/header/mini-basket.tsx +14 -3
  211. package/app-template/src/views/header/mobile-hamburger-button.tsx +5 -8
  212. package/app-template/src/views/header/mobile-menu.tsx +12 -0
  213. package/app-template/src/views/header/search/index.tsx +23 -1
  214. package/app-template/src/views/installment-options/index.tsx +1 -1
  215. package/app-template/src/views/login/index.tsx +89 -56
  216. package/app-template/src/views/otp-login/index.tsx +23 -20
  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 +75 -237
  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 +21 -0
  225. package/app-template/src/views/product/variant.tsx +69 -41
  226. package/app-template/src/views/register/index.tsx +54 -44
  227. package/app-template/src/views/share/index.tsx +9 -6
  228. package/app-template/src/views/widgets/home-hero-slider-content.tsx +41 -39
  229. package/app-template/src/widgets/flatpages/about-us/index.tsx +78 -0
  230. package/app-template/src/widgets/flatpages/blog-list/index.tsx +129 -0
  231. package/app-template/src/widgets/footer-menu.tsx +6 -2
  232. package/app-template/src/widgets/footer-subscription/footer-subscription-form.tsx +17 -14
  233. package/app-template/src/widgets/home-stories-eng.tsx +42 -34
  234. package/app-template/src/widgets/index.ts +7 -0
  235. package/app-template/src/widgets/schemas/about-us.json +46 -0
  236. package/app-template/src/widgets/schemas/blog-list.json +37 -0
  237. package/app-template/src/widgets/schemas/blog.json +29 -0
  238. package/app-template/tailwind.config.js +19 -7
  239. package/app-template/tsconfig.json +29 -11
  240. package/codemods/migrate-segments/index.js +591 -0
  241. package/codemods/sentry-9/index.js +30 -0
  242. package/codemods/sentry-9/remove-sentry-configs.js +14 -0
  243. package/codemods/sentry-9/remove-sentry-dependency.js +25 -0
  244. package/codemods/sentry-9/replace-error-page.js +32 -0
  245. package/codemods/update-tailwind-config/index.js +30 -0
  246. package/codemods/update-tailwind-config/transform.js +102 -0
  247. package/commands/codemod.ts +17 -0
  248. package/commands/index.ts +3 -1
  249. package/commands/plugins.ts +115 -46
  250. package/dist/codemods/sentry-9/templates/error.js +14 -0
  251. package/dist/commands/codemod.js +15 -0
  252. package/dist/commands/index.js +3 -1
  253. package/dist/commands/plugins.js +108 -36
  254. package/package.json +3 -2
  255. package/app-template/postcss.config.js +0 -6
  256. package/app-template/sentry.client.config.ts +0 -16
  257. package/app-template/sentry.edge.config.ts +0 -3
  258. package/app-template/sentry.properties +0 -4
  259. package/app-template/sentry.server.config.ts +0 -3
  260. package/app-template/src/app/[commerce]/[locale]/[currency]/category/[pk]/page.tsx +0 -22
  261. package/app-template/src/app/[commerce]/[locale]/[currency]/error.tsx +0 -20
  262. package/app-template/src/app/[commerce]/[locale]/[currency]/flat-page/[pk]/page.tsx +0 -20
  263. package/app-template/src/app/[commerce]/[locale]/[currency]/group-product/[pk]/page.tsx +0 -74
  264. package/app-template/src/app/[commerce]/[locale]/[currency]/list/page.tsx +0 -18
  265. package/app-template/src/app/[commerce]/[locale]/[currency]/page.tsx +0 -50
  266. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/loading.tsx +0 -67
  267. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/page.tsx +0 -84
  268. package/app-template/src/app/[commerce]/[locale]/[currency]/special-page/[pk]/page.tsx +0 -27
  269. package/app-template/src/app/[commerce]/[locale]/[currency]/xml-sitemap/[node]/route.ts +0 -25
  270. package/app-template/src/pages/api/auth/[...nextauth].ts +0 -3
  271. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/address/page.tsx +0 -0
  272. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-email/page.tsx +0 -0
  273. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-password/page.tsx +0 -0
  274. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/contact/page.tsx +0 -0
  275. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/coupons/page.tsx +0 -0
  276. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/email-verification/page.tsx +0 -0
  277. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/faq/page.tsx +0 -0
  278. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/favourite-products/page.tsx +0 -0
  279. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/my-quotations/page.tsx +0 -0
  280. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/layout.tsx +0 -0
  281. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/page.tsx +0 -0
  282. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/page.tsx +0 -0
  283. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/address/stores/page.tsx +0 -0
  284. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/anonymous-tracking/page.tsx +0 -0
  285. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/oauth-login/page.tsx +0 -0
  286. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/page.tsx +0 -0
  287. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket/page.tsx +0 -0
  288. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket-b2b/page.tsx +0 -0
  289. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/category/[pk]/loading.tsx +0 -0
  290. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/client-root.tsx +0 -0
  291. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/contact-us/page.tsx +0 -0
  292. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/flat-page/[pk]/loading.tsx +0 -0
  293. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/group-product/[pk]/loading.tsx +0 -0
  294. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/loading.tsx +0 -0
  295. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/list/loading.tsx +0 -0
  296. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/layout.tsx +0 -0
  297. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/special-page/[pk]/loading.tsx +0 -0
  298. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/template.tsx +0 -0
  299. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/password/reset/page.tsx +0 -0
  300. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/route.ts +0 -0
@@ -0,0 +1,160 @@
1
+ 'use client';
2
+
3
+ import clsx from 'clsx';
4
+
5
+ interface ActionTooltipProps {
6
+ widgetData: {
7
+ attributes: Record<string, any>;
8
+ name: string;
9
+ template: string;
10
+ slug: string;
11
+ };
12
+ selectedWidget: any;
13
+ designMode: boolean;
14
+ onDelete?: () => void;
15
+ onMoveUp?: () => void;
16
+ onMoveDown?: () => void;
17
+ onCopy?: () => void;
18
+ }
19
+
20
+ export function ActionTooltip({
21
+ widgetData,
22
+ selectedWidget,
23
+ designMode,
24
+ onDelete,
25
+ onMoveUp,
26
+ onMoveDown,
27
+ onCopy
28
+ }: ActionTooltipProps) {
29
+ if (!widgetData?.attributes) {
30
+ return null;
31
+ }
32
+
33
+ const componentId = Object.keys(widgetData.attributes)[0];
34
+ const attributes = widgetData.attributes[componentId];
35
+
36
+ if (!attributes) {
37
+ return null;
38
+ }
39
+
40
+ const isRootContainer = !attributes.parentId;
41
+
42
+ if (isRootContainer) {
43
+ return null;
44
+ }
45
+
46
+ const isContainer = ['container'].includes(attributes.type);
47
+ const isCollectionItem = selectedWidget?.id?.includes('-');
48
+
49
+ const isSelected = isCollectionItem
50
+ ? selectedWidget?.id === componentId
51
+ : selectedWidget?.id?.split('-')[0] === componentId?.split('-')[0];
52
+
53
+ if (!designMode || !selectedWidget || !isSelected) {
54
+ return null;
55
+ }
56
+
57
+ return (
58
+ <section className="flex absolute justify-center right-[29px] mr-[4px] bottom-[-1px] z-[51] w-[73px] h-[21px] bg-[#292b2c] overflow-hidden gap-[9px]">
59
+ <button
60
+ className={clsx('bg-[#292b2c] text-white hover:opacity-80')}
61
+ onClick={onMoveUp}
62
+ >
63
+ <svg
64
+ width="9"
65
+ height="9"
66
+ viewBox="0 0 9 9"
67
+ xmlns="http://www.w3.org/2000/svg"
68
+ >
69
+ <path
70
+ d="M3.94 2.33 2.557 3.715a.546.546 0 0 1-.771-.772L4.1.628a.546.546 0 0 1 .771 0l2.315 2.314a.546.546 0 0 1-.772.772L5.031 2.33v5.626a.546.546 0 0 1-1.09 0V2.33z"
71
+ fill="#FFF"
72
+ fillRule="evenodd"
73
+ />
74
+ </svg>
75
+ </button>
76
+
77
+ <button
78
+ className={clsx(
79
+ 'bg-[#292b2c] text-white hover:opacity-80',
80
+ isContainer && 'disabled'
81
+ )}
82
+ onClick={onMoveDown}
83
+ >
84
+ <svg
85
+ width="9"
86
+ height="9"
87
+ viewBox="0 0 9 9"
88
+ xmlns="http://www.w3.org/2000/svg"
89
+ >
90
+ <path
91
+ d="M3.697 6.64 2.314 5.257a.546.546 0 0 0-.771.771l2.314 2.315a.546.546 0 0 0 .772 0l2.314-2.315a.546.546 0 0 0-.772-.771L4.788 6.64V1.014a.546.546 0 0 0-1.09 0V6.64z"
92
+ fill="#FFF"
93
+ fillRule="evenodd"
94
+ />
95
+ </svg>
96
+ </button>
97
+
98
+ <button
99
+ className="bg-[#292b2c] text-white hover:opacity-80"
100
+ onClick={onDelete}
101
+ >
102
+ <svg
103
+ width="8"
104
+ height="8"
105
+ viewBox="0 0 8 8"
106
+ xmlns="http://www.w3.org/2000/svg"
107
+ >
108
+ <path
109
+ d="M6.8986356,1.49777209 L5.4463047,1.49777209 L5.4463047,1.089312 C5.4463047,0.499342458 4.94696224,0 4.3569927,0 L2.9046618,0 C2.31469226,0 1.8153498,0.499342458 1.8153498,1.089312 L1.8153498,1.49777209 L0.363018903,1.49777209 C0.181509452,1.49777209 0,1.63384035 0,1.86079099 C0,2.08774162 0.181509452,2.17836871 0.363018903,2.17836871 L0.771478991,2.17836871 L0.771478991,6.9438215 C0.771478991,7.53379103 1.27082145,7.98769231 1.86079099,7.98769231 L5.4914906,7.98769231 C6.08146013,7.98769231 6.53536141,7.48834985 6.53536141,6.9438215 L6.53536141,2.17836871 L6.9438215,2.17836871 C7.12533095,2.17836871 7.3068404,2.04230044 7.3068404,1.8153498 C7.3068404,1.58839917 7.07988976,1.49777209 6.89838031,1.49777209 L6.8986356,1.49777209 Z M2.5416429,1.089312 C2.5416429,0.862361361 2.72315235,0.680851909 2.95010299,0.680851909 L4.40243389,0.680851909 C4.62938452,0.680851909 4.81089397,0.862361361 4.81089397,1.089312 L4.81089397,1.49777209 L2.5416429,1.49777209 L2.5416429,1.089312 L2.5416429,1.089312 Z M5.8093236,6.8986356 C5.8093236,7.12558623 5.62781415,7.2616545 5.4463047,7.2616545 L1.81560509,7.2616545 C1.58865445,7.2616545 1.407145,7.08014505 1.407145,6.8986356 L1.407145,2.17862399 L5.8093236,2.17862399 L5.8093236,6.8986356 Z M2.9046618,3.31312189 C2.72315235,3.31312189 2.5416429,3.44919016 2.5416429,3.67614079 L2.5416429,5.8093236 C2.5416429,5.99083305 2.67771116,6.1723425 2.9046618,6.1723425 C3.13161244,6.1723425 3.2676807,6.03627424 3.2676807,5.8093236 L3.2676807,3.63095489 C3.2676807,3.44944544 3.08617125,3.31337718 2.9046618,3.31337718 L2.9046618,3.31312189 Z M4.3569927,3.31312189 C4.17548325,3.31312189 3.9939738,3.44919016 3.9939738,3.63069961 L3.9939738,5.80906831 C3.9939738,5.99057777 4.13004206,6.17208722 4.3569927,6.17208722 C4.58394334,6.17208722 4.7200116,6.03601895 4.7200116,5.80906831 L4.7200116,3.63069961 C4.67457042,3.44919016 4.53850215,3.31312189 4.3569927,3.31312189 Z"
110
+ fill="#FFF"
111
+ fillRule="evenodd"
112
+ />
113
+ </svg>
114
+ </button>
115
+
116
+ <button
117
+ className="bg-[#292b2c] text-white hover:opacity-80"
118
+ onClick={onCopy}
119
+ >
120
+ <svg
121
+ width="8px"
122
+ height="10px"
123
+ viewBox="0 0 8 10"
124
+ version="1.1"
125
+ xmlns="http://www.w3.org/2000/svg"
126
+ >
127
+ <g
128
+ id="dynamic-widget"
129
+ stroke="none"
130
+ strokeWidth="1"
131
+ fill="none"
132
+ fillRule="evenodd"
133
+ >
134
+ <g
135
+ id="dynamic-widget---02"
136
+ transform="translate(-543, -615)"
137
+ fill="#FFFFFF"
138
+ fillRule="nonzero"
139
+ stroke="#FFFFFF"
140
+ strokeWidth="0.307692308"
141
+ >
142
+ <g id="Grou5" transform="translate(484, 610)">
143
+ <g id="Group-5" transform="translate(59.6154, 6)">
144
+ <path
145
+ d="M4.35136402,1.39920627 L0.632480235,1.39920627 C0.283491141,1.39920627 0,1.68269742 0,2.03168651 L0,7.36751977 C0,7.71650886 0.283491141,8 0.632480235,8 L4.35136402,8 C4.70035311,8 4.98384425,7.71650886 4.98384425,7.36751977 L4.98384425,2.03168651 C4.98209431,1.68269742 4.69885316,1.39920627 4.35136402,1.39920627 Z M4.53985813,7.36576982 C4.53985813,7.47051655 4.45461079,7.55576388 4.34986407,7.55576388 L0.630980282,7.55576388 C0.526233555,7.55576388 0.440986219,7.47051655 0.440986219,7.36576982 L0.440986219,2.03143652 C0.440986219,1.92668979 0.526233555,1.84144245 0.630980282,1.84144245 L4.34986407,1.84144245 C4.45461079,1.84144245 4.53985813,1.92668979 4.53985813,2.03143652 L4.53985813,7.36576982 Z"
146
+ id="Shape"
147
+ ></path>
148
+ <path
149
+ d="M5.77331958,0 L2.0544358,0 C1.7054467,0 1.42195556,0.283491141 1.42195556,0.632480235 C1.42195556,0.755226399 1.52020249,0.853723321 1.64319865,0.853723321 C1.76619481,0.853723321 1.86444174,0.755476391 1.86444174,0.632480235 C1.86444174,0.527733508 1.94968907,0.442486172 2.0544358,0.442486172 L5.77331958,0.442486172 C5.87806631,0.442486172 5.96331365,0.527733508 5.96331365,0.632480235 L5.96331365,5.96831349 C5.96331365,6.07306022 5.87806631,6.15830755 5.77331958,6.15830755 C5.65057342,6.15830755 5.5520765,6.25655448 5.5520765,6.37955064 C5.5520765,6.5025468 5.65032343,6.60079373 5.77331958,6.60079373 C6.12230868,6.60079373 6.40579982,6.31730258 6.40579982,5.96831349 L6.40579982,0.632480235 C6.40579982,0.283491141 6.12230868,0 5.77331958,0 Z"
150
+ id="Path"
151
+ ></path>
152
+ </g>
153
+ </g>
154
+ </g>
155
+ </g>
156
+ </svg>
157
+ </button>
158
+ </section>
159
+ );
160
+ }
@@ -1,46 +1,61 @@
1
1
  'use client';
2
2
 
3
+ import { Link } from '@theme/components';
3
4
  import { ButtonProps } from '@theme/components/types';
4
5
  import clsx from 'clsx';
5
6
  import { twMerge } from 'tailwind-merge';
6
7
 
7
8
  export const Button = (props: ButtonProps) => {
8
- return (
9
- <button
10
- {...props}
11
- className={twMerge(
12
- clsx(
13
- [
14
- 'px-4',
15
- 'h-10',
16
- 'text-xs',
17
- 'bg-primary',
18
- 'text-primary-foreground',
19
- 'border',
20
- 'border-primary',
21
- 'transition-all',
22
- 'hover:bg-white',
23
- 'hover:border-primary',
24
- 'hover:text-primary'
25
- ],
26
- props.appearance === 'outlined' && [
27
- 'bg-transparent ',
28
- 'text-primary ',
29
- 'hover:bg-primary ',
30
- 'hover:text-primary-foreground'
31
- ],
32
- props.appearance === 'ghost' && [
33
- 'bg-transparent',
34
- 'border-transparent',
35
- 'text-primary',
36
- 'hover:bg-primary',
37
- 'hover:text-primary-foreground'
38
- ]
39
- ),
40
- props.className
41
- )}
9
+ const {
10
+ appearance = 'filled',
11
+ size = 'md',
12
+ href,
13
+ target,
14
+ children,
15
+ className,
16
+ ...rest
17
+ } = props;
18
+
19
+ const variants = {
20
+ filled:
21
+ 'bg-primary text-primary-foreground border border-primary hover:bg-white hover:border-primary hover:text-primary',
22
+ outlined:
23
+ 'bg-transparent text-primary hover:bg-primary hover:text-primary-foreground',
24
+ ghost:
25
+ 'bg-transparent border-transparent text-primary hover:bg-primary hover:text-primary-foreground',
26
+ link: 'px-0 h-auto underline underline-offset-2'
27
+ };
28
+
29
+ const sizes = {
30
+ sm: 'h-8',
31
+ md: 'h-10',
32
+ lg: 'h-12',
33
+ xl: 'h-14'
34
+ };
35
+
36
+ const buttonClasses = twMerge(
37
+ clsx(
38
+ 'px-4 text-xs transition-all duration-200',
39
+ 'inline-flex gap-2 justify-center items-center',
40
+ variants[appearance],
41
+ sizes[size],
42
+ className
43
+ ),
44
+ className
45
+ );
46
+
47
+ return props.href ? (
48
+ <Link
49
+ prefetch={false}
50
+ target={target}
51
+ href={href}
52
+ className={buttonClasses}
42
53
  >
43
- {props.children}
54
+ {children}
55
+ </Link>
56
+ ) : (
57
+ <button data-testid="button" {...rest} className={buttonClasses}>
58
+ {children}
44
59
  </button>
45
60
  );
46
61
  };
@@ -1,11 +1,10 @@
1
1
  'use client';
2
2
 
3
- import { useEffect, useState } from 'react';
3
+ import { forwardRef } from 'react';
4
4
  import 'react-multi-carousel/lib/styles.css';
5
5
  import Carousel, {
6
6
  CarouselProps as BaseCarouselProps
7
7
  } from 'react-multi-carousel';
8
- import { forwardRef } from 'react';
9
8
  import { useMediaQuery } from '@akinon/next/hooks';
10
9
 
11
10
  type ContainerAspectRatioType = {
@@ -20,15 +19,9 @@ interface CarouselProps extends BaseCarouselProps {
20
19
  const CarouselCore = forwardRef<Carousel, CarouselProps>((props, ref) => {
21
20
  const { containerAspectRatio } = props;
22
21
  const matches = useMediaQuery('(min-width: 768px)');
23
- const [aspectRatio, setAspectRatio] = useState(containerAspectRatio.mobile);
24
-
25
- useEffect(() => {
26
- if (matches) {
27
- setAspectRatio(containerAspectRatio.desktop);
28
- } else {
29
- setAspectRatio(containerAspectRatio.mobile);
30
- }
31
- }, [matches, containerAspectRatio]);
22
+ const aspectRatio = matches
23
+ ? containerAspectRatio.desktop
24
+ : containerAspectRatio.mobile;
32
25
 
33
26
  return (
34
27
  <div className="w-full" style={{ aspectRatio }}>
@@ -9,6 +9,7 @@ const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {
9
9
  <label className={twMerge('flex flex-col text-xs', props.className)}>
10
10
  <div className="flex items-center">
11
11
  <input
12
+ data-testid="checkbox"
12
13
  type="checkbox"
13
14
  {...rest}
14
15
  ref={ref}
@@ -18,7 +19,7 @@ const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {
18
19
  {children && <span className="ml-2">{children}</span>}
19
20
  </div>
20
21
  {error && (
21
- <span className="mt-1 text-sm text-error">{error.message}</span>
22
+ <span className="mt-1 text-sm text-error">{String(error.message)}</span>
22
23
  )}
23
24
  </label>
24
25
  );
@@ -9,6 +9,11 @@ import { Select } from './select';
9
9
 
10
10
  interface CurrencySelectProps {
11
11
  className?: string;
12
+ showIcon?: boolean;
13
+ /** Custom SVG icon content */
14
+ customIcon?: string;
15
+ /** Label format: 'full' (US Dollar), 'symbol' ($), 'code' (USD) */
16
+ labelFormat?: 'full' | 'symbol' | 'code';
12
17
  }
13
18
 
14
19
  export const CurrencySelect = (props: CurrencySelectProps) => {
@@ -17,6 +22,98 @@ export const CurrencySelect = (props: CurrencySelectProps) => {
17
22
  const { t, currency, setCurrency } = useLocalization();
18
23
  const { currencies } = settings.localization;
19
24
 
25
+ // Currency symbol map for common currencies
26
+ const currencySymbolMap: Record<string, string> = {
27
+ usd: '$',
28
+ eur: '€',
29
+ gbp: '£',
30
+ try: '₺',
31
+ jpy: '¥',
32
+ cny: '¥',
33
+ krw: '₩',
34
+ inr: '₹',
35
+ rub: '₽',
36
+ brl: 'R$',
37
+ aud: 'A$',
38
+ cad: 'C$',
39
+ chf: 'CHF',
40
+ sek: 'kr',
41
+ nok: 'kr',
42
+ dkk: 'kr',
43
+ pln: 'zł',
44
+ mxn: '$',
45
+ sgd: 'S$',
46
+ hkd: 'HK$',
47
+ nzd: 'NZ$',
48
+ zar: 'R',
49
+ aed: 'د.إ',
50
+ sar: '﷼',
51
+ thb: '฿',
52
+ myr: 'RM',
53
+ php: '₱',
54
+ idr: 'Rp',
55
+ vnd: '₫',
56
+ egp: 'E£',
57
+ ngn: '₦',
58
+ pkr: '₨',
59
+ bdt: '৳',
60
+ cop: '$',
61
+ ars: '$',
62
+ clp: '$',
63
+ pen: 'S/',
64
+ ils: '₪',
65
+ kwd: 'د.ك',
66
+ qar: '﷼',
67
+ bhd: '.د.ب',
68
+ omr: '﷼'
69
+ };
70
+
71
+ // Currency full name map for common currencies
72
+ const currencyNameMap: Record<string, string> = {
73
+ usd: 'US Dollar',
74
+ eur: 'Euro',
75
+ gbp: 'British Pound',
76
+ try: 'Turkish Lira',
77
+ jpy: 'Japanese Yen',
78
+ cny: 'Chinese Yuan',
79
+ krw: 'South Korean Won',
80
+ inr: 'Indian Rupee',
81
+ rub: 'Russian Ruble',
82
+ brl: 'Brazilian Real',
83
+ aud: 'Australian Dollar',
84
+ cad: 'Canadian Dollar',
85
+ chf: 'Swiss Franc',
86
+ sek: 'Swedish Krona',
87
+ nok: 'Norwegian Krone',
88
+ dkk: 'Danish Krone',
89
+ pln: 'Polish Zloty',
90
+ mxn: 'Mexican Peso',
91
+ sgd: 'Singapore Dollar',
92
+ hkd: 'Hong Kong Dollar',
93
+ nzd: 'New Zealand Dollar',
94
+ zar: 'South African Rand',
95
+ aed: 'UAE Dirham',
96
+ sar: 'Saudi Riyal',
97
+ thb: 'Thai Baht',
98
+ myr: 'Malaysian Ringgit',
99
+ php: 'Philippine Peso',
100
+ idr: 'Indonesian Rupiah',
101
+ vnd: 'Vietnamese Dong',
102
+ egp: 'Egyptian Pound',
103
+ ngn: 'Nigerian Naira',
104
+ pkr: 'Pakistani Rupee',
105
+ bdt: 'Bangladeshi Taka',
106
+ cop: 'Colombian Peso',
107
+ ars: 'Argentine Peso',
108
+ clp: 'Chilean Peso',
109
+ pen: 'Peruvian Sol',
110
+ ils: 'Israeli Shekel',
111
+ kwd: 'Kuwaiti Dinar',
112
+ qar: 'Qatari Riyal',
113
+ bhd: 'Bahraini Dinar',
114
+ omr: 'Omani Rial'
115
+ };
116
+
20
117
  const handleChange = async (e) => {
21
118
  setSelectedCurrency(e.currentTarget.value);
22
119
  setIsModalOpen(true);
@@ -26,16 +123,64 @@ export const CurrencySelect = (props: CurrencySelectProps) => {
26
123
  setCurrency(selectedCurrency);
27
124
  };
28
125
 
126
+ // Get currency symbol from map or use provided symbol
127
+ const getCurrencySymbol = (curr: { code: string; symbol?: string }) => {
128
+ if (curr.symbol) return curr.symbol;
129
+ return (
130
+ currencySymbolMap[curr.code.toLowerCase()] || curr.code.toUpperCase()
131
+ );
132
+ };
133
+
134
+ // Get currency full name from map or use provided label
135
+ const getCurrencyName = (curr: { code: string; label: string }) => {
136
+ const name = currencyNameMap[curr.code.toLowerCase()];
137
+ // If name exists in map, use it. Otherwise check if label looks like a full name (not just code)
138
+ if (name) return name;
139
+ // If label is different from code, assume it's a proper name
140
+ if (curr.label.toLowerCase() !== curr.code.toLowerCase()) return curr.label;
141
+ // Fallback to code uppercase
142
+ return curr.code.toUpperCase();
143
+ };
144
+
145
+ // Format label based on labelFormat prop
146
+ const formatLabel = (curr: {
147
+ code: string;
148
+ label: string;
149
+ symbol?: string;
150
+ }) => {
151
+ switch (props.labelFormat) {
152
+ case 'symbol':
153
+ // Return currency symbol ($, €, etc.)
154
+ return getCurrencySymbol(curr);
155
+ case 'code':
156
+ // Return currency code (USD, EUR, etc.)
157
+ return curr.code.toUpperCase();
158
+ case 'full':
159
+ default:
160
+ // Return full label (US Dollar, Euro, etc.)
161
+ return getCurrencyName(curr);
162
+ }
163
+ };
164
+
165
+ // Check if customIcon has actual SVG content
166
+ const hasValidCustomIcon =
167
+ props.customIcon &&
168
+ typeof props.customIcon === 'string' &&
169
+ props.customIcon.includes('<svg');
170
+
29
171
  return (
30
172
  <>
31
173
  <Select
32
174
  onChange={handleChange}
33
- options={currencies.map((currency) => ({
34
- value: currency.code,
35
- label: currency.label
175
+ options={currencies.map((curr) => ({
176
+ value: curr.code,
177
+ label: formatLabel(curr)
36
178
  }))}
37
179
  value={currency}
38
- icon="money"
180
+ icon={
181
+ props.showIcon !== false && !hasValidCustomIcon ? 'money' : undefined
182
+ }
183
+ customIcon={props.showIcon !== false ? props.customIcon : undefined}
39
184
  data-testid="currency"
40
185
  borderless
41
186
  className={props.className}
@@ -70,6 +215,7 @@ export const CurrencySelect = (props: CurrencySelectProps) => {
70
215
  onClick={confirmModalHandleClick}
71
216
  appearance="filled"
72
217
  className="font-medium px-10 py-4 h-12"
218
+ data-testid="currency-modal-confirm"
73
219
  >
74
220
  {t('common.currency_modal.continue')}
75
221
  </Button>
@@ -1,8 +1,70 @@
1
+ import { useState } from 'react';
1
2
  import { forwardRef } from 'react';
2
3
  import { FileInputProps } from '@theme/components/types';
4
+ import { useLocalization } from '@akinon/next/hooks';
5
+ import { twMerge } from 'tailwind-merge';
3
6
 
4
7
  export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
5
- function fileInput(props, ref) {
6
- return <input type="file" {...props} ref={ref} />;
8
+ function FileInput(
9
+ {
10
+ buttonClassName,
11
+ onChange,
12
+ fileClassName,
13
+ fileNameWrapperClassName,
14
+ fileInputClassName,
15
+ ...props
16
+ },
17
+ ref
18
+ ) {
19
+ const { t } = useLocalization();
20
+ const [fileNames, setFileNames] = useState<string[]>([]);
21
+
22
+ const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
23
+ const files = Array.from(event.target.files || []);
24
+ setFileNames(files.map((file) => file.name));
25
+
26
+ if (onChange) {
27
+ onChange(event);
28
+ }
29
+ };
30
+
31
+ return (
32
+ <div className="relative">
33
+ <input
34
+ type="file"
35
+ {...props}
36
+ ref={ref}
37
+ className={twMerge(
38
+ 'absolute inset-0 w-full h-full opacity-0 cursor-pointer',
39
+ fileInputClassName
40
+ )}
41
+ onChange={handleFileChange}
42
+ />
43
+ <button
44
+ type="button"
45
+ className={twMerge(
46
+ 'bg-primary text-white py-2 px-4 text-sm',
47
+ buttonClassName
48
+ )}
49
+ >
50
+ {t('common.file_input.select_file')}
51
+ </button>
52
+ <div
53
+ className={twMerge('mt-1 text-gray-500', fileNameWrapperClassName)}
54
+ >
55
+ {fileNames.length > 0 ? (
56
+ <ul className={twMerge('list-disc pl-4 text-xs', fileClassName)}>
57
+ {fileNames.map((name, index) => (
58
+ <li key={index}>{name}</li>
59
+ ))}
60
+ </ul>
61
+ ) : (
62
+ <span className={twMerge('text-xs', fileClassName)}>
63
+ {t('common.file_input.no_file')}
64
+ </span>
65
+ )}
66
+ </div>
67
+ </div>
68
+ );
7
69
  }
8
70
  );