includio-cms 0.25.0 → 0.27.0

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 (411) hide show
  1. package/API.md +97 -4
  2. package/CHANGELOG.md +118 -0
  3. package/DOCS.md +1 -1
  4. package/README.md +2 -0
  5. package/ROADMAP.md +14 -0
  6. package/dist/admin/auth-client.d.ts +42 -42
  7. package/dist/admin/client/account/lang.d.ts +1 -0
  8. package/dist/admin/client/account/lang.js +4 -2
  9. package/dist/admin/client/account/profile-section.svelte +2 -2
  10. package/dist/admin/client/account/security-section.svelte +27 -4
  11. package/dist/admin/client/account/sessions-section.svelte +1 -1
  12. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +1 -1
  13. package/dist/admin/client/admin/admin-layout.svelte +12 -2
  14. package/dist/admin/client/admin/admin-layout.svelte.d.ts +2 -1
  15. package/dist/admin/client/admin/dashboard-page.svelte +34 -10
  16. package/dist/admin/client/collection/bulk-actions-bar.svelte +86 -44
  17. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +3 -1
  18. package/dist/admin/client/collection/collection-entries.svelte +52 -36
  19. package/dist/admin/client/collection/collection-entries.svelte.d.ts +3 -0
  20. package/dist/admin/client/collection/collection.svelte +28 -14
  21. package/dist/admin/client/collection/collection.svelte.d.ts +3 -0
  22. package/dist/admin/client/collection/data-table.svelte +240 -130
  23. package/dist/admin/client/collection/data-table.svelte.d.ts +9 -0
  24. package/dist/admin/client/collection/date-cell.svelte +4 -4
  25. package/dist/admin/client/collection/row-actions.svelte +2 -1
  26. package/dist/admin/client/collection/sortable-header.svelte +33 -9
  27. package/dist/admin/client/collection/state-display.svelte +102 -0
  28. package/dist/admin/client/collection/state-display.svelte.d.ts +12 -0
  29. package/dist/admin/client/collection/status-badge.svelte +99 -11
  30. package/dist/admin/client/collection/status-badge.svelte.d.ts +15 -1
  31. package/dist/admin/client/collection/table-pagination.svelte +21 -6
  32. package/dist/admin/client/collection/table-toolbar.svelte +105 -80
  33. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +11 -8
  34. package/dist/admin/client/entry/entry-form.svelte +36 -11
  35. package/dist/admin/client/entry/entry-form.svelte.d.ts +1 -0
  36. package/dist/admin/client/entry/entry-header.svelte +22 -15
  37. package/dist/admin/client/entry/entry-header.svelte.d.ts +1 -0
  38. package/dist/admin/client/entry/entry.svelte +269 -165
  39. package/dist/admin/client/entry/header/a11y-header-badge.svelte +47 -0
  40. package/dist/admin/client/entry/header/a11y-header-badge.svelte.d.ts +8 -0
  41. package/dist/admin/client/entry/header/publish-panel.svelte +69 -13
  42. package/dist/admin/client/entry/header/save-indicator.svelte +57 -28
  43. package/dist/admin/client/entry/header/save-indicator.svelte.d.ts +1 -0
  44. package/dist/admin/client/entry/header/status-badge.svelte +60 -15
  45. package/dist/admin/client/entry/header/status-badge.svelte.d.ts +1 -2
  46. package/dist/admin/client/entry/header/version-history-sheet.svelte +1 -1
  47. package/dist/admin/client/entry/hybrid/hybrid-layout.svelte +74 -23
  48. package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +1 -1
  49. package/dist/admin/client/entry/utils.d.ts +14 -0
  50. package/dist/admin/client/entry/utils.js +28 -0
  51. package/dist/admin/client/form/form-submission/form-submission.svelte +2 -2
  52. package/dist/admin/client/form/form-submissions.svelte +143 -194
  53. package/dist/admin/client/form/form-submissions.svelte.d.ts +2 -0
  54. package/dist/admin/client/login/lang.d.ts +3 -0
  55. package/dist/admin/client/login/lang.js +10 -4
  56. package/dist/admin/client/login/login-form.svelte +8 -1
  57. package/dist/admin/client/login/reset-password-page.svelte +24 -3
  58. package/dist/admin/client/login/schema.d.ts +14 -2
  59. package/dist/admin/client/login/schema.js +19 -8
  60. package/dist/admin/client/maintenance/maintenance-page.svelte +16 -17
  61. package/dist/admin/client/media/media-page.svelte +1 -1
  62. package/dist/admin/client/shop/coupon-edit-page.svelte +117 -13
  63. package/dist/admin/client/shop/coupon-form.svelte +282 -138
  64. package/dist/admin/client/shop/coupon-form.svelte.d.ts +1 -9
  65. package/dist/admin/client/shop/coupon-new-page.svelte +40 -10
  66. package/dist/admin/client/shop/coupon-new-page.svelte.d.ts +2 -17
  67. package/dist/admin/client/shop/coupon-schema.d.ts +28 -0
  68. package/dist/admin/client/shop/coupon-schema.js +53 -0
  69. package/dist/admin/client/shop/coupons-list-page.svelte +262 -118
  70. package/dist/admin/client/shop/coupons-list-page.svelte.d.ts +16 -1
  71. package/dist/admin/client/shop/refund-dialog.svelte +37 -1
  72. package/dist/admin/client/shop/refund-dialog.svelte.d.ts +3 -0
  73. package/dist/admin/client/shop/shipping-method-edit-page.svelte +108 -59
  74. package/dist/admin/client/shop/shipping-method-form.svelte +36 -9
  75. package/dist/admin/client/shop/shipping-method-new-page.svelte +44 -13
  76. package/dist/admin/client/shop/shipping-methods-list-page.svelte +101 -59
  77. package/dist/admin/client/shop/shop-order-detail-page.svelte +220 -84
  78. package/dist/admin/client/shop/shop-orders-list-page.svelte +302 -152
  79. package/dist/admin/client/shop/shop-orders-list-page.svelte.d.ts +18 -1
  80. package/dist/admin/client/shop/shop-products-list-page.svelte +355 -118
  81. package/dist/admin/client/shop/shop-products-list-page.svelte.d.ts +19 -1
  82. package/dist/admin/client/users/accept-invite-page.svelte +24 -3
  83. package/dist/admin/client/users/create-user-dialog.svelte +3 -8
  84. package/dist/admin/client/users/lang.d.ts +2 -0
  85. package/dist/admin/client/users/lang.js +4 -0
  86. package/dist/admin/client/users/pending-invitations.svelte +2 -9
  87. package/dist/admin/client/users/user-name-cell.svelte +20 -0
  88. package/dist/admin/client/users/user-name-cell.svelte.d.ts +9 -0
  89. package/dist/admin/client/users/user-role-badge.svelte +16 -0
  90. package/dist/admin/client/users/user-role-badge.svelte.d.ts +7 -0
  91. package/dist/admin/client/users/user-row-actions.svelte +72 -0
  92. package/dist/admin/client/users/user-row-actions.svelte.d.ts +20 -0
  93. package/dist/admin/client/users/user-sessions-sheet.svelte +2 -11
  94. package/dist/admin/client/users/users-page.svelte +283 -497
  95. package/dist/admin/client/users/users-page.svelte.d.ts +12 -1
  96. package/dist/admin/components/dashboard/form-submissions-widget.svelte +59 -74
  97. package/dist/admin/components/dashboard/recent-activity.svelte +17 -5
  98. package/dist/admin/components/dashboard/recent-entries.svelte +19 -7
  99. package/dist/admin/components/dialogs/confirmation-dialog.svelte +105 -0
  100. package/dist/admin/components/dialogs/confirmation-dialog.svelte.d.ts +13 -0
  101. package/dist/admin/components/fields/block-picker-modal.svelte +6 -0
  102. package/dist/admin/components/fields/blocks-field.svelte +46 -1
  103. package/dist/admin/components/fields/boolean-field.svelte +1 -1
  104. package/dist/admin/components/fields/field-renderer.svelte +29 -22
  105. package/dist/admin/components/fields/file-field.svelte +344 -30
  106. package/dist/admin/components/fields/icon-field.svelte +86 -0
  107. package/dist/admin/components/fields/icon-field.svelte.d.ts +8 -0
  108. package/dist/admin/components/fields/icon-picker-dialog.svelte +174 -0
  109. package/dist/admin/components/fields/icon-picker-dialog.svelte.d.ts +11 -0
  110. package/dist/admin/components/fields/media-field.svelte +16 -2
  111. package/dist/admin/components/fields/object-field.svelte +27 -7
  112. package/dist/admin/components/fields/radio-field.svelte +22 -0
  113. package/dist/admin/components/fields/relation-field.svelte +123 -97
  114. package/dist/admin/components/fields/relation-picker-dialog.svelte +2 -2
  115. package/dist/admin/components/fields/seo-field.svelte +60 -30
  116. package/dist/admin/components/fields/shop-field.svelte +219 -24
  117. package/dist/admin/components/fields/simple-array-field.svelte +321 -151
  118. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +3 -0
  119. package/dist/admin/components/fields/slug-field.svelte +146 -21
  120. package/dist/admin/components/fields/text-field-wrapper.svelte +37 -20
  121. package/dist/admin/components/fields/text-field.svelte +7 -2
  122. package/dist/admin/components/fields/url-field-wrapper.svelte +10 -0
  123. package/dist/admin/components/fields/url-field.svelte +36 -23
  124. package/dist/admin/components/forms/form-error-summary.svelte +143 -0
  125. package/dist/admin/components/forms/form-error-summary.svelte.d.ts +27 -0
  126. package/dist/admin/components/layout/app-sidebar.svelte +7 -2
  127. package/dist/admin/components/layout/detail-page-shell.svelte +71 -0
  128. package/dist/admin/components/layout/detail-page-shell.svelte.d.ts +24 -0
  129. package/dist/admin/components/layout/lang.d.ts +5 -0
  130. package/dist/admin/components/layout/lang.js +10 -0
  131. package/dist/admin/components/layout/layout-renderer.svelte +71 -2
  132. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +1 -0
  133. package/dist/admin/components/layout/layout-tabs.svelte +173 -0
  134. package/dist/admin/components/layout/layout-tabs.svelte.d.ts +24 -0
  135. package/dist/admin/components/layout/nav-breadcrumbs.svelte +25 -7
  136. package/dist/admin/components/layout/nav-collections.svelte +23 -36
  137. package/dist/admin/components/layout/nav-forms.svelte +19 -35
  138. package/dist/admin/components/layout/nav-main.svelte +3 -28
  139. package/dist/admin/components/layout/nav-search.svelte +70 -2
  140. package/dist/admin/components/layout/nav-section.svelte +77 -0
  141. package/dist/admin/components/layout/nav-section.svelte.d.ts +22 -0
  142. package/dist/admin/components/layout/nav-shop.svelte +3 -27
  143. package/dist/admin/components/layout/nav-singletons.svelte +16 -28
  144. package/dist/admin/components/layout/page-header.stories.svelte +93 -0
  145. package/dist/admin/components/layout/page-header.stories.svelte.d.ts +27 -0
  146. package/dist/admin/components/layout/page-header.svelte +68 -0
  147. package/dist/admin/components/layout/page-header.svelte.d.ts +17 -0
  148. package/dist/admin/components/layout/site-header.svelte +9 -0
  149. package/dist/admin/components/layout/site-header.svelte.d.ts +2 -17
  150. package/dist/admin/components/media/file/file-name-input.svelte +6 -2
  151. package/dist/admin/components/media/file/file-preview.svelte +130 -17
  152. package/dist/admin/components/media/file-upload.svelte +16 -7
  153. package/dist/admin/components/media/file-upload.svelte.d.ts +1 -0
  154. package/dist/admin/components/media/files-list.svelte +153 -53
  155. package/dist/admin/components/media/files-list.svelte.d.ts +1 -0
  156. package/dist/admin/components/media/media-library.svelte +577 -198
  157. package/dist/admin/components/media/media-library.svelte.d.ts +4 -0
  158. package/dist/admin/components/media/media-selector.svelte +4 -2
  159. package/dist/admin/components/media/media-selector.svelte.d.ts +1 -0
  160. package/dist/admin/components/media/tag-sidebar.svelte +4 -4
  161. package/dist/admin/components/tiptap/FigureNodeView.svelte +10 -0
  162. package/dist/admin/components/tiptap/bubble-menu.svelte +104 -0
  163. package/dist/admin/components/tiptap/bubble-menu.svelte.d.ts +19 -0
  164. package/dist/admin/components/tiptap/content-editor.svelte +28 -24
  165. package/dist/admin/components/tiptap/editor-toolbar.svelte +7 -7
  166. package/dist/admin/components/tiptap/extensions.js +5 -1
  167. package/dist/admin/components/tiptap/image-dialog.svelte +5 -1
  168. package/dist/admin/components/tiptap/link-dialog.svelte +2 -0
  169. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -20
  170. package/dist/admin/components/tiptap/video-dialog.svelte +1 -1
  171. package/dist/admin/components/variant-form/VariantAttributeRenderer.svelte +109 -0
  172. package/dist/admin/components/variant-form/VariantAttributeRenderer.svelte.d.ts +9 -0
  173. package/dist/admin/helpers/build-icon-set-map.d.ts +8 -0
  174. package/dist/admin/helpers/build-icon-set-map.js +16 -0
  175. package/dist/admin/helpers/index.d.ts +2 -0
  176. package/dist/admin/helpers/index.js +2 -0
  177. package/dist/admin/i18n/errors.d.ts +140 -0
  178. package/dist/admin/i18n/errors.js +151 -0
  179. package/dist/admin/remote/entry.remote.d.ts +59 -4
  180. package/dist/admin/remote/entry.remote.js +239 -62
  181. package/dist/admin/remote/shop.remote.d.ts +87 -48
  182. package/dist/admin/remote/shop.remote.js +70 -8
  183. package/dist/admin/shared/password-generate.d.ts +6 -0
  184. package/dist/admin/shared/password-generate.js +40 -0
  185. package/dist/admin/shared/password-schema.d.ts +6 -0
  186. package/dist/admin/shared/password-schema.js +10 -3
  187. package/dist/admin/state/icon-sets.svelte.d.ts +9 -0
  188. package/dist/admin/state/icon-sets.svelte.js +20 -0
  189. package/dist/admin/styles/admin.css +23 -6
  190. package/dist/admin/styles/tokens.md +244 -0
  191. package/dist/admin/utils/accordionActivation.d.ts +13 -0
  192. package/dist/admin/utils/accordionActivation.js +35 -0
  193. package/dist/admin/utils/entryLabel.d.ts +23 -0
  194. package/dist/admin/utils/entryLabel.js +51 -12
  195. package/dist/admin/utils/field-a11y.d.ts +29 -0
  196. package/dist/admin/utils/field-a11y.js +23 -0
  197. package/dist/admin/utils/fieldPathElement.d.ts +9 -0
  198. package/dist/admin/utils/fieldPathElement.js +18 -0
  199. package/dist/admin/utils/fileDisplay.d.ts +10 -0
  200. package/dist/admin/utils/fileDisplay.js +26 -0
  201. package/dist/admin/utils/flattenFormErrors.d.ts +19 -0
  202. package/dist/admin/utils/flattenFormErrors.js +102 -0
  203. package/dist/admin/utils/formatters.d.ts +12 -0
  204. package/dist/admin/utils/{formatDate.js → formatters.js} +23 -2
  205. package/dist/admin/utils/scrollWithin.d.ts +9 -0
  206. package/dist/admin/utils/scrollWithin.js +32 -0
  207. package/dist/admin/utils/tabActivation.d.ts +12 -0
  208. package/dist/admin/utils/tabActivation.js +24 -0
  209. package/dist/cli/scaffold/admin.js +2 -2
  210. package/dist/cms/runtime/schema.d.ts +1 -0
  211. package/dist/cms/runtime/schema.js +1 -0
  212. package/dist/cms/runtime/types.d.ts +80 -7
  213. package/dist/components/ui/accordion/accordion-content.svelte +17 -3
  214. package/dist/components/ui/accordion/accordion.stories.svelte +21 -1
  215. package/dist/components/ui/alert/alert.stories.svelte +14 -0
  216. package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte +45 -0
  217. package/dist/components/ui/alert-dialog/alert-dialog.stories.svelte.d.ts +27 -0
  218. package/dist/components/ui/avatar/avatar.stories.svelte +27 -0
  219. package/dist/components/ui/badge/badge.stories.svelte +15 -0
  220. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +47 -0
  221. package/dist/components/ui/breadcrumb/breadcrumb.svelte +1 -1
  222. package/dist/components/ui/button/button.stories.svelte +53 -6
  223. package/dist/components/ui/button/button.svelte +39 -5
  224. package/dist/components/ui/button/button.svelte.d.ts +4 -0
  225. package/dist/components/ui/button-group/button-group.stories.svelte +44 -0
  226. package/dist/components/ui/button-group/button-group.stories.svelte.d.ts +27 -0
  227. package/dist/components/ui/calendar/calendar.stories.svelte +36 -0
  228. package/dist/components/ui/calendar/calendar.stories.svelte.d.ts +27 -0
  229. package/dist/components/ui/card/card.stories.svelte +7 -0
  230. package/dist/components/ui/carousel/carousel.stories.svelte +43 -0
  231. package/dist/components/ui/carousel/carousel.stories.svelte.d.ts +27 -0
  232. package/dist/components/ui/checkbox/checkbox.stories.svelte +67 -0
  233. package/dist/components/ui/checkbox/checkbox.stories.svelte.d.ts +27 -0
  234. package/dist/components/ui/checkbox/checkbox.svelte +1 -1
  235. package/dist/components/ui/command/command.stories.svelte +18 -0
  236. package/dist/components/ui/data-table/data-table.stories.svelte +61 -0
  237. package/dist/components/ui/data-table/data-table.stories.svelte.d.ts +18 -0
  238. package/dist/components/ui/dialog/dialog-content.svelte +5 -0
  239. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +2 -0
  240. package/dist/components/ui/dialog/dialog.stories.svelte +35 -0
  241. package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte +74 -0
  242. package/dist/components/ui/dropdown-menu/dropdown-menu.stories.svelte.d.ts +27 -0
  243. package/dist/components/ui/field/field-context.svelte.d.ts +22 -0
  244. package/dist/components/ui/field/field-context.svelte.js +9 -0
  245. package/dist/components/ui/field/field-control.svelte +18 -0
  246. package/dist/components/ui/field/field-control.svelte.d.ts +8 -0
  247. package/dist/components/ui/field/field-description.svelte +12 -0
  248. package/dist/components/ui/field/field-error.svelte +14 -6
  249. package/dist/components/ui/field/field-label.svelte +10 -0
  250. package/dist/components/ui/field/field.stories.svelte +95 -9
  251. package/dist/components/ui/field/field.svelte +57 -0
  252. package/dist/components/ui/field/field.svelte.d.ts +2 -0
  253. package/dist/components/ui/field/index.d.ts +3 -1
  254. package/dist/components/ui/field/index.js +4 -2
  255. package/dist/components/ui/form/form-field-errors.svelte +1 -1
  256. package/dist/components/ui/form/form.stories.svelte +25 -0
  257. package/dist/components/ui/form/form.stories.svelte.d.ts +26 -0
  258. package/dist/components/ui/input/input.stories.svelte +26 -0
  259. package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
  260. package/dist/components/ui/input-group/input-group.stories.svelte +43 -0
  261. package/dist/components/ui/input-group/input-group.stories.svelte.d.ts +27 -0
  262. package/dist/components/ui/item/item.stories.svelte +61 -0
  263. package/dist/components/ui/item/item.stories.svelte.d.ts +27 -0
  264. package/dist/components/ui/label/label.stories.svelte +7 -0
  265. package/dist/components/ui/live-region/index.d.ts +1 -0
  266. package/dist/components/ui/live-region/index.js +1 -0
  267. package/dist/components/ui/live-region/live-region-demo.svelte +32 -0
  268. package/dist/components/ui/live-region/live-region-demo.svelte.d.ts +7 -0
  269. package/dist/components/ui/live-region/live-region.stories.svelte +23 -0
  270. package/dist/components/ui/live-region/live-region.stories.svelte.d.ts +26 -0
  271. package/dist/components/ui/live-region/live-region.svelte +12 -0
  272. package/dist/components/ui/live-region/live-region.svelte.d.ts +8 -0
  273. package/dist/components/ui/popover/popover.stories.svelte +34 -0
  274. package/dist/components/ui/radio-group/radio-group.stories.svelte +58 -0
  275. package/dist/components/ui/radio-group/radio-group.stories.svelte.d.ts +27 -0
  276. package/dist/components/ui/resizable/resizable.stories.svelte +56 -0
  277. package/dist/components/ui/resizable/resizable.stories.svelte.d.ts +27 -0
  278. package/dist/components/ui/select/select.stories.svelte +49 -0
  279. package/dist/components/ui/separator/separator.stories.svelte +18 -0
  280. package/dist/components/ui/sheet/sheet.stories.svelte +34 -0
  281. package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
  282. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +1 -0
  283. package/dist/components/ui/sidebar/sidebar-trigger.svelte +1 -1
  284. package/dist/components/ui/sidebar/sidebar.stories.svelte +72 -0
  285. package/dist/components/ui/sidebar/sidebar.stories.svelte.d.ts +27 -0
  286. package/dist/components/ui/skeleton/skeleton.stories.svelte +39 -0
  287. package/dist/components/ui/skeleton/skeleton.stories.svelte.d.ts +27 -0
  288. package/dist/components/ui/skeleton/skeleton.svelte +6 -0
  289. package/dist/components/ui/sonner/index.d.ts +1 -1
  290. package/dist/components/ui/sonner/index.js +1 -1
  291. package/dist/components/ui/sonner/sonner.stories.svelte +7 -0
  292. package/dist/components/ui/sonner/sonner.svelte +17 -1
  293. package/dist/components/ui/sonner/sonner.svelte.d.ts +6 -0
  294. package/dist/components/ui/spinner/spinner.stories.svelte +30 -0
  295. package/dist/components/ui/spinner/spinner.stories.svelte.d.ts +27 -0
  296. package/dist/components/ui/switch/switch.stories.svelte +56 -0
  297. package/dist/components/ui/switch/switch.stories.svelte.d.ts +27 -0
  298. package/dist/components/ui/table/table-cell.svelte +1 -1
  299. package/dist/components/ui/table/table-head.svelte +1 -1
  300. package/dist/components/ui/table/table.stories.svelte +68 -0
  301. package/dist/components/ui/table/table.stories.svelte.d.ts +27 -0
  302. package/dist/components/ui/table/table.svelte +1 -1
  303. package/dist/components/ui/tabs/tabs.stories.svelte +48 -0
  304. package/dist/components/ui/tabs/tabs.stories.svelte.d.ts +27 -0
  305. package/dist/components/ui/textarea/textarea.stories.svelte +21 -0
  306. package/dist/components/ui/toggle/toggle.stories.svelte +23 -0
  307. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +43 -0
  308. package/dist/components/ui/tooltip/tooltip.stories.svelte +46 -6
  309. package/dist/core/cms.d.ts +11 -2
  310. package/dist/core/cms.js +29 -0
  311. package/dist/core/fields/fieldSchemaToTs.d.ts +7 -0
  312. package/dist/core/fields/fieldSchemaToTs.js +241 -90
  313. package/dist/core/fields/layoutUtils.d.ts +4 -1
  314. package/dist/core/fields/layoutUtils.js +41 -4
  315. package/dist/core/fields/resolveSeo.d.ts +70 -0
  316. package/dist/core/fields/resolveSeo.js +88 -0
  317. package/dist/core/fields/seoFieldDescriptor.d.ts +43 -0
  318. package/dist/core/fields/seoFieldDescriptor.js +74 -0
  319. package/dist/core/fields/slugPath.d.ts +13 -0
  320. package/dist/core/fields/slugPath.js +32 -0
  321. package/dist/core/fields/urlUtils.d.ts +8 -0
  322. package/dist/core/fields/urlUtils.js +27 -0
  323. package/dist/core/index.d.ts +1 -0
  324. package/dist/core/index.js +1 -0
  325. package/dist/core/server/entries/operations/create.js +13 -0
  326. package/dist/core/server/entries/operations/get.d.ts +7 -0
  327. package/dist/core/server/entries/operations/get.js +10 -6
  328. package/dist/core/server/entries/operations/slugUniqueness.d.ts +37 -0
  329. package/dist/core/server/entries/operations/slugUniqueness.js +116 -0
  330. package/dist/core/server/entries/operations/update.d.ts +6 -1
  331. package/dist/core/server/entries/operations/update.js +24 -1
  332. package/dist/core/server/fields/slugResolver.d.ts +3 -13
  333. package/dist/core/server/fields/slugResolver.js +8 -37
  334. package/dist/core/server/generator/fields.d.ts +2 -0
  335. package/dist/core/server/generator/fields.js +44 -18
  336. package/dist/core/server/generator/formFields.js +2 -1
  337. package/dist/core/server/generator/generator.js +6 -5
  338. package/dist/core/server/generator/utils.d.ts +1 -0
  339. package/dist/core/server/generator/utils.js +4 -0
  340. package/dist/db-postgres/schema/shop/order.d.ts +37 -1
  341. package/dist/db-postgres/schema/shop/order.js +3 -1
  342. package/dist/db-postgres/schema/shop/payment.d.ts +20 -0
  343. package/dist/db-postgres/schema/shop/payment.js +4 -1
  344. package/dist/db-postgres/schema/shop/product.d.ts +20 -0
  345. package/dist/db-postgres/schema/shop/product.js +3 -1
  346. package/dist/db-postgres/schema/shop/productVariant.d.ts +12 -2
  347. package/dist/db-postgres/schema/shop/productVariant.js +22 -0
  348. package/dist/shop/cart/types.d.ts +1 -0
  349. package/dist/shop/client/index.d.ts +54 -0
  350. package/dist/shop/client/index.js +5 -1
  351. package/dist/shop/expiry.d.ts +35 -0
  352. package/dist/shop/expiry.js +68 -0
  353. package/dist/shop/http/balance-handler.d.ts +20 -0
  354. package/dist/shop/http/balance-handler.js +91 -0
  355. package/dist/shop/http/cart-handler.js +19 -0
  356. package/dist/shop/http/checkout-handler.js +19 -1
  357. package/dist/shop/http/index.d.ts +2 -0
  358. package/dist/shop/http/index.js +2 -0
  359. package/dist/shop/http/upcoming-handler.d.ts +16 -0
  360. package/dist/shop/http/upcoming-handler.js +65 -0
  361. package/dist/shop/http/webhook-handler.js +46 -9
  362. package/dist/shop/index.d.ts +4 -1
  363. package/dist/shop/index.js +7 -1
  364. package/dist/shop/server/balance-payment.d.ts +40 -0
  365. package/dist/shop/server/balance-payment.js +140 -0
  366. package/dist/shop/server/cart-hydrate.js +2 -0
  367. package/dist/shop/server/init.d.ts +14 -0
  368. package/dist/shop/server/init.js +35 -0
  369. package/dist/shop/server/orders.d.ts +35 -0
  370. package/dist/shop/server/orders.js +155 -2
  371. package/dist/shop/server/payment-policy.d.ts +35 -0
  372. package/dist/shop/server/payment-policy.js +55 -0
  373. package/dist/shop/server/payments.d.ts +29 -0
  374. package/dist/shop/server/payments.js +64 -0
  375. package/dist/shop/server/populate.d.ts +1 -1
  376. package/dist/shop/server/refund.d.ts +17 -12
  377. package/dist/shop/server/refund.js +96 -13
  378. package/dist/shop/server/shop-data.d.ts +6 -1
  379. package/dist/shop/server/shop-data.js +44 -7
  380. package/dist/shop/template.d.ts +13 -0
  381. package/dist/shop/template.js +98 -0
  382. package/dist/shop/types.d.ts +142 -1
  383. package/dist/shop/variant-attributes.d.ts +28 -0
  384. package/dist/shop/variant-attributes.js +69 -0
  385. package/dist/sveltekit/server/handle.js +17 -0
  386. package/dist/sveltekit/server/index.d.ts +1 -0
  387. package/dist/sveltekit/server/index.js +2 -0
  388. package/dist/types/cms.d.ts +4 -3
  389. package/dist/types/cms.schema.d.ts +1 -1
  390. package/dist/types/cms.schema.js +13 -2
  391. package/dist/types/fields.d.ts +56 -2
  392. package/dist/types/index.d.ts +2 -2
  393. package/dist/types/index.js +1 -1
  394. package/dist/types/layout.d.ts +35 -2
  395. package/dist/types/plugins.d.ts +40 -0
  396. package/dist/types/plugins.js +4 -1
  397. package/dist/updates/0.26.0/index.d.ts +2 -0
  398. package/dist/updates/0.26.0/index.js +51 -0
  399. package/dist/updates/0.26.1/index.d.ts +2 -0
  400. package/dist/updates/0.26.1/index.js +19 -0
  401. package/dist/updates/0.27.0/index.d.ts +2 -0
  402. package/dist/updates/0.27.0/index.js +50 -0
  403. package/dist/updates/index.js +7 -1
  404. package/package.json +29 -7
  405. package/dist/admin/client/collection/empty-state.svelte +0 -28
  406. package/dist/admin/client/collection/empty-state.svelte.d.ts +0 -9
  407. package/dist/admin/client/form/submission-status-badge.svelte +0 -41
  408. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +0 -7
  409. package/dist/admin/components/media/file-preview.svelte +0 -51
  410. package/dist/admin/components/media/file-preview.svelte.d.ts +0 -6
  411. package/dist/admin/utils/formatDate.d.ts +0 -5
@@ -1,17 +1,16 @@
1
1
  <script lang="ts">
2
+ import { defaults, superForm } from 'sveltekit-superforms';
3
+ import { zod4, zod4Client } from 'sveltekit-superforms/adapters';
4
+ import * as Form from '../../../components/ui/form/index.js';
2
5
  import { Input } from '../../../components/ui/input/index.js';
3
6
  import { Button } from '../../../components/ui/button/index.js';
4
- import Label from '../../../components/ui/label/label.svelte';
5
-
6
- type CouponInput = {
7
- code: string;
8
- type: 'percent' | 'fixed';
9
- value: number;
10
- minOrderAmount: number | null;
11
- maxUses: number | null;
12
- expiresAt: string | null;
13
- isActive: boolean;
14
- };
7
+ import { Switch } from '../../../components/ui/switch/index.js';
8
+ import FormErrorSummary, {
9
+ type FormErrorEntry
10
+ } from '../../components/forms/form-error-summary.svelte';
11
+ import { createCouponSchema, defaultCoupon, type CouponInput } from './coupon-schema.js';
12
+ import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
13
+ import type { InterfaceLanguage } from '../../../types/languages.js';
15
14
 
16
15
  type Props = {
17
16
  initial?: Partial<CouponInput>;
@@ -20,150 +19,295 @@
20
19
  onCancel?: () => void;
21
20
  };
22
21
 
23
- let { initial, submitLabel = 'Zapisz', onSubmit, onCancel }: Props = $props();
22
+ let { initial, submitLabel, onSubmit, onCancel }: Props = $props();
24
23
 
25
- let code = $state(initial?.code ?? '');
26
- let type = $state<'percent' | 'fixed'>(initial?.type ?? 'percent');
27
- let value = $state(initial?.value != null ? String(initial.value) : '');
28
- let minOrderAmountPln = $state(
29
- initial?.minOrderAmount != null ? (initial.minOrderAmount / 100).toFixed(2) : ''
30
- );
31
- let maxUses = $state(initial?.maxUses != null ? String(initial.maxUses) : '');
32
- let expiresAt = $state(initial?.expiresAt ? initial.expiresAt.slice(0, 10) : '');
33
- let isActive = $state(initial?.isActive ?? true);
34
-
35
- let submitting = $state(false);
36
- let error = $state<string | null>(null);
37
-
38
- async function handleSubmit(e: Event) {
39
- e.preventDefault();
40
- error = null;
41
- const numValue = Number(value.replace(',', '.'));
42
- if (!Number.isFinite(numValue) || numValue <= 0) {
43
- error = 'Podaj wartość większą od zera.';
44
- return;
45
- }
46
- if (type === 'percent' && numValue > 100) {
47
- error = 'Procent nie może przekraczać 100.';
48
- return;
24
+ const interfaceLanguage = useInterfaceLanguage();
25
+
26
+ const lang: Record<
27
+ InterfaceLanguage,
28
+ {
29
+ code: string;
30
+ codeHint: string;
31
+ codePlaceholder: string;
32
+ discountType: string;
33
+ discountTypePercent: string;
34
+ discountTypeFixed: string;
35
+ value: string;
36
+ valuePercent: string;
37
+ valueFixed: string;
38
+ valuePercentPlaceholder: string;
39
+ valueFixedPlaceholder: string;
40
+ conditionsSection: string;
41
+ minOrder: string;
42
+ minOrderHint: string;
43
+ minOrderPlaceholder: string;
44
+ maxUses: string;
45
+ maxUsesPlaceholder: string;
46
+ expiresAt: string;
47
+ expiresHint: string;
48
+ statusSection: string;
49
+ isActive: string;
50
+ isActiveHint: string;
51
+ save: string;
52
+ saving: string;
53
+ cancel: string;
49
54
  }
50
- const minOrderCents = minOrderAmountPln
51
- ? Math.round(Number(minOrderAmountPln.replace(',', '.')) * 100)
52
- : null;
53
- if (minOrderCents != null && (!Number.isFinite(minOrderCents) || minOrderCents < 0)) {
54
- error = 'Minimalna wartość zamówienia musi być nieujemna.';
55
- return;
55
+ > = {
56
+ pl: {
57
+ code: 'Kod',
58
+ codeHint: 'Litery, cyfry, „_”, „-”. Wielkość liter zostanie ujednolicona do dużych.',
59
+ codePlaceholder: 'np. ARIA10',
60
+ discountType: 'Typ rabatu',
61
+ discountTypePercent: 'Procent (% od kwoty netto)',
62
+ discountTypeFixed: 'Kwota stała (PLN)',
63
+ value: 'Wartość',
64
+ valuePercent: 'Procent (0–100)',
65
+ valueFixed: 'Kwota (PLN)',
66
+ valuePercentPlaceholder: 'np. 10',
67
+ valueFixedPlaceholder: 'np. 50,00',
68
+ conditionsSection: 'Warunki',
69
+ minOrder: 'Min. wartość zamówienia (PLN)',
70
+ minOrderHint: 'Zostaw puste, jeśli rabat nie ma minimum.',
71
+ minOrderPlaceholder: 'opcjonalnie',
72
+ maxUses: 'Maks. liczba użyć',
73
+ maxUsesPlaceholder: 'bez limitu',
74
+ expiresAt: 'Data wygaśnięcia',
75
+ expiresHint: 'Zostaw puste, jeśli kod nie ma terminu.',
76
+ statusSection: 'Status',
77
+ isActive: 'Aktywny',
78
+ isActiveHint: 'Tylko aktywne kody działają w koszyku.',
79
+ save: 'Zapisz',
80
+ saving: 'Zapisuję…',
81
+ cancel: 'Anuluj'
82
+ },
83
+ en: {
84
+ code: 'Code',
85
+ codeHint: 'Letters, digits, "_", "-". Case will be normalized to uppercase.',
86
+ codePlaceholder: 'e.g. ARIA10',
87
+ discountType: 'Discount type',
88
+ discountTypePercent: 'Percent (% off net amount)',
89
+ discountTypeFixed: 'Fixed amount (PLN)',
90
+ value: 'Value',
91
+ valuePercent: 'Percent (0–100)',
92
+ valueFixed: 'Amount (PLN)',
93
+ valuePercentPlaceholder: 'e.g. 10',
94
+ valueFixedPlaceholder: 'e.g. 50.00',
95
+ conditionsSection: 'Conditions',
96
+ minOrder: 'Min. order amount (PLN)',
97
+ minOrderHint: 'Leave empty if there is no minimum.',
98
+ minOrderPlaceholder: 'optional',
99
+ maxUses: 'Max uses',
100
+ maxUsesPlaceholder: 'no limit',
101
+ expiresAt: 'Expiry date',
102
+ expiresHint: 'Leave empty if the code does not expire.',
103
+ statusSection: 'Status',
104
+ isActive: 'Active',
105
+ isActiveHint: 'Only active codes work at checkout.',
106
+ save: 'Save',
107
+ saving: 'Saving…',
108
+ cancel: 'Cancel'
56
109
  }
57
- const maxUsesNum = maxUses ? Number(maxUses) : null;
58
- if (maxUsesNum != null && (!Number.isInteger(maxUsesNum) || maxUsesNum <= 0)) {
59
- error = 'Maksymalna liczba użyć musi być dodatnią liczbą całkowitą.';
60
- return;
110
+ };
111
+
112
+ const t = $derived(lang[interfaceLanguage.current]);
113
+
114
+ const initialData: CouponInput = {
115
+ ...defaultCoupon,
116
+ ...initial
117
+ };
118
+
119
+ const schema = createCouponSchema(interfaceLanguage.current);
120
+
121
+ const form = superForm(defaults(initialData, zod4(schema)), {
122
+ validators: zod4Client(schema),
123
+ SPA: true,
124
+ resetForm: false,
125
+ onUpdate: async ({ form }) => {
126
+ if (form.valid) {
127
+ await onSubmit({
128
+ ...form.data,
129
+ code: form.data.code.trim().toUpperCase()
130
+ });
131
+ }
61
132
  }
133
+ });
62
134
 
63
- submitting = true;
64
- try {
65
- await onSubmit({
66
- code: code.trim().toUpperCase(),
67
- type,
68
- value: numValue,
69
- minOrderAmount: minOrderCents,
70
- maxUses: maxUsesNum,
71
- expiresAt: expiresAt ? new Date(expiresAt).toISOString() : null,
72
- isActive
73
- });
74
- } catch (err) {
75
- error = err instanceof Error ? err.message : 'Nie udało się zapisać.';
76
- submitting = false;
135
+ const { form: formData, errors, enhance, submitting } = form;
136
+
137
+ const summaryErrors = $derived.by<FormErrorEntry[]>(() => {
138
+ const list: FormErrorEntry[] = [];
139
+ const e = $errors as Record<string, string[] | undefined>;
140
+ const labels: Record<string, string> = {
141
+ code: t.code,
142
+ type: t.discountType,
143
+ value: t.value,
144
+ minOrderAmount: t.minOrder,
145
+ maxUses: t.maxUses,
146
+ expiresAt: t.expiresAt,
147
+ isActive: t.isActive
148
+ };
149
+ for (const [key, msgs] of Object.entries(e)) {
150
+ if (!msgs || !Array.isArray(msgs)) continue;
151
+ for (const message of msgs) {
152
+ list.push({ path: key, label: labels[key] ?? key, message });
153
+ }
77
154
  }
78
- }
155
+ return list;
156
+ });
157
+
158
+ let valueInput = $state(initialData.value === 0 ? '' : String(initialData.value));
159
+ let minOrderPlnInput = $state(
160
+ initialData.minOrderAmount != null ? (initialData.minOrderAmount / 100).toFixed(2) : ''
161
+ );
162
+ let maxUsesInput = $state(initialData.maxUses != null ? String(initialData.maxUses) : '');
163
+ let expiresInput = $state(initialData.expiresAt ? initialData.expiresAt.slice(0, 10) : '');
164
+
165
+ $effect(() => {
166
+ const num = Number(valueInput.replace(',', '.'));
167
+ $formData.value = Number.isFinite(num) ? num : 0;
168
+ });
169
+
170
+ $effect(() => {
171
+ const num = minOrderPlnInput ? Number(minOrderPlnInput.replace(',', '.')) : null;
172
+ $formData.minOrderAmount = num != null && Number.isFinite(num) ? Math.round(num * 100) : null;
173
+ });
174
+
175
+ $effect(() => {
176
+ const num = maxUsesInput ? Number(maxUsesInput) : null;
177
+ $formData.maxUses = num != null && Number.isInteger(num) ? num : null;
178
+ });
179
+
180
+ $effect(() => {
181
+ $formData.expiresAt = expiresInput ? new Date(expiresInput).toISOString() : null;
182
+ });
79
183
  </script>
80
184
 
81
- <form onsubmit={handleSubmit} class="space-y-5">
82
- <div class="space-y-2">
83
- <Label for="coupon-code">Kod</Label>
84
- <Input
85
- id="coupon-code"
86
- bind:value={code}
87
- placeholder="np. ARIA10"
88
- required
89
- pattern="[A-Za-z0-9_-]+"
90
- maxlength={64}
91
- aria-describedby="coupon-code-hint"
92
- />
93
- <p id="coupon-code-hint" class="text-muted-foreground text-xs">
94
- Wielkość liter zostanie ujednolicona do dużych liter. Tylko litery, cyfry, „_”, „-”.
95
- </p>
96
- </div>
185
+ {#snippet sectionHeader(title: string)}
186
+ <h2 class="text-lg font-bold">{title}</h2>
187
+ {/snippet}
97
188
 
98
- <fieldset class="space-y-2">
99
- <legend class="mb-1 text-sm font-semibold">Typ rabatu</legend>
100
- <label class="flex items-center gap-2 text-sm">
101
- <input type="radio" name="coupon-type" value="percent" bind:group={type} />
102
- <span>Procent (% od kwoty netto)</span>
103
- </label>
104
- <label class="flex items-center gap-2 text-sm">
105
- <input type="radio" name="coupon-type" value="fixed" bind:group={type} />
106
- <span>Kwota stała (PLN)</span>
107
- </label>
108
- </fieldset>
109
-
110
- <div class="space-y-2">
111
- <Label for="coupon-value">{type === 'percent' ? 'Procent (0–100)' : 'Kwota (PLN)'}</Label>
112
- <Input
113
- id="coupon-value"
114
- type="text"
115
- inputmode="decimal"
116
- bind:value
117
- placeholder={type === 'percent' ? 'np. 10' : 'np. 50,00'}
118
- required
119
- />
120
- </div>
189
+ <form method="POST" use:enhance class="space-y-6">
190
+ <FormErrorSummary errors={summaryErrors} />
121
191
 
122
- <div class="grid grid-cols-2 gap-4">
123
- <div class="space-y-2">
124
- <Label for="coupon-min-order">Min. wartość zamówienia (PLN)</Label>
125
- <Input
126
- id="coupon-min-order"
127
- type="text"
128
- inputmode="decimal"
129
- bind:value={minOrderAmountPln}
130
- placeholder="opcjonalnie"
131
- />
132
- </div>
133
- <div class="space-y-2">
134
- <Label for="coupon-max-uses">Maks. liczba użyć</Label>
135
- <Input
136
- id="coupon-max-uses"
137
- type="number"
138
- min="1"
139
- step="1"
140
- bind:value={maxUses}
141
- placeholder="bez limitu"
142
- />
143
- </div>
144
- </div>
192
+ <section class="border-border bg-card space-y-4 rounded-xl border p-6">
193
+ {@render sectionHeader(t.code)}
194
+ <Form.Field name="code" {form}>
195
+ <Form.Control>
196
+ {#snippet children({ props })}
197
+ <Input
198
+ {...props}
199
+ bind:value={$formData.code}
200
+ placeholder={t.codePlaceholder}
201
+ maxlength={64}
202
+ />
203
+ {/snippet}
204
+ </Form.Control>
205
+ <Form.Description>{t.codeHint}</Form.Description>
206
+ <Form.FieldErrors />
207
+ </Form.Field>
208
+ </section>
145
209
 
146
- <div class="space-y-2">
147
- <Label for="coupon-expires-at">Data wygaśnięcia</Label>
148
- <Input id="coupon-expires-at" type="date" bind:value={expiresAt} />
149
- </div>
210
+ <section class="border-border bg-card space-y-4 rounded-xl border p-6">
211
+ {@render sectionHeader(t.discountType)}
212
+ <Form.Fieldset {form} name="type" class="space-y-2">
213
+ <label class="flex items-center gap-2 text-sm">
214
+ <input type="radio" name="coupon-type" value="percent" bind:group={$formData.type} />
215
+ <span>{t.discountTypePercent}</span>
216
+ </label>
217
+ <label class="flex items-center gap-2 text-sm">
218
+ <input type="radio" name="coupon-type" value="fixed" bind:group={$formData.type} />
219
+ <span>{t.discountTypeFixed}</span>
220
+ </label>
221
+ <Form.FieldErrors />
222
+ </Form.Fieldset>
150
223
 
151
- <label class="flex items-center gap-2 text-sm">
152
- <input type="checkbox" bind:checked={isActive} />
153
- <span>Aktywny (dostępny przy checkoucie)</span>
154
- </label>
224
+ <Form.ElementField name="value" {form}>
225
+ <Form.Control>
226
+ {#snippet children({ props })}
227
+ <Form.Label>
228
+ {$formData.type === 'percent' ? t.valuePercent : t.valueFixed}
229
+ </Form.Label>
230
+ <Input
231
+ {...props}
232
+ type="text"
233
+ inputmode="decimal"
234
+ bind:value={valueInput}
235
+ placeholder={$formData.type === 'percent'
236
+ ? t.valuePercentPlaceholder
237
+ : t.valueFixedPlaceholder}
238
+ />
239
+ {/snippet}
240
+ </Form.Control>
241
+ <Form.FieldErrors />
242
+ </Form.ElementField>
243
+ </section>
155
244
 
156
- {#if error}
157
- <p class="text-destructive text-sm" role="alert">{error}</p>
158
- {/if}
245
+ <section class="border-border bg-card space-y-4 rounded-xl border p-6">
246
+ {@render sectionHeader(t.conditionsSection)}
247
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
248
+ <Form.ElementField name="minOrderAmount" {form}>
249
+ <Form.Control>
250
+ {#snippet children({ props })}
251
+ <Form.Label>{t.minOrder}</Form.Label>
252
+ <Input
253
+ {...props}
254
+ type="text"
255
+ inputmode="decimal"
256
+ bind:value={minOrderPlnInput}
257
+ placeholder={t.minOrderPlaceholder}
258
+ />
259
+ {/snippet}
260
+ </Form.Control>
261
+ <Form.Description>{t.minOrderHint}</Form.Description>
262
+ <Form.FieldErrors />
263
+ </Form.ElementField>
264
+
265
+ <Form.ElementField name="maxUses" {form}>
266
+ <Form.Control>
267
+ {#snippet children({ props })}
268
+ <Form.Label>{t.maxUses}</Form.Label>
269
+ <Input
270
+ {...props}
271
+ type="number"
272
+ min="1"
273
+ step="1"
274
+ bind:value={maxUsesInput}
275
+ placeholder={t.maxUsesPlaceholder}
276
+ />
277
+ {/snippet}
278
+ </Form.Control>
279
+ <Form.FieldErrors />
280
+ </Form.ElementField>
281
+ </div>
282
+
283
+ <Form.ElementField name="expiresAt" {form}>
284
+ <Form.Control>
285
+ {#snippet children({ props })}
286
+ <Form.Label>{t.expiresAt}</Form.Label>
287
+ <Input {...props} type="date" bind:value={expiresInput} />
288
+ {/snippet}
289
+ </Form.Control>
290
+ <Form.Description>{t.expiresHint}</Form.Description>
291
+ <Form.FieldErrors />
292
+ </Form.ElementField>
293
+ </section>
294
+
295
+ <section class="border-border bg-card space-y-4 rounded-xl border p-6">
296
+ {@render sectionHeader(t.statusSection)}
297
+ <label class="flex items-center gap-2">
298
+ <Switch bind:checked={$formData.isActive} />
299
+ <span class="text-sm">{t.isActive}</span>
300
+ </label>
301
+ <p class="text-muted-foreground text-sm">{t.isActiveHint}</p>
302
+ </section>
159
303
 
160
304
  <div class="flex gap-2">
161
- <Button type="submit" disabled={submitting}>
162
- {submitting ? 'Zapisywanie…' : submitLabel}
305
+ <Button type="submit" disabled={$submitting}>
306
+ {$submitting ? t.saving : (submitLabel ?? t.save)}
163
307
  </Button>
164
308
  {#if onCancel}
165
- <Button type="button" variant="outline" onclick={onCancel} disabled={submitting}>
166
- Anuluj
309
+ <Button type="button" variant="outline" onclick={onCancel} disabled={$submitting}>
310
+ {t.cancel}
167
311
  </Button>
168
312
  {/if}
169
313
  </div>
@@ -1,12 +1,4 @@
1
- type CouponInput = {
2
- code: string;
3
- type: 'percent' | 'fixed';
4
- value: number;
5
- minOrderAmount: number | null;
6
- maxUses: number | null;
7
- expiresAt: string | null;
8
- isActive: boolean;
9
- };
1
+ import { type CouponInput } from './coupon-schema.js';
10
2
  type Props = {
11
3
  initial?: Partial<CouponInput>;
12
4
  submitLabel?: string;
@@ -1,25 +1,55 @@
1
1
  <script lang="ts">
2
2
  import { goto } from '$app/navigation';
3
3
  import { getRemotes } from '../../../sveltekit/index.js';
4
+ import { toast } from 'svelte-sonner';
4
5
  import CouponForm from './coupon-form.svelte';
6
+ import DetailPageShell from '../../components/layout/detail-page-shell.svelte';
7
+ import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
8
+ import { getBreadcrumbs } from '../../state/breadcrumbs.svelte.js';
9
+ import { sidebarLang } from '../../components/layout/lang.js';
10
+ import type { InterfaceLanguage } from '../../../types/languages.js';
5
11
 
6
12
  const remotes = getRemotes();
7
- </script>
13
+ const interfaceLanguage = useInterfaceLanguage();
14
+ const breadcrumbs = getBreadcrumbs();
15
+
16
+ const lang: Record<
17
+ InterfaceLanguage,
18
+ { title: string; description: string; submitLabel: string; createdToast: string }
19
+ > = {
20
+ pl: {
21
+ title: 'Nowy kod rabatowy',
22
+ description: 'Skonfiguruj rabat — procent lub kwotę stałą.',
23
+ submitLabel: 'Utwórz kod',
24
+ createdToast: 'Kod utworzony.'
25
+ },
26
+ en: {
27
+ title: 'New coupon',
28
+ description: 'Configure the discount — percentage or fixed amount.',
29
+ submitLabel: 'Create coupon',
30
+ createdToast: 'Coupon created.'
31
+ }
32
+ };
33
+ const t = $derived(lang[interfaceLanguage.current]);
8
34
 
9
- <div class="mx-auto max-w-2xl space-y-6 p-6">
10
- <header>
11
- <h1 class="text-2xl font-extrabold tracking-tight">Nowy kod rabatowy</h1>
12
- <p class="text-muted-foreground text-sm">
13
- <a href="/admin/shop/coupons" class="hover:underline">← Wróć do listy</a>
14
- </p>
15
- </header>
35
+ $effect(() => {
36
+ const s = sidebarLang[interfaceLanguage.current].shop;
37
+ breadcrumbs.state = [
38
+ { label: s.title },
39
+ { label: s.coupons, href: '/admin/shop/coupons' },
40
+ { label: t.title }
41
+ ];
42
+ });
43
+ </script>
16
44
 
45
+ <DetailPageShell title={t.title} description={t.description}>
17
46
  <CouponForm
18
- submitLabel="Utwórz kod"
47
+ submitLabel={t.submitLabel}
19
48
  onSubmit={async (input) => {
20
49
  await remotes.createCouponCmd(input);
50
+ toast.success(t.createdToast);
21
51
  await goto('/admin/shop/coupons');
22
52
  }}
23
53
  onCancel={() => goto('/admin/shop/coupons')}
24
54
  />
25
- </div>
55
+ </DetailPageShell>
@@ -1,18 +1,3 @@
1
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
- $$bindings?: Bindings;
4
- } & Exports;
5
- (internal: unknown, props: {
6
- $$events?: Events;
7
- $$slots?: Slots;
8
- }): Exports & {
9
- $set?: any;
10
- $on?: any;
11
- };
12
- z_$$bindings?: Bindings;
13
- }
14
- declare const CouponNewPage: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
- [evt: string]: CustomEvent<any>;
16
- }, {}, {}, string>;
17
- type CouponNewPage = InstanceType<typeof CouponNewPage>;
1
+ declare const CouponNewPage: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type CouponNewPage = ReturnType<typeof CouponNewPage>;
18
3
  export default CouponNewPage;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @internal
3
+ * Zod schema for coupon edit form (superForm + formsnap, S8).
4
+ */
5
+ import { z } from 'zod';
6
+ import type { InterfaceLanguage } from '../../../types/languages.js';
7
+ export type CouponInput = {
8
+ code: string;
9
+ type: 'percent' | 'fixed';
10
+ value: number;
11
+ minOrderAmount: number | null;
12
+ maxUses: number | null;
13
+ expiresAt: string | null;
14
+ isActive: boolean;
15
+ };
16
+ export declare function createCouponSchema(lang?: InterfaceLanguage): z.ZodObject<{
17
+ code: z.ZodString;
18
+ type: z.ZodEnum<{
19
+ percent: "percent";
20
+ fixed: "fixed";
21
+ }>;
22
+ value: z.ZodNumber;
23
+ minOrderAmount: z.ZodNullable<z.ZodNumber>;
24
+ maxUses: z.ZodNullable<z.ZodNumber>;
25
+ expiresAt: z.ZodNullable<z.ZodString>;
26
+ isActive: z.ZodBoolean;
27
+ }, z.core.$strip>;
28
+ export declare const defaultCoupon: CouponInput;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @internal
3
+ * Zod schema for coupon edit form (superForm + formsnap, S8).
4
+ */
5
+ import { z } from 'zod';
6
+ const messages = {
7
+ pl: {
8
+ codeRequired: 'Wpisz kod, np. ARIA10.',
9
+ codeFormat: 'Kod może zawierać litery, cyfry, „_” i „-”.',
10
+ valuePositive: 'Podaj wartość większą od zera.',
11
+ percentRange: 'Procent nie może przekraczać 100.',
12
+ minOrderNonneg: 'Minimalna wartość zamówienia musi być nieujemna.',
13
+ maxUsesPositive: 'Maksymalna liczba użyć musi być dodatnia.'
14
+ },
15
+ en: {
16
+ codeRequired: 'Enter a code, e.g. ARIA10.',
17
+ codeFormat: 'Use letters, digits, "_" or "-" only.',
18
+ valuePositive: 'Enter a value greater than zero.',
19
+ percentRange: 'Percent cannot exceed 100.',
20
+ minOrderNonneg: 'Minimum order amount must be non-negative.',
21
+ maxUsesPositive: 'Maximum uses must be positive.'
22
+ }
23
+ };
24
+ export function createCouponSchema(lang = 'pl') {
25
+ const m = messages[lang];
26
+ return z
27
+ .object({
28
+ code: z
29
+ .string()
30
+ .min(1, m.codeRequired)
31
+ .max(64)
32
+ .regex(/^[A-Za-z0-9_-]+$/, m.codeFormat),
33
+ type: z.enum(['percent', 'fixed']),
34
+ value: z.number().positive(m.valuePositive),
35
+ minOrderAmount: z.number().int().nonnegative(m.minOrderNonneg).nullable(),
36
+ maxUses: z.number().int().positive(m.maxUsesPositive).nullable(),
37
+ expiresAt: z.string().nullable(),
38
+ isActive: z.boolean()
39
+ })
40
+ .refine((d) => !(d.type === 'percent' && d.value > 100), {
41
+ message: m.percentRange,
42
+ path: ['value']
43
+ });
44
+ }
45
+ export const defaultCoupon = {
46
+ code: '',
47
+ type: 'percent',
48
+ value: 10,
49
+ minOrderAmount: null,
50
+ maxUses: null,
51
+ expiresAt: null,
52
+ isActive: true
53
+ };