@vendure/dashboard 3.5.0-minor-202509261210 → 3.5.0-minor-202510031341

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 (263) hide show
  1. package/README.md +4 -0
  2. package/dist/plugin/dashboard.plugin.d.ts +25 -6
  3. package/dist/plugin/dashboard.plugin.js +184 -27
  4. package/dist/plugin/default-page.html +188 -0
  5. package/dist/vite/vite-plugin-config.js +13 -9
  6. package/dist/vite/vite-plugin-translations.d.ts +22 -0
  7. package/dist/vite/vite-plugin-translations.js +66 -0
  8. package/dist/vite/vite-plugin-vendure-dashboard.js +8 -6
  9. package/lingui.config.js +25 -2
  10. package/package.json +159 -156
  11. package/src/app/app-providers.tsx +0 -4
  12. package/src/app/common/delete-bulk-action.tsx +6 -5
  13. package/src/app/common/duplicate-bulk-action.tsx +4 -5
  14. package/src/app/common/duplicate-entity-dialog.tsx +1 -1
  15. package/src/app/common/set-document-direction.ts +7 -0
  16. package/src/app/main.tsx +50 -17
  17. package/src/app/routes/_authenticated/_administrators/administrators.tsx +8 -6
  18. package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +17 -6
  19. package/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx +2 -2
  20. package/src/app/routes/_authenticated/_assets/assets.tsx +1 -1
  21. package/src/app/routes/_authenticated/_assets/assets_.$id.tsx +4 -4
  22. package/src/app/routes/_authenticated/_assets/components/asset-bulk-actions.tsx +8 -6
  23. package/src/app/routes/_authenticated/_assets/components/asset-tag-filter.tsx +1 -1
  24. package/src/app/routes/_authenticated/_assets/components/asset-tags-editor.tsx +1 -1
  25. package/src/app/routes/_authenticated/_assets/components/manage-tags-dialog.tsx +3 -8
  26. package/src/app/routes/_authenticated/_channels/channels.tsx +3 -6
  27. package/src/app/routes/_authenticated/_channels/channels_.$id.tsx +5 -5
  28. package/src/app/routes/_authenticated/_collections/collections.tsx +3 -4
  29. package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +4 -6
  30. package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +1 -1
  31. package/src/app/routes/_authenticated/_collections/components/collection-contents-sheet.tsx +1 -1
  32. package/src/app/routes/_authenticated/_collections/components/move-collections-dialog.tsx +6 -6
  33. package/src/app/routes/_authenticated/_countries/countries.graphql.ts +2 -0
  34. package/src/app/routes/_authenticated/_countries/countries.tsx +2 -3
  35. package/src/app/routes/_authenticated/_countries/countries_.$id.tsx +4 -4
  36. package/src/app/routes/_authenticated/_customer-groups/components/customer-group-members-sheet.tsx +1 -1
  37. package/src/app/routes/_authenticated/_customer-groups/components/customer-group-members-table.tsx +4 -4
  38. package/src/app/routes/_authenticated/_customer-groups/customer-groups.tsx +2 -4
  39. package/src/app/routes/_authenticated/_customer-groups/customer-groups_.$id.tsx +13 -6
  40. package/src/app/routes/_authenticated/_customers/components/customer-address-card.tsx +8 -8
  41. package/src/app/routes/_authenticated/_customers/components/customer-address-form.tsx +3 -3
  42. package/src/app/routes/_authenticated/_customers/components/customer-history/customer-history-container.tsx +1 -1
  43. package/src/app/routes/_authenticated/_customers/components/customer-history/customer-history-utils.tsx +1 -1
  44. package/src/app/routes/_authenticated/_customers/components/customer-history/default-customer-history-components.tsx +1 -1
  45. package/src/app/routes/_authenticated/_customers/components/customer-history/use-customer-history.ts +1 -1
  46. package/src/app/routes/_authenticated/_customers/components/customer-status-badge.tsx +1 -1
  47. package/src/app/routes/_authenticated/_customers/customers.graphql.ts +4 -0
  48. package/src/app/routes/_authenticated/_customers/customers.tsx +23 -11
  49. package/src/app/routes/_authenticated/_customers/customers_.$id.tsx +10 -8
  50. package/src/app/routes/_authenticated/_facets/components/edit-facet-value.tsx +1 -1
  51. package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +6 -5
  52. package/src/app/routes/_authenticated/_facets/components/facet-values-sheet.tsx +1 -1
  53. package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +1 -1
  54. package/src/app/routes/_authenticated/_facets/facets.tsx +5 -5
  55. package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +7 -5
  56. package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +4 -4
  57. package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +5 -5
  58. package/src/app/routes/_authenticated/_orders/components/add-manual-payment-dialog.tsx +19 -21
  59. package/src/app/routes/_authenticated/_orders/components/customer-address-selector.tsx +1 -1
  60. package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +22 -22
  61. package/src/app/routes/_authenticated/_orders/components/fulfill-order-dialog.tsx +6 -6
  62. package/src/app/routes/_authenticated/_orders/components/fulfillment-details.tsx +15 -9
  63. package/src/app/routes/_authenticated/_orders/components/order-address.tsx +1 -1
  64. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +11 -9
  65. package/src/app/routes/_authenticated/_orders/components/order-history/default-order-history-components.tsx +1 -1
  66. package/src/app/routes/_authenticated/_orders/components/order-history/order-history-container.tsx +1 -1
  67. package/src/app/routes/_authenticated/_orders/components/order-history/order-history-utils.tsx +1 -1
  68. package/src/app/routes/_authenticated/_orders/components/order-history/use-order-history.ts +1 -1
  69. package/src/app/routes/_authenticated/_orders/components/order-line-custom-fields-form.tsx +1 -1
  70. package/src/app/routes/_authenticated/_orders/components/order-modification-preview-dialog.tsx +4 -4
  71. package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +1 -1
  72. package/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx +27 -27
  73. package/src/app/routes/_authenticated/_orders/components/order-table.tsx +2 -2
  74. package/src/app/routes/_authenticated/_orders/components/order-tax-summary.tsx +1 -1
  75. package/src/app/routes/_authenticated/_orders/components/payment-details.tsx +26 -20
  76. package/src/app/routes/_authenticated/_orders/components/seller-orders-card.tsx +3 -1
  77. package/src/app/routes/_authenticated/_orders/components/settle-refund-dialog.tsx +6 -6
  78. package/src/app/routes/_authenticated/_orders/components/shipping-method-selector.tsx +1 -1
  79. package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +1 -1
  80. package/src/app/routes/_authenticated/_orders/components/use-transition-order-to-state.tsx +3 -2
  81. package/src/app/routes/_authenticated/_orders/orders.tsx +5 -9
  82. package/src/app/routes/_authenticated/_orders/orders_.$aggregateOrderId_.seller-orders.$sellerOrderId.tsx +1 -1
  83. package/src/app/routes/_authenticated/_orders/orders_.$id.tsx +1 -1
  84. package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +4 -4
  85. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +17 -17
  86. package/src/app/routes/_authenticated/_orders/utils/order-detail-loaders.tsx +1 -1
  87. package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +5 -6
  88. package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +13 -6
  89. package/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx +1 -1
  90. package/src/app/routes/_authenticated/_product-variants/components/variant-price-detail.tsx +1 -1
  91. package/src/app/routes/_authenticated/_product-variants/product-variants.tsx +9 -2
  92. package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +13 -6
  93. package/src/app/routes/_authenticated/_products/components/add-option-group-dialog.tsx +5 -5
  94. package/src/app/routes/_authenticated/_products/components/add-product-variant-dialog.tsx +5 -5
  95. package/src/app/routes/_authenticated/_products/components/assign-facet-values-dialog.tsx +5 -4
  96. package/src/app/routes/_authenticated/_products/components/create-product-options-dialog.tsx +9 -12
  97. package/src/app/routes/_authenticated/_products/components/create-product-variants-dialog.tsx +1 -1
  98. package/src/app/routes/_authenticated/_products/components/create-product-variants.tsx +4 -4
  99. package/src/app/routes/_authenticated/_products/components/option-groups-editor.tsx +1 -1
  100. package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +1 -1
  101. package/src/app/routes/_authenticated/_products/components/product-option-select.tsx +3 -3
  102. package/src/app/routes/_authenticated/_products/components/product-options-table.tsx +9 -6
  103. package/src/app/routes/_authenticated/_products/products.graphql.ts +31 -31
  104. package/src/app/routes/_authenticated/_products/products.tsx +11 -6
  105. package/src/app/routes/_authenticated/_products/products_.$id.tsx +4 -4
  106. package/src/app/routes/_authenticated/_products/products_.$id_.variants.tsx +11 -11
  107. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$id.tsx +8 -12
  108. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +2 -2
  109. package/src/app/routes/_authenticated/_profile/profile.tsx +4 -4
  110. package/src/app/routes/_authenticated/_promotions/promotions.tsx +2 -4
  111. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +16 -9
  112. package/src/app/routes/_authenticated/_roles/components/permissions-table-grid.tsx +1 -1
  113. package/src/app/routes/_authenticated/_roles/roles.tsx +3 -6
  114. package/src/app/routes/_authenticated/_roles/roles_.$id.tsx +4 -6
  115. package/src/app/routes/_authenticated/_sellers/sellers.tsx +3 -4
  116. package/src/app/routes/_authenticated/_sellers/sellers_.$id.tsx +4 -4
  117. package/src/app/routes/_authenticated/_shipping-methods/components/price-display.tsx +5 -5
  118. package/src/app/routes/_authenticated/_shipping-methods/components/shipping-method-test-result-wrapper.tsx +1 -1
  119. package/src/app/routes/_authenticated/_shipping-methods/components/test-address-form.tsx +4 -3
  120. package/src/app/routes/_authenticated/_shipping-methods/components/test-order-builder.tsx +4 -3
  121. package/src/app/routes/_authenticated/_shipping-methods/components/test-shipping-methods-result.tsx +8 -8
  122. package/src/app/routes/_authenticated/_shipping-methods/components/test-shipping-methods-sheet.tsx +1 -1
  123. package/src/app/routes/_authenticated/_shipping-methods/components/test-single-method-result.tsx +8 -8
  124. package/src/app/routes/_authenticated/_shipping-methods/components/test-single-shipping-method-sheet.tsx +4 -4
  125. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +2 -3
  126. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +2 -2
  127. package/src/app/routes/_authenticated/_stock-locations/stock-locations.tsx +3 -4
  128. package/src/app/routes/_authenticated/_stock-locations/stock-locations_.$id.tsx +13 -6
  129. package/src/app/routes/_authenticated/_system/healthchecks.tsx +10 -4
  130. package/src/app/routes/_authenticated/_system/job-queue.tsx +10 -13
  131. package/src/app/routes/_authenticated/_system/scheduled-tasks.tsx +18 -16
  132. package/src/app/routes/_authenticated/_tax-categories/tax-categories.tsx +2 -4
  133. package/src/app/routes/_authenticated/_tax-categories/tax-categories_.$id.tsx +13 -6
  134. package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +8 -12
  135. package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +6 -4
  136. package/src/app/routes/_authenticated/_zones/zones.tsx +4 -4
  137. package/src/app/routes/_authenticated/_zones/zones_.$id.tsx +8 -5
  138. package/src/app/routes/_authenticated/index.tsx +6 -2
  139. package/src/app/styles.css +4 -0
  140. package/src/i18n/common-strings.ts +111 -0
  141. package/src/i18n/locales/ar.po +4777 -0
  142. package/src/i18n/locales/cs.po +4777 -0
  143. package/src/i18n/locales/de.po +4299 -1101
  144. package/src/i18n/locales/en.po +3857 -659
  145. package/src/i18n/locales/es.po +4777 -0
  146. package/src/i18n/locales/fa.po +4777 -0
  147. package/src/i18n/locales/fr.po +4777 -0
  148. package/src/i18n/locales/he.po +4777 -0
  149. package/src/i18n/locales/hr.po +4777 -0
  150. package/src/i18n/locales/it.po +4777 -0
  151. package/src/i18n/locales/ja.po +4777 -0
  152. package/src/i18n/locales/ko.po +4628 -0
  153. package/src/i18n/locales/nb.po +4777 -0
  154. package/src/i18n/locales/ne.po +4777 -0
  155. package/src/i18n/locales/nl.po +4628 -0
  156. package/src/i18n/locales/pl.po +4777 -0
  157. package/src/i18n/locales/pt_BR.po +4777 -0
  158. package/src/i18n/locales/pt_PT.po +4777 -0
  159. package/src/i18n/locales/ru.po +4777 -0
  160. package/src/i18n/locales/sv.po +4777 -0
  161. package/src/i18n/locales/tr.po +4777 -0
  162. package/src/i18n/locales/uk.po +4777 -0
  163. package/src/i18n/locales/zh_Hans.po +4777 -0
  164. package/src/i18n/locales/zh_Hant.po +4777 -0
  165. package/src/lib/components/data-input/combination-mode-input.tsx +1 -1
  166. package/src/lib/components/data-input/custom-field-list-input.tsx +11 -7
  167. package/src/lib/components/data-input/customer-group-input.tsx +27 -33
  168. package/src/lib/components/data-input/datetime-input.tsx +40 -1
  169. package/src/lib/components/data-input/default-relation-input.tsx +5 -4
  170. package/src/lib/components/data-input/product-multi-selector-input.tsx +14 -14
  171. package/src/lib/components/data-input/relation-selector.tsx +1 -1
  172. package/src/lib/components/data-input/select-with-options.tsx +1 -1
  173. package/src/lib/components/data-input/slug-input.tsx +9 -15
  174. package/src/lib/components/data-table/add-filter-menu.tsx +4 -4
  175. package/src/lib/components/data-table/data-table-bulk-action-item.tsx +8 -8
  176. package/src/lib/components/data-table/data-table-bulk-actions.tsx +4 -4
  177. package/src/lib/components/data-table/data-table-column-header.tsx +13 -8
  178. package/src/lib/components/data-table/data-table-faceted-filter.tsx +2 -1
  179. package/src/lib/components/data-table/data-table-filter-dialog.tsx +1 -1
  180. package/src/lib/components/data-table/data-table-utils.ts +21 -4
  181. package/src/lib/components/data-table/data-table-view-options.tsx +4 -2
  182. package/src/lib/components/data-table/data-table.tsx +3 -3
  183. package/src/lib/components/data-table/filters/data-table-boolean-filter.tsx +4 -4
  184. package/src/lib/components/data-table/global-views-bar.tsx +1 -1
  185. package/src/lib/components/data-table/human-readable-operator.tsx +1 -1
  186. package/src/lib/components/data-table/manage-global-views-button.tsx +1 -1
  187. package/src/lib/components/data-table/my-views-button.tsx +13 -13
  188. package/src/lib/components/data-table/refresh-button.tsx +1 -1
  189. package/src/lib/components/data-table/save-view-button.tsx +11 -11
  190. package/src/lib/components/data-table/use-generated-columns.tsx +10 -7
  191. package/src/lib/components/data-table/views-sheet.tsx +79 -71
  192. package/src/lib/components/date-range-picker.tsx +36 -34
  193. package/src/lib/components/layout/app-sidebar.tsx +3 -1
  194. package/src/lib/components/layout/channel-switcher.tsx +8 -10
  195. package/src/lib/components/layout/dev-mode-indicator.tsx +1 -1
  196. package/src/lib/components/layout/generated-breadcrumbs.tsx +10 -8
  197. package/src/lib/components/layout/language-dialog.tsx +34 -13
  198. package/src/lib/components/layout/manage-languages-dialog.tsx +1 -1
  199. package/src/lib/components/layout/nav-main.tsx +23 -13
  200. package/src/lib/components/layout/nav-user.tsx +19 -23
  201. package/src/lib/components/login/login-form.tsx +1 -1
  202. package/src/lib/components/shared/asset/asset-bulk-actions.tsx +4 -4
  203. package/src/lib/components/shared/asset/asset-focal-point-editor.tsx +1 -1
  204. package/src/lib/components/shared/asset/asset-gallery.tsx +15 -14
  205. package/src/lib/components/shared/assign-to-channel-bulk-action.tsx +11 -11
  206. package/src/lib/components/shared/assign-to-channel-dialog.tsx +6 -5
  207. package/src/lib/components/shared/channel-code-label.tsx +1 -1
  208. package/src/lib/components/shared/channel-selector.tsx +4 -4
  209. package/src/lib/components/shared/configurable-operation-multi-selector.tsx +16 -14
  210. package/src/lib/components/shared/configurable-operation-selector.tsx +1 -1
  211. package/src/lib/components/shared/confirmation-dialog.tsx +8 -8
  212. package/src/lib/components/shared/country-selector.tsx +1 -1
  213. package/src/lib/components/shared/currency-selector.tsx +4 -4
  214. package/src/lib/components/shared/custom-fields-form.tsx +8 -24
  215. package/src/lib/components/shared/customer-address-form.tsx +3 -3
  216. package/src/lib/components/shared/customer-group-selector.tsx +1 -1
  217. package/src/lib/components/shared/customer-selector.tsx +1 -1
  218. package/src/lib/components/shared/error-page.tsx +1 -1
  219. package/src/lib/components/shared/facet-value-selector.tsx +10 -10
  220. package/src/lib/components/shared/history-timeline/history-note-checkbox.tsx +1 -1
  221. package/src/lib/components/shared/history-timeline/history-note-editor.tsx +1 -1
  222. package/src/lib/components/shared/history-timeline/history-note-entry.tsx +1 -1
  223. package/src/lib/components/shared/language-selector.tsx +4 -4
  224. package/src/lib/components/shared/navigation-confirmation.tsx +1 -1
  225. package/src/lib/components/shared/paginated-list-data-table.tsx +21 -18
  226. package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +6 -5
  227. package/src/lib/components/shared/rich-text-editor/image-dialog.tsx +1 -1
  228. package/src/lib/components/shared/rich-text-editor/link-dialog.tsx +1 -1
  229. package/src/lib/components/shared/rich-text-editor/responsive-toolbar.tsx +1 -1
  230. package/src/lib/components/shared/rich-text-editor/table-edit-icons.tsx +1 -1
  231. package/src/lib/components/shared/role-code-label.tsx +1 -1
  232. package/src/lib/components/shared/role-selector.tsx +4 -4
  233. package/src/lib/components/shared/seller-selector.tsx +1 -1
  234. package/src/lib/components/shared/stock-level-label.tsx +3 -5
  235. package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +3 -1
  236. package/src/lib/components/shared/tax-category-selector.tsx +1 -1
  237. package/src/lib/components/shared/translatable-form-field.tsx +15 -15
  238. package/src/lib/components/shared/zone-selector.tsx +1 -1
  239. package/src/lib/constants.ts +10 -0
  240. package/src/lib/framework/dashboard-widget/base-widget.tsx +11 -9
  241. package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +6 -4
  242. package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +8 -5
  243. package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +7 -4
  244. package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +3 -1
  245. package/src/lib/framework/defaults.ts +34 -63
  246. package/src/lib/framework/layout-engine/page-layout.tsx +36 -36
  247. package/src/lib/framework/page/detail-page.tsx +10 -10
  248. package/src/lib/framework/page/use-extended-router.tsx +48 -23
  249. package/src/lib/graphql/api.ts +22 -7
  250. package/src/lib/graphql/graphql-env.d.ts +13 -25
  251. package/src/lib/hooks/use-display-locale.ts +40 -0
  252. package/src/lib/hooks/use-dynamic-translations.ts +46 -0
  253. package/src/lib/hooks/use-extended-detail-query.ts +1 -1
  254. package/src/lib/hooks/use-extended-list-query.ts +1 -1
  255. package/src/lib/hooks/use-local-format.ts +15 -1
  256. package/src/lib/hooks/use-saved-views.ts +7 -0
  257. package/src/lib/hooks/use-ui-language-loader.ts +30 -0
  258. package/src/lib/lib/load-i18n-messages.ts +17 -0
  259. package/src/lib/lib/trans.tsx +15 -11
  260. package/src/lib/providers/auth.tsx +2 -2
  261. package/src/lib/providers/channel-provider.tsx +3 -2
  262. package/src/lib/providers/i18n-provider.tsx +7 -14
  263. package/src/lib/providers/user-settings.tsx +46 -5
@@ -0,0 +1,40 @@
1
+ import { useUserSettings } from './use-user-settings.js';
2
+
3
+ const rtlLanguageCodes = ['ar', 'he', 'fa', 'ur', 'ps'];
4
+
5
+ /**
6
+ * @description
7
+ * Returns information about the current display language & region.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * const {
12
+ * bcp47Tag,
13
+ * humanReadableLanguageAndLocale,
14
+ * humanReadableLanguage,
15
+ * isRTL,
16
+ * } = useDisplayLocale();
17
+ *
18
+ * console.log(bcp47Tag) // "en-GB"
19
+ * console.log(humanReadableLanguage) // "English"
20
+ * console.log(humanReadableLanguageAndLocale) // "British English"
21
+ * console.log(isRTL) // false
22
+ * ```
23
+ *
24
+ * @docsCategory hooks
25
+ * @docsPage useDisplayLocale
26
+ */
27
+ export function useDisplayLocale() {
28
+ const { settings } = useUserSettings();
29
+ const language = settings.displayLanguage.replace(/[_-]/, '-');
30
+ const locale = settings.displayLocale;
31
+ const bcp47Tag = language.match(/[_-]/)
32
+ ? language.replace(/[_-]/, '-')
33
+ : [language, locale].filter(x => !!x).join('-');
34
+ const humanReadableLanguageAndLocale = new Intl.DisplayNames([bcp47Tag], { type: 'language' }).of(
35
+ bcp47Tag,
36
+ );
37
+ const isRTL = rtlLanguageCodes.includes(language);
38
+ const humanReadableLanguage = new Intl.DisplayNames([bcp47Tag], { type: 'language' }).of(language);
39
+ return { bcp47Tag, humanReadableLanguageAndLocale, humanReadableLanguage, isRTL };
40
+ }
@@ -0,0 +1,46 @@
1
+ import { camelCaseToTitleCase } from '@/vdb/lib/utils.js';
2
+ import { useLingui } from '@lingui/react';
3
+
4
+ export function useDynamicTranslations() {
5
+ const { i18n } = useLingui();
6
+
7
+ const getTranslatedFieldName = (fieldId: string) => {
8
+ const fieldNameTranslationId = `fieldName.${fieldId}`;
9
+ const translatedDisplay = i18n.t(fieldNameTranslationId);
10
+ return translatedDisplay !== fieldNameTranslationId
11
+ ? translatedDisplay
12
+ : camelCaseToTitleCase(fieldId);
13
+ };
14
+
15
+ const getTranslatedOrderState = (state: string) => {
16
+ const stateTranslationId = `orderState.${state}`;
17
+ const translatedDisplay = i18n.t(stateTranslationId);
18
+ return translatedDisplay !== stateTranslationId ? translatedDisplay : camelCaseToTitleCase(state);
19
+ };
20
+
21
+ const getTranslatedFulfillmentState = (state: string) => {
22
+ const stateTranslationId = `fulfillmentState.${state}`;
23
+ const translatedDisplay = i18n.t(stateTranslationId);
24
+ return translatedDisplay !== stateTranslationId ? translatedDisplay : camelCaseToTitleCase(state);
25
+ };
26
+
27
+ const getTranslatedPaymentState = (state: string) => {
28
+ const stateTranslationId = `paymentState.${state}`;
29
+ const translatedDisplay = i18n.t(stateTranslationId);
30
+ return translatedDisplay !== stateTranslationId ? translatedDisplay : camelCaseToTitleCase(state);
31
+ };
32
+
33
+ const getTranslatedRefundState = (state: string) => {
34
+ const stateTranslationId = `refundState.${state}`;
35
+ const translatedDisplay = i18n.t(stateTranslationId);
36
+ return translatedDisplay !== stateTranslationId ? translatedDisplay : camelCaseToTitleCase(state);
37
+ };
38
+
39
+ return {
40
+ getTranslatedFieldName,
41
+ getTranslatedOrderState,
42
+ getTranslatedFulfillmentState,
43
+ getTranslatedPaymentState,
44
+ getTranslatedRefundState,
45
+ };
46
+ }
@@ -1,5 +1,5 @@
1
1
  import { extendDetailFormQuery } from '@/vdb/framework/document-extension/extend-detail-form-query.js';
2
- import { useLingui } from '@/vdb/lib/trans.js';
2
+ import { useLingui } from '@lingui/react/macro';
3
3
  import { DocumentNode } from 'graphql';
4
4
  import { useEffect, useMemo, useRef } from 'react';
5
5
  import { toast } from 'sonner';
@@ -1,6 +1,6 @@
1
1
  import { getListQueryDocuments } from '@/vdb/framework/data-table/data-table-extensions.js';
2
2
  import { extendDocument } from '@/vdb/framework/document-extension/extend-document.js';
3
- import { useLingui } from '@/vdb/lib/trans.js';
3
+ import { useLingui } from '@lingui/react/macro';
4
4
  import { DocumentNode } from 'graphql';
5
5
  import { useEffect, useMemo, useRef } from 'react';
6
6
  import { toast } from 'sonner';
@@ -1,5 +1,6 @@
1
1
  import { useCallback, useMemo } from 'react';
2
2
 
3
+ import { useDisplayLocale } from './use-display-locale.js';
3
4
  import { useServerConfig } from './use-server-config.js';
4
5
 
5
6
  /**
@@ -26,7 +27,8 @@ import { useServerConfig } from './use-server-config.js';
26
27
  export function useLocalFormat() {
27
28
  const { moneyStrategyPrecision } = useServerConfig() ?? { moneyStrategyPrecision: 2 };
28
29
  const precisionFactor = useMemo(() => Math.pow(10, moneyStrategyPrecision), [moneyStrategyPrecision]);
29
- const locale = 'en';
30
+ const { bcp47Tag } = useDisplayLocale();
31
+ const locale = bcp47Tag;
30
32
 
31
33
  const toMajorUnits = useCallback(
32
34
  (value: number): number => {
@@ -119,6 +121,17 @@ export function useLocalFormat() {
119
121
  [locale],
120
122
  );
121
123
 
124
+ const formatRegionName = useCallback(
125
+ (value: string): string => {
126
+ try {
127
+ return new Intl.DisplayNames([locale], { type: 'region' }).of(value) ?? value;
128
+ } catch (e: any) {
129
+ return value;
130
+ }
131
+ },
132
+ [locale],
133
+ );
134
+
122
135
  const formatCurrencyName = useCallback(
123
136
  (currencyCode: string, display: 'full' | 'symbol' | 'name' = 'full'): string => {
124
137
  if (!currencyCode) return '';
@@ -154,6 +167,7 @@ export function useLocalFormat() {
154
167
  formatDate,
155
168
  formatRelativeDate,
156
169
  formatLanguageName,
170
+ formatRegionName,
157
171
  formatCurrencyName,
158
172
  toMajorUnits,
159
173
  toMinorUnits,
@@ -3,6 +3,7 @@ import {
3
3
  getSettingsStoreValueDocument,
4
4
  setSettingsStoreValueDocument,
5
5
  } from '@/vdb/graphql/settings-store-operations.js';
6
+ import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
6
7
  import { SavedView, SavedViewsStore, SaveViewInput, UpdateViewInput } from '@/vdb/types/saved-views.js';
7
8
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
8
9
  import { ColumnFiltersState } from '@tanstack/react-table';
@@ -19,6 +20,7 @@ const generateId = () => {
19
20
 
20
21
  export function useSavedViews() {
21
22
  const queryClient = useQueryClient();
23
+ const { settingsStoreIsAvailable } = useUserSettings();
22
24
  const { pageId } = usePage();
23
25
  const pageBlock = usePageBlock({ optional: true });
24
26
  const blockId = pageBlock?.blockId || 'default';
@@ -38,6 +40,8 @@ export function useSavedViews() {
38
40
  const allUserViews = (result?.getSettingsStoreValue as SavedViewsStore) || {};
39
41
  return allUserViews[pageId]?.[blockId] || [];
40
42
  },
43
+ retry: false,
44
+ enabled: settingsStoreIsAvailable,
41
45
  });
42
46
 
43
47
  // Query for global views
@@ -48,6 +52,8 @@ export function useSavedViews() {
48
52
  const allGlobalViews = (result?.getSettingsStoreValue as SavedViewsStore) || {};
49
53
  return allGlobalViews[pageId]?.[blockId] || [];
50
54
  },
55
+ retry: false,
56
+ enabled: settingsStoreIsAvailable,
51
57
  });
52
58
 
53
59
  // Save user view mutation
@@ -217,6 +223,7 @@ export function useSavedViews() {
217
223
  const canManageGlobalViews = hasPermissions(['WriteDashboardGlobalViews']);
218
224
 
219
225
  return {
226
+ savedViewsAreAvailable: settingsStoreIsAvailable,
220
227
  userViews: userViewsData || [],
221
228
  globalViews: globalViewsData || [],
222
229
  isLoading: userViewsLoading || globalViewsLoading,
@@ -0,0 +1,30 @@
1
+ import { loadI18nMessages } from '@/vdb/lib/load-i18n-messages.js';
2
+ import { useLingui } from '@lingui/react/macro';
3
+
4
+ let currentlyLoading: string | null = null;
5
+
6
+ /**
7
+ * @description
8
+ * Loads the UI translations for the given locale and activates it
9
+ * with the Lingui I18nProvider. Generally this is used internally
10
+ * when the display language is set via the user > language dialog.
11
+ *
12
+ * @docsCategory hooks
13
+ * @docsPage useUiLanguageLoader
14
+ */
15
+ export function useUiLanguageLoader() {
16
+ const { i18n } = useLingui();
17
+
18
+ async function loadAndActivateLocale(locale: string) {
19
+ if (currentlyLoading === locale) {
20
+ return;
21
+ }
22
+ currentlyLoading = locale;
23
+ const messages = await loadI18nMessages(locale);
24
+ i18n.load(locale, messages);
25
+ i18n.activate(locale);
26
+ currentlyLoading = null;
27
+ }
28
+
29
+ return { loadAndActivateLocale };
30
+ }
@@ -0,0 +1,17 @@
1
+ import { Messages } from '@lingui/core';
2
+
3
+ export async function loadI18nMessages(locale: string): Promise<Messages> {
4
+ if (import.meta.env.PROD) {
5
+ // We add the vite-ignore directive because we do not want to transform and
6
+ // bundle this dynamic import. Instead, we actually want to load it at runtime
7
+ // as a normal dynamic JS import.
8
+ // These i18n JS files are generated during build by the `translationsPlugin` in the
9
+ // vite-plugin-translations.ts file.
10
+ const { messages } = await import(/* @vite-ignore */ `./i18n/${locale}.js`);
11
+ return messages;
12
+ } else {
13
+ // In dev mode we allow the dynamic import behaviour
14
+ const { messages } = await import(`../../i18n/locales/${locale}.po`);
15
+ return messages;
16
+ }
17
+ }
@@ -1,16 +1,20 @@
1
+ // export { Trans } from '@lingui/react/macro';
2
+ // export { useLingui } from '@lingui/react';
3
+
4
+
1
5
  /**
2
6
  * This is a temporary work-around because the Lingui macros do not
3
7
  * currently work when the dashboard is packaged in an npm
4
8
  * module. Related issue: https://github.com/kentcdodds/babel-plugin-macros/issues/87
5
9
  */
6
- export function Trans({ children }: Readonly<{ children: React.ReactNode; context?: string }>) {
7
- return <>{children}</>;
8
- }
9
-
10
- export function useLingui() {
11
- return {
12
- i18n: {
13
- t: (key: string) => key,
14
- },
15
- };
16
- }
10
+ // export function Trans({ children }: Readonly<{ children: React.ReactNode; context?: string }>) {
11
+ // return <>{children}</>;
12
+ // }
13
+ //
14
+ // export function useLingui() {
15
+ // return {
16
+ // i18n: {
17
+ // t: (key: string) => key,
18
+ // },
19
+ // };
20
+ // }
@@ -1,3 +1,4 @@
1
+ import { LS_KEY_SELECTED_CHANNEL_TOKEN } from '@/vdb/constants.js';
1
2
  import { api } from '@/vdb/graphql/api.js';
2
3
  import { graphql, ResultOf } from '@/vdb/graphql/graphql.js';
3
4
  import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
@@ -170,8 +171,7 @@ export function AuthProvider({ children }: Readonly<{ children: React.ReactNode
170
171
  // Clear all cached queries to prevent stale data
171
172
  queryClient.clear();
172
173
  // Clear selected channel from localStorage
173
- localStorage.removeItem('vendure-selected-channel');
174
- localStorage.removeItem('vendure-selected-channel-token');
174
+ localStorage.removeItem(LS_KEY_SELECTED_CHANNEL_TOKEN);
175
175
  setStatus('unauthenticated');
176
176
  setIsLoginLogoutInProgress(false);
177
177
  onLogoutSuccess?.();
@@ -1,4 +1,5 @@
1
- import { api, SELECTED_CHANNEL_TOKEN_KEY } from '@/vdb/graphql/api.js';
1
+ import { LS_KEY_SELECTED_CHANNEL_TOKEN } from '@/vdb/constants.js';
2
+ import { api } from '@/vdb/graphql/api.js';
2
3
  import { graphql, ResultOf } from '@/vdb/graphql/graphql.js';
3
4
  import { useAuth } from '@/vdb/hooks/use-auth.js';
4
5
  import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
@@ -94,7 +95,7 @@ export interface ChannelContext {
94
95
  */
95
96
  function setChannelTokenInLocalStorage(channelToken: string) {
96
97
  try {
97
- localStorage.setItem(SELECTED_CHANNEL_TOKEN_KEY, channelToken);
98
+ localStorage.setItem(LS_KEY_SELECTED_CHANNEL_TOKEN, channelToken);
98
99
  } catch (e) {
99
100
  console.error('Failed to store selected channel in localStorage', e);
100
101
  }
@@ -1,11 +1,8 @@
1
+ import { loadI18nMessages } from '@/vdb/lib/load-i18n-messages.js';
2
+ import { i18n } from '@lingui/core';
3
+ import { I18nProvider as LinguiI18nProvider } from '@lingui/react';
1
4
  import React from 'react';
2
- // import { i18n } from '@lingui/core';
3
- // import { I18nProvider as LinguiI18nProvider } from '@lingui/react';
4
5
 
5
- export const locales = {
6
- en: 'English',
7
- de: 'Deutsch',
8
- };
9
6
  export const defaultLocale = 'en';
10
7
 
11
8
  /**
@@ -13,16 +10,12 @@ export const defaultLocale = 'en';
13
10
  * @param locale any locale string
14
11
  */
15
12
  export async function dynamicActivate(locale: string, onActivate?: () => void) {
16
- // Temporarily disabled because Lingui macros do not work when the dashboard is packaged in an npm module.
17
- // Related issue: https://github.com/kentcdodds/babel-plugin-macros/issues/87
18
-
19
- // const { messages } = await import(`../../i18n/locales/${locale}.po`);
20
- // i18n.load(locale, messages);
21
- // i18n.activate(locale);
13
+ const messages = await loadI18nMessages(locale);
14
+ i18n.load(locale, messages);
15
+ i18n.activate(locale);
22
16
  onActivate?.();
23
17
  }
24
18
 
25
19
  export function I18nProvider({ children }: { children: React.ReactNode }) {
26
- // return <LinguiI18nProvider i18n={i18n}>{children}</LinguiI18nProvider>;
27
- return <>{children}</>;
20
+ return <LinguiI18nProvider i18n={i18n}>{children}</LinguiI18nProvider>;
28
21
  }
@@ -1,3 +1,4 @@
1
+ import { LS_KEY_USER_SETTINGS } from '@/vdb/constants.js';
1
2
  import { QueryClient, useMutation, useQuery } from '@tanstack/react-query';
2
3
  import { ColumnFiltersState } from '@tanstack/react-table';
3
4
  import React, { createContext, useEffect, useRef, useState } from 'react';
@@ -43,6 +44,12 @@ const defaultSettings: UserSettings = {
43
44
  };
44
45
 
45
46
  export interface UserSettingsContextType {
47
+ /**
48
+ * @description
49
+ * Whether the server-side SettingsStore is available to use
50
+ * (i.e. the Vendure instance has the DashboardPlugin configured)
51
+ */
52
+ settingsStoreIsAvailable: boolean;
46
53
  settings: UserSettings;
47
54
  setDisplayLanguage: (language: string) => void;
48
55
  setDisplayLocale: (locale: string | undefined) => void;
@@ -63,7 +70,6 @@ export interface UserSettingsContextType {
63
70
 
64
71
  export const UserSettingsContext = createContext<UserSettingsContextType | undefined>(undefined);
65
72
 
66
- const STORAGE_KEY = 'vendure-user-settings';
67
73
  const SETTINGS_STORE_KEY = 'vendure.dashboard.userSettings';
68
74
 
69
75
  interface UserSettingsProviderProps {
@@ -75,7 +81,7 @@ export const UserSettingsProvider: React.FC<UserSettingsProviderProps> = ({ quer
75
81
  // Load settings from localStorage or use defaults
76
82
  const loadSettings = (): UserSettings => {
77
83
  try {
78
- const storedSettings = localStorage.getItem(STORAGE_KEY);
84
+ const storedSettings = localStorage.getItem(LS_KEY_USER_SETTINGS);
79
85
  if (storedSettings) {
80
86
  return { ...defaultSettings, ...JSON.parse(storedSettings) };
81
87
  }
@@ -86,19 +92,35 @@ export const UserSettingsProvider: React.FC<UserSettingsProviderProps> = ({ quer
86
92
  };
87
93
 
88
94
  const [settings, setSettings] = useState<UserSettings>(loadSettings);
95
+ const [settingsStoreIsAvailable, setSettingsStoreIsAvailable] = useState<boolean>(true);
89
96
  const [serverSettings, setServerSettings] = useState<UserSettings | null>(null);
90
97
  const [isReady, setIsReady] = useState(false);
91
98
  const previousContentLanguage = useRef(settings.contentLanguage);
92
99
  const saveInProgressRef = useRef(false);
93
100
 
94
101
  // Load settings from server on mount
95
- const { data: serverSettingsResponse, isSuccess: serverSettingsLoaded } = useQuery({
102
+ const {
103
+ data: serverSettingsResponse,
104
+ isSuccess: serverSettingsLoaded,
105
+ error,
106
+ } = useQuery({
96
107
  queryKey: ['user-settings', SETTINGS_STORE_KEY],
97
108
  queryFn: () => api.query(getSettingsStoreValueDocument, { key: SETTINGS_STORE_KEY }),
98
109
  retry: false,
99
110
  staleTime: 0,
111
+ enabled: settingsStoreIsAvailable,
100
112
  });
101
113
 
114
+ useEffect(() => {
115
+ if (
116
+ settingsStoreIsAvailable &&
117
+ error?.message.includes('Settings store field not registered: vendure.dashboard.userSettings')
118
+ ) {
119
+ logSettingsStoreWarning();
120
+ setSettingsStoreIsAvailable(false);
121
+ }
122
+ }, [settingsStoreIsAvailable, error]);
123
+
102
124
  // Mutation to save settings to server
103
125
  const saveToServerMutation = useMutation({
104
126
  mutationFn: (settingsToSave: UserSettings) =>
@@ -144,7 +166,7 @@ export const UserSettingsProvider: React.FC<UserSettingsProviderProps> = ({ quer
144
166
  // Save settings to localStorage whenever they change
145
167
  useEffect(() => {
146
168
  try {
147
- localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));
169
+ localStorage.setItem(LS_KEY_USER_SETTINGS, JSON.stringify(settings));
148
170
  } catch (e) {
149
171
  console.error('Failed to save user settings to localStorage', e);
150
172
  }
@@ -152,7 +174,7 @@ export const UserSettingsProvider: React.FC<UserSettingsProviderProps> = ({ quer
152
174
 
153
175
  // Save to server when settings differ from server state
154
176
  useEffect(() => {
155
- if (isReady && serverSettings && !saveInProgressRef.current) {
177
+ if (settingsStoreIsAvailable && isReady && serverSettings && !saveInProgressRef.current) {
156
178
  const serverDiffers = JSON.stringify(serverSettings) !== JSON.stringify(settings);
157
179
 
158
180
  if (serverDiffers) {
@@ -177,6 +199,7 @@ export const UserSettingsProvider: React.FC<UserSettingsProviderProps> = ({ quer
177
199
  };
178
200
 
179
201
  const contextValue: UserSettingsContextType = {
202
+ settingsStoreIsAvailable,
180
203
  settings,
181
204
  setDisplayLanguage: language => updateSetting('displayLanguage', language),
182
205
  setDisplayLocale: locale => updateSetting('displayLocale', locale),
@@ -201,3 +224,21 @@ export const UserSettingsProvider: React.FC<UserSettingsProviderProps> = ({ quer
201
224
 
202
225
  return <UserSettingsContext.Provider value={contextValue}>{children}</UserSettingsContext.Provider>;
203
226
  };
227
+
228
+ function logSettingsStoreWarning() {
229
+ // eslint-disable-next-line no-console
230
+ console.warn(
231
+ [
232
+ `User settings could not be fetched from the Vendure server.`,
233
+ `This suggests that the DashboardPlugin is not configured.`,
234
+ `Check your VendureConfig and ensure the DashboardPlugin is in your plugins array.`,
235
+ ``,
236
+ `By setting up the DashboardPlugin, you can take advantage of:`,
237
+ ` - Persisted settings across browsers and devices`,
238
+ ` - Saved views on list pages`,
239
+ ` - Metrics on the Insights page`,
240
+ ``,
241
+ `https://docs.vendure.io/reference/core-plugins/dashboard-plugin/`,
242
+ ].join('\n'),
243
+ );
244
+ }