@deenruv/admin-dashboard 1.0.5 → 1.0.9

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 (76) hide show
  1. package/dist/DeenruvAdminPanel.js +5 -4
  2. package/dist/DeenruvDeveloperIndicator.js +1 -1
  3. package/dist/components/ContentAreaSkeleton.js +5 -0
  4. package/dist/components/Menu/LanguagesDropdown.js +4 -3
  5. package/dist/components/Menu/Navigation.js +10 -9
  6. package/dist/components/Menu/Notifications.js +2 -1
  7. package/dist/components/Menu/flag-icons.js +16 -0
  8. package/dist/components/Menu/index.js +3 -2
  9. package/dist/pages/Custom404.js +16 -2
  10. package/dist/pages/Root.js +2 -2
  11. package/dist/pages/admins/Detail.js +7 -7
  12. package/dist/pages/admins/_components/AdminDetailView.js +17 -9
  13. package/dist/pages/channels/Detail.js +12 -12
  14. package/dist/pages/channels/_components/ChannelDetailView.js +25 -17
  15. package/dist/pages/collections/Detail.js +8 -7
  16. package/dist/pages/collections/List.js +1 -2
  17. package/dist/pages/collections/_components/CollectionDetailView.js +65 -22
  18. package/dist/pages/collections/_components/CollectionProductVariantsDrawer.js +1 -1
  19. package/dist/pages/countries/Detail.js +5 -5
  20. package/dist/pages/countries/_components/CountryDetailView.js +15 -8
  21. package/dist/pages/customer-groups/Detail.js +3 -3
  22. package/dist/pages/customer-groups/_components/CustomerGroupsDetailView.js +4 -4
  23. package/dist/pages/customers/Detail.js +6 -8
  24. package/dist/pages/customers/_components/AddressForm.js +48 -60
  25. package/dist/pages/customers/_components/AddressesCard.js +1 -1
  26. package/dist/pages/customers/_components/CustomerDetailView.js +9 -9
  27. package/dist/pages/dashboard/Dashboard.js +3 -2
  28. package/dist/pages/extensions/Extensions.js +12 -13
  29. package/dist/pages/facets/Detail.js +6 -6
  30. package/dist/pages/facets/_components/AddFacetValueDialog.js +39 -39
  31. package/dist/pages/facets/_components/FacetDetailView.js +19 -12
  32. package/dist/pages/global-settings/GlobalSettingsComponent.js +9 -8
  33. package/dist/pages/global-settings/index.js +4 -4
  34. package/dist/pages/orders/List.js +2 -1
  35. package/dist/pages/orders/_components/AddressCard.js +123 -78
  36. package/dist/pages/orders/_components/CustomerSelectCard.js +38 -43
  37. package/dist/pages/orders/_components/FulfillmentModal.js +47 -28
  38. package/dist/pages/orders/_components/ModifyingCard.js +30 -13
  39. package/dist/pages/orders/_components/OrderLineCustomFields.js +2 -1
  40. package/dist/pages/orders/_components/PossibleOrderStates.js +2 -1
  41. package/dist/pages/orders/_components/ProductsCard.js +2 -1
  42. package/dist/pages/orders/_components/SurchargeCard.js +58 -60
  43. package/dist/pages/orders/_components/TopActions.js +2 -1
  44. package/dist/pages/payment-methods/Detail.js +8 -7
  45. package/dist/pages/payment-methods/_components/PaymentMethodDetailView.js +22 -14
  46. package/dist/pages/products/Detail.js +9 -7
  47. package/dist/pages/products/_components/AddOptionGroupDialog.js +36 -14
  48. package/dist/pages/products/_components/BasicFieldsCard.js +5 -2
  49. package/dist/pages/products/_components/OptionValueCard.js +25 -23
  50. package/dist/pages/products/_components/ProductDetailSidebar.js +15 -7
  51. package/dist/pages/products/_components/ProductDetailView.js +51 -17
  52. package/dist/pages/products/_components/Variant.js +105 -57
  53. package/dist/pages/promotions/Detail.js +13 -11
  54. package/dist/pages/promotions/_components/OptionsCard.js +1 -1
  55. package/dist/pages/promotions/_components/PromotionDetailSidebar.js +9 -6
  56. package/dist/pages/promotions/_components/PromotionDetailView.js +26 -20
  57. package/dist/pages/roles/Detail.js +5 -5
  58. package/dist/pages/roles/_components/RoleDetailView.js +13 -8
  59. package/dist/pages/sellers/Detail.js +4 -4
  60. package/dist/pages/sellers/_components/SellerDetailView.js +4 -4
  61. package/dist/pages/shipping-methods/Detail.js +14 -12
  62. package/dist/pages/shipping-methods/_components/Lines.js +1 -1
  63. package/dist/pages/shipping-methods/_components/ShippingMethodDetailView.js +26 -13
  64. package/dist/pages/shipping-methods/_components/TestCard.js +67 -21
  65. package/dist/pages/status/_components/Health.js +2 -1
  66. package/dist/pages/status/_components/Jobs.js +2 -6
  67. package/dist/pages/stock-locations/Detail.js +4 -4
  68. package/dist/pages/stock-locations/_components/StockLocationDetailView.js +5 -5
  69. package/dist/pages/tax-categories/Detail.js +4 -4
  70. package/dist/pages/tax-categories/_components/TaxCategoryDetailView.js +7 -7
  71. package/dist/pages/tax-rates/Detail.js +8 -8
  72. package/dist/pages/tax-rates/_components/TaxRateDetailView.js +13 -9
  73. package/dist/pages/zones/Detail.js +4 -4
  74. package/dist/pages/zones/_components/ZoneDetailView.js +8 -7
  75. package/dist/version.js +1 -1
  76. package/package.json +79 -78
@@ -1,25 +1,27 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button, DialogHeader, DialogTitle, DialogTrigger, Input, Dialog, DialogContent, Label, DialogFooter, apiClient, useSettings, useGFFLP, EntityCustomFields, useTranslation, } from '@deenruv/react-ui-devkit';
2
+ import { Button, DialogHeader, DialogTitle, DialogTrigger, Input, Dialog, DialogContent, Label, DialogFooter, apiClient, useSettings, useDeenruvForm, z, EntityCustomFields, useTranslation, } from '@deenruv/react-ui-devkit';
3
3
  import { useCallback, useEffect, useMemo } from 'react';
4
4
  import { toast } from 'sonner';
5
+ const facetValueSchema = z.object({
6
+ name: z.string().min(1),
7
+ code: z.string().min(1),
8
+ customFields: z.record(z.string(), z.unknown()).optional().default({}),
9
+ });
5
10
  export const AddFacetValueDialog = ({ facetId, onFacetValueChange, open, setOpen, facetValueId, }) => {
6
11
  const editMode = useMemo(() => !!facetValueId, [facetValueId]);
7
12
  const { t } = useTranslation('facets');
8
- const { translationsLanguage: languageCode } = useSettings(({ translationsLanguage }) => ({ translationsLanguage }));
9
- const { state, setField } = useGFFLP('FacetValue', 'name', 'code', 'customFields')({
10
- name: {
11
- validate: (v) => {
12
- if (!v || v === '')
13
- return [t('requiredError')];
14
- },
15
- },
16
- code: {
17
- validate: (v) => {
18
- if (!v || v === '')
19
- return [t('requiredError')];
20
- },
13
+ const languageCode = useSettings((p) => p.translationsLanguage);
14
+ const form = useDeenruvForm({
15
+ schema: facetValueSchema,
16
+ defaultValues: {
17
+ name: '',
18
+ code: '',
19
+ customFields: {},
21
20
  },
22
21
  });
22
+ const nameValue = form.watch('name');
23
+ const codeValue = form.watch('code');
24
+ const customFieldsValue = form.watch('customFields');
23
25
  const fetchFacetValue = useCallback(() => facetValueId &&
24
26
  apiClient('query')({
25
27
  facetValues: [
@@ -27,39 +29,37 @@ export const AddFacetValueDialog = ({ facetId, onFacetValueChange, open, setOpen
27
29
  { items: { code: true, translations: { languageCode: true, name: true } } },
28
30
  ],
29
31
  }).then((resp) => {
30
- setField('code', resp.facetValues.items[0].code);
31
- setField('name', resp.facetValues.items[0].translations.find((t) => t.languageCode === languageCode)?.name || '');
32
+ form.setField('code', resp.facetValues.items[0].code);
33
+ form.setField('name', resp.facetValues.items[0].translations.find((t) => t.languageCode === languageCode)?.name || '');
32
34
  if ('customFields' in resp.facetValues.items[0])
33
- setField('customFields', resp.facetValues.items[0].customFields);
35
+ form.setField('customFields', resp.facetValues.items[0].customFields);
34
36
  }), [facetValueId, t, languageCode]);
35
37
  useEffect(() => {
36
38
  fetchFacetValue();
37
39
  }, [fetchFacetValue, facetValueId]);
38
40
  useEffect(() => {
39
- if (editMode || !state.name?.value)
41
+ if (editMode || !nameValue)
40
42
  return;
41
- const facetCode = state.name?.value.toLowerCase().replace(/\s+/g, '-');
43
+ const facetCode = nameValue.toLowerCase().replace(/\s+/g, '-');
42
44
  if (facetCode)
43
- setField('code', facetCode);
44
- }, [state, editMode, setField]);
45
- useEffect(() => {
46
- console.log('ST', state);
47
- }, [state]);
45
+ form.setField('code', facetCode);
46
+ }, [nameValue, editMode, form.setField]);
48
47
  const resetValues = useCallback(() => {
49
48
  onFacetValueChange();
50
49
  setOpen(false);
51
- setField('name', '');
52
- setField('code', '');
53
- }, [onFacetValueChange, setField]);
50
+ form.reset({ name: '', code: '', customFields: {} });
51
+ }, [onFacetValueChange, form]);
54
52
  const saveFacetValue = useCallback(() => apiClient('mutation')({
55
53
  createFacetValues: [
56
54
  {
57
55
  input: [
58
56
  {
59
57
  facetId,
60
- code: state.code.value,
61
- translations: [{ languageCode, name: state.name?.value }],
62
- ...(state.customFields?.validatedValue ? { customFields: state.customFields?.validatedValue } : {}),
58
+ code: codeValue,
59
+ translations: [{ languageCode, name: nameValue }],
60
+ ...(customFieldsValue && Object.keys(customFieldsValue).length > 0
61
+ ? { customFields: customFieldsValue }
62
+ : {}),
63
63
  },
64
64
  ],
65
65
  },
@@ -70,7 +70,7 @@ export const AddFacetValueDialog = ({ facetId, onFacetValueChange, open, setOpen
70
70
  toast.message(t('addValueModal.success'));
71
71
  resetValues();
72
72
  })
73
- .catch((err) => toast.message(t('addValueModal.error') + ': ' + err)), [state, languageCode, facetId, resetValues, t]);
73
+ .catch((err) => toast.message(t('addValueModal.error') + ': ' + err)), [nameValue, codeValue, customFieldsValue, languageCode, facetId, resetValues, t]);
74
74
  const updateFacetValue = useCallback(() => {
75
75
  if (!facetValueId)
76
76
  return;
@@ -80,9 +80,11 @@ export const AddFacetValueDialog = ({ facetId, onFacetValueChange, open, setOpen
80
80
  input: [
81
81
  {
82
82
  id: facetValueId,
83
- code: state.code.value,
84
- translations: [{ languageCode, name: state.name?.value }],
85
- ...(state.customFields?.validatedValue ? { customFields: state.customFields?.validatedValue } : {}),
83
+ code: codeValue,
84
+ translations: [{ languageCode, name: nameValue }],
85
+ ...(customFieldsValue && Object.keys(customFieldsValue).length > 0
86
+ ? { customFields: customFieldsValue }
87
+ : {}),
86
88
  },
87
89
  ],
88
90
  },
@@ -94,12 +96,10 @@ export const AddFacetValueDialog = ({ facetId, onFacetValueChange, open, setOpen
94
96
  resetValues();
95
97
  })
96
98
  .catch((err) => toast.message(t('addValueModal.error') + ': ' + err));
97
- }, [state, languageCode, facetId, resetValues, t]);
99
+ }, [nameValue, codeValue, customFieldsValue, languageCode, facetValueId, resetValues, t]);
98
100
  return (_jsxs(Dialog, { open: open, onOpenChange: resetValues, children: [_jsx(DialogTrigger, { children: _jsx(Button, { onClick: () => {
99
101
  setOpen(true);
100
- }, children: "Create" }) }), _jsxs(DialogContent, { className: "sm:max-w-3xl", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: editMode ? t('addValueModal.editTitle') : t('addValueModal.title') }) }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { children: [_jsx(Label, { children: t('addValueModal.nameLabel') }), _jsx(Input, { className: "mt-1", value: state.name?.value, onChange: (e) => setField('name', e.target.value) })] }), _jsxs("div", { children: [_jsx(Label, { children: t('addValueModal.codeLabel') }), _jsx(Input, { className: "mt-1", value: state.code?.value, onChange: (e) => setField('code', e.target.value) })] }), _jsx(EntityCustomFields, { entityName: "facetValue", id: facetValueId, hideButton: true, initialValues: state && 'customFields' in state
101
- ? { customFields: state.customFields?.validatedValue }
102
- : { customFields: {} }, onChange: (cf) => {
103
- setField('customFields', cf);
102
+ }, children: "Create" }) }), _jsxs(DialogContent, { className: "sm:max-w-3xl", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: editMode ? t('addValueModal.editTitle') : t('addValueModal.title') }) }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { children: [_jsx(Label, { children: t('addValueModal.nameLabel') }), _jsx(Input, { className: "mt-1", value: nameValue, onChange: (e) => form.setField('name', e.target.value) })] }), _jsxs("div", { children: [_jsx(Label, { children: t('addValueModal.codeLabel') }), _jsx(Input, { className: "mt-1", value: codeValue, onChange: (e) => form.setField('code', e.target.value) })] }), _jsx(EntityCustomFields, { entityName: "facetValue", id: facetValueId, hideButton: true, initialValues: customFieldsValue ? { customFields: customFieldsValue } : { customFields: {} }, onChange: (cf) => {
103
+ form.setField('customFields', cf);
104
104
  }, additionalData: {} })] }), _jsx(DialogFooter, { className: "mt-2", children: _jsx(Button, { onClick: editMode ? updateFacetValue : saveFacetValue, children: editMode ? t('addValueModal.editButton') : t('addValueModal.button') }) })] })] }));
105
105
  };
@@ -27,20 +27,25 @@ const STOCK_LOCATION_FORM_KEYS = [
27
27
  ];
28
28
  export const FacetsDetailView = () => {
29
29
  const { form, fetchEntity, entity, additionalData, setAdditionalData, id } = useDetailView('facets-detail-view', ...STOCK_LOCATION_FORM_KEYS);
30
- const { base: { setField, state }, } = form;
30
+ const { base } = form;
31
31
  const editMode = useMemo(() => !!id, [id]);
32
32
  const { t } = useTranslation(['common', 'facets']);
33
33
  const [facetValueIdInModal, setFacetValueIdInModal] = useState(null);
34
34
  const [open, setOpen] = useState(false);
35
35
  const { translationsLanguage: currentTranslationLng } = useSettings();
36
- const translations = state?.translations?.value || [];
36
+ const translations = base.watch('translations') || [];
37
37
  const currentTranslationValue = translations.find((v) => v.languageCode === currentTranslationLng);
38
38
  const setTranslationField = useCallback((field, e) => {
39
- setField('translations', setInArrayBy(translations, (t) => t.languageCode !== currentTranslationLng, {
39
+ const baseTranslation = currentTranslationValue ?? {
40
+ languageCode: currentTranslationLng,
41
+ name: '',
42
+ };
43
+ base.setField('translations', setInArrayBy(translations, (t) => t.languageCode === currentTranslationLng, {
44
+ ...baseTranslation,
40
45
  [field]: e,
41
46
  languageCode: currentTranslationLng,
42
47
  }));
43
- }, [currentTranslationLng, translations]);
48
+ }, [currentTranslationLng, translations, currentTranslationValue]);
44
49
  const fetchFacetValues = useCallback(async ({ page, perPage, filter, filterOperator, sort }, additionalSelector) => {
45
50
  // if (!id) return Promise.resolve([]);
46
51
  const response = await apiClient('query')({
@@ -64,22 +69,24 @@ export const FacetsDetailView = () => {
64
69
  const res = await fetchEntity();
65
70
  if (!res)
66
71
  return;
67
- setField('translations', res.translations);
68
- setField('code', res.code);
69
- setField('isPrivate', res.isPrivate);
72
+ base.setField('translations', res.translations);
73
+ base.setField('code', res.code);
74
+ base.setField('isPrivate', res.isPrivate);
70
75
  if ('customFields' in res)
71
- setField('customFields', res.customFields);
76
+ base.setField('customFields', res.customFields);
72
77
  })();
73
78
  }, []);
74
79
  useEffect(() => {
75
80
  if (!editMode && currentTranslationValue?.name) {
76
- setField('code', currentTranslationValue.name.toLowerCase().replace(/\s+/g, '-'));
81
+ base.setField('code', currentTranslationValue.name.toLowerCase().replace(/\s+/g, '-'));
77
82
  }
78
83
  }, [currentTranslationValue?.name, editMode]);
79
- return (_jsx("main", { className: "my-4", children: _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(CustomCard, { title: t('facets:details.basicInfo'), icon: _jsx(CardIcons.basic, {}), color: "green", children: _jsxs("div", { className: "flex gap-8 p-0 pt-2", children: [_jsx("div", { className: "basis-full md:basis-1/2 xl:basis-1/3", children: _jsx(Input, { label: t('facets:table.name'), value: currentTranslationValue?.name ?? undefined, onChange: (e) => setTranslationField('name', e.target.value), errors: state.translations?.errors, required: true }) }), _jsx("div", { className: "basis-full md:basis-1/2 xl:basis-1/3", children: _jsx(Input, { label: t('facets:table.code'), value: state.code?.value, onChange: (e) => setField('code', e.target.value), errors: state.code?.errors, required: true }) }), _jsxs("div", { className: "basis-full md:basis-1/2 xl:basis-1/3", children: [_jsx(Label, { children: t('facets:table.isPrivate') }), _jsxs("div", { className: "mt-2 flex gap-3", children: [_jsx(Switch, { checked: state.isPrivate?.value, onCheckedChange: (e) => setField('isPrivate', e) }), _jsx("p", { children: state.isPrivate?.value ? t('facets:table.isPrivate') : t('facets:table.public') })] })] })] }) }), _jsx(DetailViewMarker, { position: 'facets-detail-view' }), _jsx(EntityCustomFields, { entityName: "facet", id: id, hideButton: true, onChange: (customFields, translations) => {
80
- setField('customFields', customFields);
84
+ return (_jsx("main", { className: "my-4", children: _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(CustomCard, { title: t('facets:details.basicInfo'), icon: _jsx(CardIcons.basic, {}), color: "green", children: _jsxs("div", { className: "flex gap-8 p-0 pt-2", children: [_jsx("div", { className: "basis-full md:basis-1/2 xl:basis-1/3", children: _jsx(Input, { label: t('facets:table.name'), value: currentTranslationValue?.name ?? '', onChange: (e) => setTranslationField('name', e.target.value), errors: base.formState.errors?.translations?.message
85
+ ? [base.formState.errors.translations.message]
86
+ : undefined, required: true }) }), _jsx("div", { className: "basis-full md:basis-1/2 xl:basis-1/3", children: _jsx(Input, { label: t('facets:table.code'), value: base.watch('code') ?? '', onChange: (e) => base.setField('code', e.target.value), errors: base.formState.errors?.code?.message ? [base.formState.errors.code.message] : undefined, required: true }) }), _jsxs("div", { className: "basis-full md:basis-1/2 xl:basis-1/3", children: [_jsx(Label, { children: t('facets:table.isPrivate') }), _jsxs("div", { className: "mt-2 flex gap-3", children: [_jsx(Switch, { checked: base.watch('isPrivate') ?? false, onCheckedChange: (e) => base.setField('isPrivate', e) }), _jsx("p", { children: base.watch('isPrivate') ? t('facets:table.isPrivate') : t('facets:table.public') })] })] })] }) }), _jsx(DetailViewMarker, { position: 'facets-detail-view' }), _jsx(EntityCustomFields, { entityName: "facet", id: id, hideButton: true, onChange: (customFields, translations) => {
87
+ base.setField('customFields', customFields);
81
88
  if (translations)
82
- setField('translations', translations);
89
+ base.setField('translations', translations);
83
90
  }, initialValues: entity && 'customFields' in entity
84
91
  ? { customFields: entity.customFields, translations: entity.translations }
85
92
  : { customFields: {} } }), entity && editMode && (_jsx(CustomCard, { title: t('facets:details.facetValues'), icon: _jsx(CardIcons.tag, {}), color: "teal", upperRight: _jsx(AddFacetValueDialog, { open: open, setOpen: setOpen, facetId: entity.id, facetValueId: facetValueIdInModal, onFacetValueChange: () => {
@@ -6,25 +6,26 @@ import { useEffect, useMemo } from 'react';
6
6
  export const GlobalSettingsComponent = () => {
7
7
  const contentLng = useSettings((p) => p.translationsLanguage);
8
8
  const { form, fetchEntity, entity } = useDetailView('globalSettings-detail-view', 'UpdateGlobalSettingsInput', 'availableLanguages', 'outOfStockThreshold', 'trackInventory', 'customFields');
9
- const { base: { state, setField }, } = form;
9
+ const { base } = form;
10
10
  const options = useMemo(() => Object.values(LanguageCode).map((el) => ({ label: `${t(`languageCode.${el}`)} (${el})`, value: el })), [t]);
11
11
  useEffect(() => {
12
12
  const init = async () => {
13
13
  const data = await fetchEntity();
14
14
  if (data) {
15
- setField('availableLanguages', data.availableLanguages);
16
- setField('outOfStockThreshold', data.outOfStockThreshold);
17
- setField('trackInventory', data.trackInventory);
15
+ base.setField('availableLanguages', data.availableLanguages);
16
+ base.setField('outOfStockThreshold', data.outOfStockThreshold);
17
+ base.setField('trackInventory', data.trackInventory);
18
18
  if ('customFields' in data)
19
- setField('customFields', data.customFields);
19
+ base.setField('customFields', data.customFields);
20
20
  }
21
21
  };
22
22
  init();
23
23
  }, [contentLng]);
24
- return (_jsxs("div", { className: "flex flex-col gap-6 p-4", children: [_jsx(CustomCard, { title: t('globalSettings:available-languages.label'), description: t('globalSettings:available-languages.description'), icon: _jsx(CardIcons.options, {}), color: "green", children: _jsx(MultipleSelector, { options: options, value: state.availableLanguages?.value?.map((el) => ({
24
+ const availableLanguages = base.watch('availableLanguages');
25
+ return (_jsxs("div", { className: "flex flex-col gap-6 p-4", children: [_jsx(CustomCard, { title: t('globalSettings:available-languages.label'), description: t('globalSettings:available-languages.description'), icon: _jsx(CardIcons.options, {}), color: "green", children: _jsx(MultipleSelector, { options: options, value: availableLanguages?.map((el) => ({
25
26
  label: t(`languageCode.${el}`),
26
27
  value: el,
27
- })), placeholder: t('globalSettings:available-languages.placeholder'), onChange: (val) => setField('availableLanguages', val.map((el) => el.value)) }) }), _jsx(CustomCard, { title: t('globalSettings:stock-threshold.label'), description: t('globalSettings:stock-threshold.description'), icon: _jsx(CardIcons.options, {}), color: "teal", children: _jsx(Input, { value: state.outOfStockThreshold?.value ?? undefined, type: "number", onChange: (e) => setField('outOfStockThreshold', Number(e.target.value)), required: true }) }), _jsx(CustomCard, { title: t('globalSettings:track-inventory.label'), description: t('globalSettings:track-inventory.description'), icon: _jsx(CardIcons.options, {}), color: "cyan", children: _jsx(Switch, { checked: state.trackInventory?.value ?? undefined, onCheckedChange: (val) => setField('trackInventory', val) }) }), _jsx(EntityCustomFields, { id: entity?.id, entityName: "globalSettings", hideButton: true, initialValues: entity && 'customFields' in entity ? { customFields: entity.customFields } : { customFields: {} }, onChange: (cf) => {
28
- setField('customFields', cf);
28
+ })), placeholder: t('globalSettings:available-languages.placeholder'), onChange: (val) => base.setField('availableLanguages', val.map((el) => el.value)) }) }), _jsx(CustomCard, { title: t('globalSettings:stock-threshold.label'), description: t('globalSettings:stock-threshold.description'), icon: _jsx(CardIcons.options, {}), color: "teal", children: _jsx(Input, { value: base.watch('outOfStockThreshold') ?? '', type: "number", onChange: (e) => base.setField('outOfStockThreshold', Number(e.target.value)), required: true }) }), _jsx(CustomCard, { title: t('globalSettings:track-inventory.label'), description: t('globalSettings:track-inventory.description'), icon: _jsx(CardIcons.options, {}), color: "cyan", children: _jsx(Switch, { checked: base.watch('trackInventory') ?? false, onCheckedChange: (val) => base.setField('trackInventory', val) }) }), _jsx(EntityCustomFields, { id: entity?.id, entityName: "globalSettings", hideButton: true, initialValues: entity && 'customFields' in entity ? { customFields: entity.customFields } : { customFields: {} }, onChange: (cf) => {
29
+ base.setField('customFields', cf);
29
30
  }, additionalData: {} })] }));
30
31
  };
@@ -48,10 +48,10 @@ export const GlobalSettings = () => {
48
48
  onSubmitted: async (state) => {
49
49
  const res = await update({
50
50
  input: {
51
- availableLanguages: state.availableLanguages?.value,
52
- outOfStockThreshold: state.outOfStockThreshold?.value,
53
- trackInventory: state.trackInventory?.value,
54
- ...(state.customFields?.validatedValue ? { customFields: state.customFields?.validatedValue } : {}),
51
+ availableLanguages: state.availableLanguages,
52
+ outOfStockThreshold: state.outOfStockThreshold,
53
+ trackInventory: state.trackInventory,
54
+ ...(state.customFields ? { customFields: state.customFields } : {}),
55
55
  },
56
56
  });
57
57
  if (res.updateGlobalSettings.__typename === 'GlobalSettings') {
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Permission, SortOrder, typedGql, scalars } from '@deenruv/admin-types';
3
3
  import { Routes, apiClient, DetailList, deepMerge, OrderStateBadge, priceFormatter, TableLabel, useQuery, ListLocations, useTranslation, MultipleSelector, useServer, } from '@deenruv/react-ui-devkit';
4
4
  import { useCallback } from 'react';
5
+ import { useShallow } from 'zustand/react/shallow';
5
6
  import { useNavigate } from 'react-router';
6
7
  import { toast } from 'sonner';
7
8
  const tableId = 'orders-list-view';
@@ -37,7 +38,7 @@ export const OrdersListPage = () => {
37
38
  const { t } = useTranslation('table');
38
39
  const { t: tCommon } = useTranslation('common');
39
40
  const navigate = useNavigate();
40
- const orderStates = useServer((state) => state.serverConfig?.orderProcess.map((p) => p.name) ?? []);
41
+ const orderStates = useServer(useShallow((state) => state.serverConfig?.orderProcess.map((p) => p.name) ?? []));
41
42
  const getMethodName = useCallback((code) => code
42
43
  ? (data?.paymentMethods.items.find((i) => i.code === code)?.name ??
43
44
  code?.replace(/-/g, ' ').replace(/\b\w/g, (char) => char.toUpperCase()))
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Card, Button, Tabs, TabsList, TabsTrigger, TabsContent, CardDescription, ScrollArea, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, apiClient, useOrder, cn, CustomCard, useGFFLP, useTranslation, useMutation, } from '@deenruv/react-ui-devkit';
3
+ import { Card, Button, Tabs, TabsList, TabsTrigger, TabsContent, CardDescription, ScrollArea, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, apiClient, useOrder, cn, CustomCard, useDeenruvForm, z, useTranslation, useMutation, } from '@deenruv/react-ui-devkit';
4
4
  import { addressBaseSelector } from "../../../graphql/draft_order";
5
5
  import { Edit, MapPin, Building, Check, Loader2, User, Phone, Globe } from 'lucide-react';
6
6
  import { useEffect, useMemo, useState } from 'react';
@@ -31,60 +31,46 @@ export const AddressCard = ({ type }) => {
31
31
  }, [currentOrder, type]);
32
32
  const [selectedAddress, setSelectedAddress] = useState(undefined);
33
33
  const isShipping = type === 'shipping';
34
- const { state, setState } = useGFFLP('CreateAddressInput', 'city', 'company', 'countryCode', 'postalCode', 'fullName', 'phoneNumber', 'postalCode', 'streetLine1', 'streetLine2', 'province', 'customFields')({
35
- fullName: {
36
- initialValue: '',
37
- validate: (v) => {
38
- if (!v || v === '')
39
- return [t('selectAddress.nameRequired')];
40
- },
41
- },
42
- company: { initialValue: '' },
43
- streetLine1: {
44
- initialValue: '',
45
- validate: (v) => {
46
- if (!v || v === '')
47
- return [t('selectAddress.streetRequired')];
48
- },
49
- },
50
- streetLine2: { initialValue: '' },
51
- postalCode: {
52
- initialValue: '',
53
- validate: (v) => {
54
- if (!v || v === '')
55
- return [t('selectAddress.postalCodeRequired')];
56
- },
57
- },
58
- countryCode: {
59
- initialValue: '',
60
- validate: (v) => {
61
- if (!v || v === '')
62
- return [t('selectAddress.countryRequired')];
63
- },
64
- },
65
- phoneNumber: {
66
- initialValue: '',
67
- validate: (v) => {
68
- if (!v || v === '')
69
- return [t('selectAddress.phoneNumberRequired')];
70
- },
71
- },
72
- city: {
73
- initialValue: '',
74
- validate: (v) => {
75
- if (!v || v === '')
76
- return [t('selectAddress.cityRequired')];
77
- },
34
+ const addressSchema = z.object({
35
+ city: z.string().min(1, t('selectAddress.cityRequired')),
36
+ company: z.string().default(''),
37
+ countryCode: z.string().min(1, t('selectAddress.countryRequired')),
38
+ postalCode: z.string().min(1, t('selectAddress.postalCodeRequired')),
39
+ fullName: z.string().min(1, t('selectAddress.nameRequired')),
40
+ phoneNumber: z.string().min(1, t('selectAddress.phoneNumberRequired')),
41
+ streetLine1: z.string().min(1, t('selectAddress.streetRequired')),
42
+ streetLine2: z.string().default(''),
43
+ province: z.string().default(''),
44
+ customFields: z.record(z.string(), z.any()).default({}),
45
+ });
46
+ const form = useDeenruvForm({
47
+ schema: addressSchema,
48
+ defaultValues: {
49
+ fullName: '',
50
+ company: '',
51
+ streetLine1: '',
52
+ streetLine2: '',
53
+ postalCode: '',
54
+ countryCode: '',
55
+ phoneNumber: '',
56
+ city: '',
57
+ province: '',
58
+ customFields: {},
78
59
  },
79
- province: { initialValue: '' },
80
- customFields: { initialValue: {} },
81
60
  });
82
61
  useEffect(() => {
83
62
  if (selectedAddress) {
84
- setState({
85
- ...selectedAddress,
63
+ form.reset({
64
+ ...form.getValues(),
65
+ fullName: selectedAddress.fullName ?? '',
66
+ company: selectedAddress.company ?? '',
67
+ streetLine1: selectedAddress.streetLine1 ?? '',
68
+ streetLine2: selectedAddress.streetLine2 ?? '',
69
+ city: selectedAddress.city ?? '',
70
+ postalCode: selectedAddress.postalCode ?? '',
71
+ province: selectedAddress.province ?? '',
72
+ phoneNumber: selectedAddress.phoneNumber ?? '',
86
73
  countryCode: selectedAddress.country?.code || '',
87
- streetLine1: selectedAddress.streetLine1 || '',
88
74
  });
89
75
  }
90
76
  }, [selectedAddress]);
@@ -93,17 +79,20 @@ export const AddressCard = ({ type }) => {
93
79
  return;
94
80
  if (!!order?.customer?.addresses?.length && tab === 'select' && !selectedAddress)
95
81
  return;
82
+ const values = form.getValues();
96
83
  const input = {
97
- fullName: state.fullName?.validatedValue,
98
- company: state.company?.validatedValue,
99
- streetLine1: state.streetLine1?.validatedValue || '',
100
- streetLine2: state.streetLine2?.validatedValue,
101
- countryCode: state.countryCode?.validatedValue || '',
102
- city: state.city?.validatedValue,
103
- phoneNumber: state.phoneNumber?.validatedValue,
104
- postalCode: state.postalCode?.validatedValue,
105
- province: state.province?.validatedValue,
106
- ...('customFields' in state ? { customFields: state.customFields.value } : {}),
84
+ fullName: values.fullName,
85
+ company: values.company,
86
+ streetLine1: values.streetLine1 || '',
87
+ streetLine2: values.streetLine2,
88
+ countryCode: values.countryCode || '',
89
+ city: values.city,
90
+ phoneNumber: values.phoneNumber,
91
+ postalCode: values.postalCode,
92
+ province: values.province,
93
+ ...(values.customFields && Object.keys(values.customFields).length > 0
94
+ ? { customFields: values.customFields }
95
+ : {}),
107
96
  };
108
97
  if (!order?.customer?.addresses?.length) {
109
98
  await createAddress({ customerId: order.customer.id, input }).then((resp) => {
@@ -119,7 +108,7 @@ export const AddressCard = ({ type }) => {
119
108
  const setAddress = type === 'shipping' ? setShippingAddress : setBillingAddress;
120
109
  setAddress({
121
110
  ...address,
122
- countryCode: state.countryCode?.validatedValue || 'PL',
111
+ countryCode: values.countryCode || 'PL',
123
112
  });
124
113
  setOrder({
125
114
  ...currentOrder,
@@ -210,15 +199,33 @@ export const AddressCard = ({ type }) => {
210
199
  if (sameAddressInSaved) {
211
200
  setTab('select');
212
201
  setSelectedAddress(sameAddressInSaved);
213
- setState({ countryCode: sameAddressInSaved.country?.code || '', ...sameAddressInSaved });
202
+ form.reset({
203
+ countryCode: sameAddressInSaved.country?.code || '',
204
+ fullName: sameAddressInSaved.fullName ?? '',
205
+ company: sameAddressInSaved.company ?? '',
206
+ streetLine1: sameAddressInSaved.streetLine1 ?? '',
207
+ streetLine2: sameAddressInSaved.streetLine2 ?? '',
208
+ city: sameAddressInSaved.city ?? '',
209
+ postalCode: sameAddressInSaved.postalCode ?? '',
210
+ province: sameAddressInSaved.province ?? '',
211
+ phoneNumber: sameAddressInSaved.phoneNumber ?? '',
212
+ customFields: {},
213
+ });
214
214
  }
215
215
  else {
216
216
  setSelectedAddress(undefined);
217
217
  if (currentAddress) {
218
- setState({
219
- ...currentAddress,
220
- countryCode: currentAddress.countryCode || '',
218
+ form.reset({
219
+ fullName: currentAddress.fullName ?? '',
220
+ company: currentAddress.company ?? '',
221
221
  streetLine1: currentAddress.streetLine1 || '',
222
+ streetLine2: currentAddress.streetLine2 ?? '',
223
+ city: currentAddress.city ?? '',
224
+ postalCode: currentAddress.postalCode ?? '',
225
+ province: currentAddress.province ?? '',
226
+ phoneNumber: currentAddress.phoneNumber ?? '',
227
+ countryCode: currentAddress.countryCode || '',
228
+ customFields: {},
222
229
  });
223
230
  }
224
231
  }
@@ -239,22 +246,60 @@ export const AddressCard = ({ type }) => {
239
246
  ? 'border-primary bg-primary/5 shadow-sm'
240
247
  : 'border-border'), onClick: () => setSelectedAddress(address), children: [_jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx(User, { className: `size-4 ${iconColor}` }), _jsx("p", { className: "font-medium", children: address.fullName }), selectedAddress?.id === address.id && (_jsx("div", { className: "ml-auto", children: _jsx(Check, { className: "size-4 text-green-500" }) }))] }), _jsx(CardDescription, { className: "text-sm", children: `${address.streetLine1} ${address.streetLine2 ? ', ' + address.streetLine2 : ''}` }), _jsx(CardDescription, { className: "text-sm", children: `${address.postalCode} ${address.city} ${address.country?.name || address.country?.code}` }), _jsx(CardDescription, { className: "text-sm", children: `${t('selectAddress.phoneNumberShort', { value: address.phoneNumber })} ${address.company ? '• ' + address.company : ''} ` }), _jsxs("div", { className: "mt-2 flex gap-2", children: [address.defaultBillingAddress && (_jsx("span", { className: "rounded-full bg-cyan-100 px-2 py-0.5 text-xs text-cyan-800 dark:bg-cyan-900/50 dark:text-cyan-300", children: t('selectAddress.isDefaultBilling') })), address.defaultShippingAddress && (_jsx("span", { className: "rounded-full bg-purple-100 px-2 py-0.5 text-xs text-purple-800 dark:bg-purple-900/50 dark:text-purple-300", children: t('selectAddress.isDefaultShipping') }))] })] }), _jsx(Button, { variant: "ghost", size: "icon", className: "size-8", onClick: (e) => {
241
248
  e.stopPropagation();
242
- setState({ countryCode: address.country?.code || '', ...address });
249
+ form.reset({
250
+ countryCode: address.country?.code || '',
251
+ fullName: address.fullName ?? '',
252
+ company: address.company ?? '',
253
+ streetLine1: address.streetLine1 ?? '',
254
+ streetLine2: address.streetLine2 ?? '',
255
+ city: address.city ?? '',
256
+ postalCode: address.postalCode ?? '',
257
+ province: address.province ?? '',
258
+ phoneNumber: address.phoneNumber ?? '',
259
+ customFields: {},
260
+ });
243
261
  setTab('create');
244
262
  }, children: _jsx(Edit, { size: 16, className: iconColor }) })] }, `${address.id}-${index}`))) }) }) }), _jsx(TabsContent, { value: "create", className: cn('flex flex-1 flex-col overflow-hidden focus-visible:ring-transparent', tab !== 'create' && 'hidden'), children: _jsx(ScrollArea, { className: "pr-4", children: _jsx(AddressForm, { initialValues: {
245
- country: { code: state.countryCode.validatedValue },
246
- streetLine1: state.streetLine1.validatedValue,
247
- streetLine2: state.streetLine2.validatedValue,
248
- city: state.city.validatedValue,
249
- company: state.company.validatedValue,
250
- fullName: state.fullName.validatedValue,
251
- phoneNumber: state.phoneNumber.validatedValue,
252
- postalCode: state.postalCode.validatedValue,
253
- province: state.province?.validatedValue,
254
- ...(state.customFields?.validatedValue
255
- ? { customFields: state.customFields?.validatedValue }
263
+ country: { code: form.getValues('countryCode') },
264
+ streetLine1: form.getValues('streetLine1'),
265
+ streetLine2: form.getValues('streetLine2'),
266
+ city: form.getValues('city'),
267
+ company: form.getValues('company'),
268
+ fullName: form.getValues('fullName'),
269
+ phoneNumber: form.getValues('phoneNumber'),
270
+ postalCode: form.getValues('postalCode'),
271
+ province: form.getValues('province'),
272
+ ...(form.getValues('customFields') &&
273
+ Object.keys(form.getValues('customFields') ?? {}).length > 0
274
+ ? { customFields: form.getValues('customFields') }
275
+ : {}),
276
+ }, onInputChange: (input) => form.reset({
277
+ ...form.getValues(),
278
+ fullName: input.fullName ?? '',
279
+ company: input.company ?? '',
280
+ streetLine1: input.streetLine1 ?? '',
281
+ streetLine2: input.streetLine2 ?? '',
282
+ city: input.city ?? '',
283
+ postalCode: input.postalCode ?? '',
284
+ province: input.province ?? '',
285
+ phoneNumber: input.phoneNumber ?? '',
286
+ countryCode: input.countryCode ?? '',
287
+ ...(input.customFields
288
+ ? { customFields: input.customFields }
256
289
  : {}),
257
- }, onInputChange: setState }) }) })] })) : (_jsx(AddressForm, { onInputChange: setState }))] }), _jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [_jsx(Button, { variant: "outline", onClick: () => setOpen(false), disabled: submitting, children: t('common.cancel', 'Cancel') }), _jsx(Button, { className: "gap-2", disabled: submitting || (!!order?.customer?.addresses?.length && tab === 'select' && !selectedAddress), onClick: submitAddress, children: submitting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "size-4 animate-spin" }), t('common.submitting')] })) : (_jsxs(_Fragment, { children: [_jsx(Check, { className: "size-4" }), !order?.customer?.addresses?.length
290
+ }) }) }) })] })) : (_jsx(AddressForm, { onInputChange: (input) => form.reset({
291
+ ...form.getValues(),
292
+ fullName: input.fullName ?? '',
293
+ company: input.company ?? '',
294
+ streetLine1: input.streetLine1 ?? '',
295
+ streetLine2: input.streetLine2 ?? '',
296
+ city: input.city ?? '',
297
+ postalCode: input.postalCode ?? '',
298
+ province: input.province ?? '',
299
+ phoneNumber: input.phoneNumber ?? '',
300
+ countryCode: input.countryCode ?? '',
301
+ ...(input.customFields ? { customFields: input.customFields } : {}),
302
+ }) }))] }), _jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [_jsx(Button, { variant: "outline", onClick: () => setOpen(false), disabled: submitting, children: t('common.cancel', 'Cancel') }), _jsx(Button, { className: "gap-2", disabled: submitting || (!!order?.customer?.addresses?.length && tab === 'select' && !selectedAddress), onClick: submitAddress, children: submitting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "size-4 animate-spin" }), t('common.submitting')] })) : (_jsxs(_Fragment, { children: [_jsx(Check, { className: "size-4" }), !order?.customer?.addresses?.length
258
303
  ? 'Create'
259
304
  : t(tab === 'select' ? 'selectAddress.selectAddress' : 'selectAddress.editAddress')] })) })] })] })] })), children: _jsx("div", { className: "rounded-lg border border-border bg-muted/50 p-3", children: _jsx("div", { className: "flex items-start gap-3", children: !currentAddress ? (_jsxs(_Fragment, { children: [_jsx("div", { className: `mt-0.5 flex size-8 items-center justify-center rounded-full ${isShipping ? 'bg-purple-100 dark:bg-purple-900/30' : 'bg-cyan-100 dark:bg-cyan-900/30'}`, children: isShipping ? (_jsx(MapPin, { className: `size-4 ${iconColor}` })) : (_jsx(Building, { className: `size-4 ${iconColor}` })) }), _jsxs("div", { className: "flex-1", children: [_jsx("p", { className: "text-sm text-muted-foreground italic", children: t(isShipping ? 'selectAddress.noShippingAddress' : 'selectAddress.noBillingAddress') }), mode !== 'view' && (_jsxs(Button, { variant: "outline", size: "sm", className: "mt-2 gap-2", onClick: () => setOpen(true), children: [_jsx(Edit, { className: "size-3.5" }), t('selectAddress.addAddress', 'Add Address')] }))] })] })) : (_jsx(_Fragment, { children: _jsx("div", { className: "flex-1", children: _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(User, { className: `max-h-4 min-h-4 max-w-4 min-w-4 ${iconColor}` }), _jsx("p", { className: "text-sm font-medium", children: currentAddress?.fullName })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(MapPin, { className: `max-h-4 min-h-4 max-w-4 min-w-4 ${iconColor}` }), _jsxs("p", { className: "text-sm", children: [currentAddress.streetLine1, " ", currentAddress?.streetLine2] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Globe, { className: `max-h-4 min-h-4 max-w-4 min-w-4 ${iconColor}` }), _jsxs("p", { className: "text-sm", children: [currentAddress.city, " ", currentAddress.postalCode, " ", currentAddress.province, ' ', currentAddress.country] })] }), _jsx("div", { className: "mt-1 flex items-center justify-between border-t border-border pt-1", children: _jsxs("div", { className: "flex items-center gap-2", children: [currentAddress.company && (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Building, { className: "size-4 text-muted-foreground" }), _jsx("span", { className: "text-sm text-muted-foreground", children: currentAddress.company })] })), currentAddress.phoneNumber && (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Phone, { className: "size-4 text-muted-foreground" }), _jsx("span", { className: "text-sm text-muted-foreground", children: t('selectAddress.phoneNumberShort', { value: currentAddress.phoneNumber }) })] }))] }) })] }) }) })) }) }) }));
260
305
  };