@deenruv/admin-dashboard 1.0.16 → 1.0.17-dev.4

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 (48) hide show
  1. package/dist/DeenruvAdminPanel.js +4 -4
  2. package/dist/components/GlobalSearch.js +5 -5
  3. package/dist/components/Menu/ActiveAdmins.js +1 -1
  4. package/dist/components/Menu/ChannelSwitcher.js +1 -1
  5. package/dist/components/Menu/LanguagesDropdown.js +1 -1
  6. package/dist/components/Menu/Navigation.js +4 -4
  7. package/dist/components/Menu/NavigationFooter.js +2 -2
  8. package/dist/components/Menu/Notifications.js +1 -1
  9. package/dist/components/Menu/index.js +12 -14
  10. package/dist/index.css +54 -44
  11. package/dist/locales/en/collections.json +7 -0
  12. package/dist/locales/en/common.json +1 -0
  13. package/dist/locales/en/orders.json +8 -0
  14. package/dist/locales/en/products.json +14 -2
  15. package/dist/locales/en/promotions.json +4 -0
  16. package/dist/locales/pl/collections.json +7 -0
  17. package/dist/locales/pl/common.json +1 -0
  18. package/dist/locales/pl/orders.json +8 -0
  19. package/dist/locales/pl/products.json +14 -2
  20. package/dist/locales/pl/promotions.json +4 -0
  21. package/dist/pages/Root.js +1 -1
  22. package/dist/pages/collections/Detail.js +20 -5
  23. package/dist/pages/collections/_components/CollectionDetailView.js +15 -2
  24. package/dist/pages/collections/_components/FiltersCard.js +51 -11
  25. package/dist/pages/customers/_components/PersonalDataCard.js +2 -1
  26. package/dist/pages/extensions/Extensions.js +3 -7
  27. package/dist/pages/orders/Detail.js +38 -5
  28. package/dist/pages/orders/List.js +1 -16
  29. package/dist/pages/orders/_components/CancelAndRefundDialog.js +1 -2
  30. package/dist/pages/orders/_components/OrderLineCustomFields.js +1 -1
  31. package/dist/pages/orders/_components/ProductsTable.js +1 -2
  32. package/dist/pages/orders/_components/RefundPaymentCard.js +1 -2
  33. package/dist/pages/products/Detail.js +58 -4
  34. package/dist/pages/products/_components/AssetsCard.js +15 -2
  35. package/dist/pages/products/_components/OptionsCard.js +7 -5
  36. package/dist/pages/products/_components/PriceCard.js +21 -8
  37. package/dist/pages/products/_components/ProductDetailView.js +7 -3
  38. package/dist/pages/products/_components/Variant.js +40 -19
  39. package/dist/pages/products/_components/VariantsTab.js +1 -1
  40. package/dist/pages/promotions/Detail.js +34 -3
  41. package/dist/pages/promotions/_components/EnabledCard.js +2 -2
  42. package/dist/pages/promotions/_components/PromotionDetailSidebar.js +2 -1
  43. package/dist/pages/roles/_components/PermissionsTable.js +0 -1
  44. package/dist/pages/shipping-methods/Detail.js +9 -5
  45. package/dist/pages/shipping-methods/_components/CalculatorCard.js +27 -11
  46. package/dist/pages/shipping-methods/_components/CheckerCard.js +28 -12
  47. package/dist/version.js +1 -1
  48. package/package.json +68 -68
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { DropdownMenuItem, Label, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuTrigger, apiClient, cn, CustomCard, CardIcons, AssetsModalInput, useTranslation, createDialogFromComponent, } from '@deenruv/react-ui-devkit';
2
+ import { DropdownMenuItem, Label, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuTrigger, apiClient, cn, CustomCard, CardIcons, AssetsModalInput, AssetUploadButton, useTranslation, createDialogFromComponent, } from '@deenruv/react-ui-devkit';
3
3
  import { assetsSelector } from "../../../graphql/base";
4
4
  import { ImageOff } from 'lucide-react';
5
5
  import { useCallback, useEffect, useState } from 'react';
@@ -31,5 +31,18 @@ export const AssetsCard = ({ featuredAssetId, assetsIds, onAddAsset, onFeaturedA
31
31
  const newAssets = assetsIds?.filter((aId) => aId !== id);
32
32
  onAssetsChange(newAssets || []);
33
33
  }, [assetsIds, onAssetsChange]);
34
- return (_jsx(CustomCard, { title: t('assets'), color: "green", icon: _jsx(CardIcons.asset, {}), children: _jsx("div", { className: "flex flex-col gap-6", children: _jsxs("div", { className: "flex gap-6", children: [_jsxs("div", { children: [_jsx(Label, { children: t('details.featuredAsset') }), _jsxs("div", { className: "flex flex-col pt-3", children: [_jsx("div", { className: "mb-4 flex h-36 min-w-36 items-center justify-center border border-solid border-gray-300 p-2 shadow", children: featureAsset?.preview ? (_jsx("img", { src: featureAsset.preview, className: "h-32", alt: "Main image preview" })) : (_jsxs("div", { className: "flex size-full flex-col items-center justify-center gap-2 bg-gray-200 p-3", children: [_jsx(ImageOff, { size: 32 }), t('details.noFeaturedAsset')] })) }), _jsx(AssetsModalInput, { setValue: (a) => onAddAsset(a?.id) })] })] }), _jsxs("div", { children: [_jsx(Label, { children: t('details.otherAssets') }), _jsx("div", { className: "flex gap-3 pt-3", children: assets?.length ? (assets.map((asset) => (_jsxs(DropdownMenu, { modal: false, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("div", { className: cn('flex h-20 min-w-20 cursor-pointer items-center justify-center border border-solid border-gray-300 p-2 shadow', asset.id === featuredAssetId && 'border-2 border-blue-500'), children: asset?.preview && _jsx("img", { src: asset.preview, className: "h-16" }) }) }), _jsx(DropdownMenuContent, { className: "w-56", side: "bottom", align: "end", children: _jsxs(DropdownMenuGroup, { children: [_jsx(DropdownMenuItem, { onClick: () => createDialogFromComponent(EditAssetDialog, asset, { className: 'max-w-4xl' }), children: t('details.editAsset') }), _jsx(DropdownMenuItem, { onClick: () => onFeaturedAssetChange(asset.id), children: t('details.setAsFeatured') }), _jsx(DropdownMenuItem, { onClick: () => handleRemoveAsset(asset.id), children: t('details.removeAsset') })] }) })] }, asset.id)))) : (_jsx("p", { children: t('details.noAssets') })) })] })] }) }) }));
34
+ const handleAssetAdded = useCallback((id) => {
35
+ if (!id)
36
+ return;
37
+ if (!assetsIds?.includes(id)) {
38
+ onAddAsset(id);
39
+ }
40
+ if (!featuredAssetId) {
41
+ onFeaturedAssetChange(id);
42
+ }
43
+ }, [assetsIds, featuredAssetId, onAddAsset, onFeaturedAssetChange]);
44
+ return (_jsx(CustomCard, { title: t('assets'), color: "green", icon: _jsx(CardIcons.asset, {}), children: _jsx("div", { className: "flex flex-col gap-6", children: _jsxs("div", { className: "flex gap-6", children: [_jsxs("div", { children: [_jsx(Label, { children: t('details.featuredAsset') }), _jsxs("div", { className: "flex flex-col pt-3", children: [_jsx("div", { className: "mb-4 flex h-36 min-w-36 items-center justify-center border border-solid border-gray-300 p-2 shadow", children: featureAsset?.preview ? (_jsx("img", { src: featureAsset.preview, className: "h-32", alt: "Main image preview" })) : (_jsxs("div", { className: "flex size-full flex-col items-center justify-center gap-2 bg-gray-200 p-3", children: [_jsx(ImageOff, { size: 32 }), t('details.noFeaturedAsset')] })) }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(AssetsModalInput, { setValue: (a) => handleAssetAdded(a?.id) }), _jsx(AssetUploadButton, { buttonProps: { size: 'sm' }, cb: (asset) => {
45
+ handleAssetAdded(asset.id);
46
+ return {};
47
+ }, children: t('details.uploadAsset') })] })] })] }), _jsxs("div", { children: [_jsx(Label, { children: t('details.otherAssets') }), _jsx("div", { className: "flex gap-3 pt-3", children: assets?.length ? (assets.map((asset) => (_jsxs(DropdownMenu, { modal: false, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("div", { className: cn('flex h-20 min-w-20 cursor-pointer items-center justify-center border border-solid border-gray-300 p-2 shadow', asset.id === featuredAssetId && 'border-2 border-blue-500'), children: asset?.preview && _jsx("img", { src: asset.preview, className: "h-16" }) }) }), _jsx(DropdownMenuContent, { className: "w-56", side: "bottom", align: "end", children: _jsxs(DropdownMenuGroup, { children: [_jsx(DropdownMenuItem, { onClick: () => createDialogFromComponent(EditAssetDialog, asset, { className: 'max-w-4xl' }), children: t('details.editAsset') }), _jsx(DropdownMenuItem, { onClick: () => onFeaturedAssetChange(asset.id), children: t('details.setAsFeatured') }), _jsx(DropdownMenuItem, { onClick: () => handleRemoveAsset(asset.id), children: t('details.removeAsset') })] }) })] }, asset.id)))) : (_jsx("p", { children: t('details.noAssets') })) })] })] }) }) }));
35
48
  };
@@ -1,10 +1,12 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useState } from 'react';
3
- import { Table, TableBody, TableCell, TableRow, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, apiClient, CustomCard, CardIcons, useTranslation, } from '@deenruv/react-ui-devkit';
3
+ import { Table, TableBody, TableCell, TableRow, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, apiClient, CustomCard, CardIcons, useTranslation, useSettings, } from '@deenruv/react-ui-devkit';
4
4
  import { OptionGroupSelector } from "../../../graphql/products";
5
5
  import { toast } from 'sonner';
6
+ import { AddOptionGroupDialog } from "./AddOptionGroupDialog";
6
7
  export const OptionsCard = ({ optionGroups: options, productId, onChange, optionIds, createMode, }) => {
7
8
  const { t } = useTranslation('products');
9
+ const contentLng = useSettings((p) => p.translationsLanguage);
8
10
  const [optionGroups, setOptionGroups] = useState();
9
11
  const fetchOptionGroups = useCallback(async () => {
10
12
  if (productId) {
@@ -23,7 +25,7 @@ export const OptionsCard = ({ optionGroups: options, productId, onChange, option
23
25
  toast.error(t('toasts.fetchProductErrorToast'));
24
26
  }
25
27
  }
26
- }, [productId]);
28
+ }, [productId, t]);
27
29
  useEffect(() => {
28
30
  fetchOptionGroups();
29
31
  }, [fetchOptionGroups]);
@@ -32,7 +34,7 @@ export const OptionsCard = ({ optionGroups: options, productId, onChange, option
32
34
  newState[groupIdx] = optionId;
33
35
  onChange(newState);
34
36
  }, [optionIds, onChange]);
35
- return (_jsx(CustomCard, { title: t('options'), icon: _jsx(CardIcons.options, {}), color: "orange", children: !createMode ? (_jsx(Table, { children: _jsx(TableBody, { children: options?.map((o) => (_jsxs(TableRow, { children: [_jsxs(TableCell, { className: "font-semibold capitalize", children: [o.group.name, ":"] }), _jsx(TableCell, { className: "capitalize", children: o.name })] }, o.name))) }) })) : (optionGroups?.map((group, i) => (_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("div", { className: "w-1/3 font-semibold", children: [group.name, ":"] }), _jsx("div", { className: "w-2/3", children: _jsxs(Select, { value: optionIds?.[i] || '', onValueChange: (e) => {
36
- handleOptionChange(e, i);
37
- }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: t('addVariantDialog.selectOption') }) }), _jsx(SelectContent, { children: group.options.map((o) => (_jsx(SelectItem, { value: o.id, className: "capitalize", children: o.name }, o.id))) })] }) })] }, group.name)))) }));
37
+ return (_jsx(CustomCard, { title: t('options'), icon: _jsx(CardIcons.options, {}), color: "orange", upperRight: createMode ? (_jsx(AddOptionGroupDialog, { currentTranslationLng: contentLng, onSuccess: fetchOptionGroups, productId: productId })) : undefined, children: !createMode ? (_jsx(Table, { children: _jsx(TableBody, { children: options?.map((o) => (_jsxs(TableRow, { children: [_jsxs(TableCell, { className: "font-semibold capitalize", children: [o.group.name, ":"] }), _jsx(TableCell, { className: "capitalize", children: o.name })] }, o.name))) }) })) : optionGroups === undefined ? null : optionGroups.length ? (_jsx("div", { className: "flex flex-col gap-3", children: optionGroups.map((group, i) => (_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("div", { className: "w-1/3 font-semibold", children: [group.name, ":"] }), _jsx("div", { className: "w-2/3", children: _jsxs(Select, { value: optionIds?.[i] || '', onValueChange: (e) => {
38
+ handleOptionChange(e, i);
39
+ }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: t('addVariantDialog.selectOption') }) }), _jsx(SelectContent, { children: group.options.map((o) => (_jsx(SelectItem, { value: o.id, className: "capitalize", children: o.name }, o.id))) })] }) })] }, group.name))) })) : (_jsx("p", { className: "text-sm text-muted-foreground", children: t('addVariantDialog.createOptionsHint') })) }));
38
40
  };
@@ -1,13 +1,20 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, apiClient, CustomCard, CardIcons, useTranslation, } from '@deenruv/react-ui-devkit';
3
- import { useCallback, useEffect, useState } from 'react';
4
- export const PriceCard = ({ priceValue, onPriceChange, currencyCode, taxRateValue, onTaxRateChange, }) => {
3
+ import { useCallback, useEffect, useMemo, useState } from 'react';
4
+ export const PriceCard = ({ priceValue, onPriceChange, currencyCode, taxRateValue, onTaxRateChange, showDefaultPriceWhenEmpty = false, }) => {
5
5
  const { t } = useTranslation('products');
6
6
  const [taxCategories, setTaxCategories] = useState([]);
7
7
  const [currentTaxCategory, setCurrentTaxCategory] = useState();
8
+ const defaultPrice = useMemo(() => ({
9
+ currencyCode,
10
+ price: 0,
11
+ }), [currencyCode]);
12
+ const pricesToRender = useMemo(() => (priceValue?.length ? priceValue : showDefaultPriceWhenEmpty ? [defaultPrice] : []), [defaultPrice, priceValue, showDefaultPriceWhenEmpty]);
8
13
  useEffect(() => {
9
- fetchTaxRates();
10
- }, []);
14
+ if (showDefaultPriceWhenEmpty && !priceValue?.length) {
15
+ onPriceChange([defaultPrice]);
16
+ }
17
+ }, [defaultPrice, onPriceChange, priceValue?.length, showDefaultPriceWhenEmpty]);
11
18
  const fetchTaxRates = useCallback(async () => {
12
19
  const response = await apiClient('query')({
13
20
  taxCategories: [{}, { items: { id: true, name: true } }],
@@ -19,9 +26,15 @@ export const PriceCard = ({ priceValue, onPriceChange, currencyCode, taxRateValu
19
26
  }));
20
27
  setTaxCategories(categoriesWithRates);
21
28
  }, []);
29
+ useEffect(() => {
30
+ fetchTaxRates();
31
+ }, [fetchTaxRates]);
32
+ useEffect(() => {
33
+ setCurrentTaxCategory(taxCategories.find((category) => category.id === taxRateValue));
34
+ }, [taxCategories, taxRateValue]);
22
35
  const handlePriceChange = useCallback((currencyCode, value) => {
23
- const newPrices = priceValue?.map((p) => (p.currencyCode === currencyCode ? { ...p, price: value } : p));
24
- onPriceChange(newPrices || []);
25
- }, [priceValue, onPriceChange]);
26
- return (_jsx(CustomCard, { title: t('details.price'), color: "rose", icon: _jsx(CardIcons.calc, {}), children: _jsxs("div", { className: "flex flex-col gap-y-4", children: [priceValue?.map((price) => (_jsx("div", { className: "flex items-center gap-x-2", children: _jsx(Input, { type: "currency", placeholder: t('price'), value: price.price, onChange: (e) => handlePriceChange(price.currencyCode, +e.target.value), step: 0.01, startAdornment: price.currencyCode }) }, price.currencyCode))), _jsxs(Select, { value: taxRateValue, onValueChange: onTaxRateChange, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Tax rate" }) }), _jsx(SelectContent, { children: taxCategories.map((tR) => (_jsx(SelectItem, { value: tR.id.toString(), children: tR.name }, tR.id))) })] }), currentTaxCategory?.value !== undefined && `${t('details.taxRateDescription')} ${currentTaxCategory?.value}%`] }) }));
36
+ const newPrices = pricesToRender.map((p) => (p.currencyCode === currencyCode ? { ...p, price: value } : p));
37
+ onPriceChange(newPrices);
38
+ }, [onPriceChange, pricesToRender]);
39
+ return (_jsx(CustomCard, { title: t('details.price'), color: "rose", icon: _jsx(CardIcons.calc, {}), children: _jsxs("div", { className: "flex flex-col gap-y-4", children: [pricesToRender.map((price) => (_jsx("div", { className: "flex items-center gap-x-2", children: _jsx(Input, { type: "currency", placeholder: t('price'), value: price.price, onChange: (e) => handlePriceChange(price.currencyCode, +e.target.value), step: 0.01, startAdornment: price.currencyCode }) }, price.currencyCode))), _jsxs(Select, { value: taxRateValue, onValueChange: onTaxRateChange, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Tax rate" }) }), _jsx(SelectContent, { children: taxCategories.map((tR) => (_jsx(SelectItem, { value: tR.id.toString(), children: tR.name }, tR.id))) })] }), currentTaxCategory?.value !== undefined && `${t('details.taxRateDescription')} ${currentTaxCategory?.value}%`] }) }));
27
40
  };
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useDetailView, DetailViewMarker, useSettings, setInArrayBy, EntityCustomFields, normalizeString, } from '@deenruv/react-ui-devkit';
2
+ import { useDetailView, DetailViewMarker, useSettings, setInArrayBy, EntityCustomFields, normalizeString, CustomCard, CardIcons, Input, useTranslation, } from '@deenruv/react-ui-devkit';
3
3
  import { useCallback, useEffect, useMemo, useRef } from 'react';
4
4
  import { BasicFieldsCard } from './BasicFieldsCard';
5
5
  import { AssetsCard } from './AssetsCard';
@@ -13,9 +13,10 @@ export const PRODUCT_FORM_KEYS = [
13
13
  'customFields',
14
14
  ];
15
15
  export const ProductDetailView = () => {
16
+ const { t } = useTranslation('products');
16
17
  const contentLng = useSettings((p) => p.translationsLanguage);
17
18
  const selectedChannel = useSettings((p) => p.selectedChannel);
18
- const { entity, id, form, loading, fetchEntity } = useDetailView('products-detail-view', ...PRODUCT_FORM_KEYS);
19
+ const { entity, id, form, fetchEntity } = useDetailView('products-detail-view', ...PRODUCT_FORM_KEYS);
19
20
  const { base } = form;
20
21
  // --- Slug auto-generation ---
21
22
  // Track whether the user has manually edited the slug for the current language.
@@ -42,6 +43,7 @@ export const ProductDetailView = () => {
42
43
  })();
43
44
  }, [selectedChannel?.id, contentLng]);
44
45
  const translations = base.watch('translations') || [];
46
+ const initialVariantPrice = base.watch('initialVariantPrice') ?? 0;
45
47
  const currentTranslationValue = useMemo(() => {
46
48
  return translations.find((v) => v.languageCode === contentLng);
47
49
  }, [translations, contentLng]);
@@ -78,7 +80,9 @@ export const ProductDetailView = () => {
78
80
  }, [base, base.setField]);
79
81
  return (_jsx("div", { children: _jsxs("div", { className: "flex w-full flex-col gap-4", children: [_jsx(BasicFieldsCard, { currentTranslationValue: currentTranslationValue, onChange: setTranslationField, onSlugManualEdit: handleSlugManualEdit, errors: base.formState.errors?.translations?.message
80
82
  ? [base.formState.errors.translations.message]
81
- : undefined }), _jsx(DetailViewMarker, { position: 'products-detail-view' }), _jsx(EntityCustomFields, { id: id, entityName: "product", hideButton: true, onChange: (customFields, translations) => {
83
+ : undefined }), !id && (_jsx(CustomCard, { title: t('initialVariant.title'), icon: _jsx(CardIcons.tag, {}), color: "rose", children: _jsxs("div", { className: "flex flex-col gap-4 pt-4", children: [_jsx("p", { className: "text-sm text-muted-foreground", children: t('initialVariant.description') }), _jsxs("div", { className: "grid gap-4 md:grid-cols-3", children: [_jsx(Input, { label: t('initialVariant.sku'), value: base.watch('initialVariantSku') ?? '', onChange: (e) => base.setField('initialVariantSku', e.target.value), errors: base.formState.errors?.initialVariantSku?.message
84
+ ? [base.formState.errors.initialVariantSku.message]
85
+ : undefined, required: true }), _jsx(Input, { type: "currency", label: t('initialVariant.price'), value: initialVariantPrice, onChange: (e) => base.setField('initialVariantPrice', +e.target.value), startAdornment: selectedChannel?.currencyCode, step: 0.01 }), _jsx(Input, { label: t('initialVariant.name'), placeholder: t('initialVariant.namePlaceholder'), value: base.watch('initialVariantName') ?? '', onChange: (e) => base.setField('initialVariantName', e.target.value) })] })] }) })), _jsx(DetailViewMarker, { position: 'products-detail-view' }), _jsx(EntityCustomFields, { id: id, entityName: "product", hideButton: true, onChange: (customFields, translations) => {
82
86
  base.setField('customFields', customFields);
83
87
  if (translations)
84
88
  base.setField('translations', translations);
@@ -1,5 +1,5 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button, CardIcons, ConfirmationDialog, CustomCard, Input, apiClient, setInArrayBy, useDeenruvForm, z, EntityCustomFields, useTranslation, EntityChannelManager, } from '@deenruv/react-ui-devkit';
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Button, CardIcons, ConfirmationDialog, CustomCard, Input, apiClient, setInArrayBy, useDeenruvForm, z, EntityCustomFields, useTranslation, useSettings, EntityChannelManager, DEFAULT_CHANNEL_CODE, } from '@deenruv/react-ui-devkit';
3
3
  import { CurrencyCode } from '@deenruv/admin-types';
4
4
  import { useCallback, useEffect } from 'react';
5
5
  import { toast } from 'sonner';
@@ -10,6 +10,7 @@ import { OptionsCard } from "./OptionsCard";
10
10
  import { FacetValuesCard } from "./FacetValuesCard";
11
11
  export const Variant = ({ variant, currentTranslationLng, onActionCompleted, productId }) => {
12
12
  const { t } = useTranslation('products');
13
+ const selectedChannel = useSettings((p) => p.selectedChannel);
13
14
  const variantSchema = z.object({
14
15
  translations: z.array(z.any()).default([]),
15
16
  price: z.any().optional(),
@@ -50,6 +51,8 @@ export const Variant = ({ variant, currentTranslationLng, onActionCompleted, pro
50
51
  const formValues = form.watch();
51
52
  const translations = formValues.translations || [];
52
53
  const currentTranslationValue = translations.find((v) => v.languageCode === currentTranslationLng);
54
+ const variantDisplayName = currentTranslationValue?.name || variant?.name || t('addVariantDialog.new');
55
+ const variantDisplaySku = formValues.sku || variant?.sku;
53
56
  useEffect(() => {
54
57
  if (!variant)
55
58
  return;
@@ -67,18 +70,20 @@ export const Variant = ({ variant, currentTranslationLng, onActionCompleted, pro
67
70
  form.setField('trackInventory', variant.trackInventory);
68
71
  form.setField('facetValueIds', variant.facetValues.map((f) => f.id));
69
72
  }, [variant]);
70
- const createVariant = useCallback(() => {
73
+ const createVariant = useCallback(async () => {
71
74
  const values = form.getValues();
72
- if (productId && values.sku && values.translations)
73
- return apiClient('mutation')({
75
+ const firstPrice = Array.isArray(values.prices) ? values.prices[0]?.price : undefined;
76
+ if (!productId || !values.sku || !values.translations)
77
+ return;
78
+ try {
79
+ const response = await apiClient('mutation')({
74
80
  createProductVariants: [
75
81
  {
76
82
  input: [
77
83
  {
78
84
  productId,
79
85
  translations: values.translations,
80
- // price: +values.price,
81
- prices: values.prices,
86
+ price: firstPrice,
82
87
  sku: values.sku,
83
88
  assetIds: values.assetIds,
84
89
  featuredAssetId: values.featuredAssetId,
@@ -100,15 +105,31 @@ export const Variant = ({ variant, currentTranslationLng, onActionCompleted, pro
100
105
  id: true,
101
106
  },
102
107
  ],
103
- })
104
- .then(() => {
105
- toast(t('toasts.createProductVariantSuccessToast'));
106
- onActionCompleted();
107
- })
108
- .catch(() => {
109
- toast(t('toasts.createProductVariantErrorToast'));
110
108
  });
111
- }, [form, productId, onActionCompleted, t]);
109
+ const createdVariantId = response.createProductVariants?.[0]?.id;
110
+ if (createdVariantId &&
111
+ selectedChannel?.id &&
112
+ selectedChannel.code &&
113
+ selectedChannel.code !== DEFAULT_CHANNEL_CODE) {
114
+ await apiClient('mutation')({
115
+ assignProductVariantsToChannel: [
116
+ {
117
+ input: {
118
+ productVariantIds: [createdVariantId],
119
+ channelId: selectedChannel.id,
120
+ },
121
+ },
122
+ { id: true },
123
+ ],
124
+ });
125
+ }
126
+ toast(t('toasts.createProductVariantSuccessToast'));
127
+ onActionCompleted();
128
+ }
129
+ catch {
130
+ toast(t('toasts.createProductVariantErrorToast'));
131
+ }
132
+ }, [form, productId, selectedChannel?.id, selectedChannel?.code, onActionCompleted, t]);
112
133
  const updateVariant = useCallback(() => {
113
134
  if (!variant)
114
135
  return;
@@ -183,15 +204,15 @@ export const Variant = ({ variant, currentTranslationLng, onActionCompleted, pro
183
204
  return;
184
205
  form.setField('assetIds', [...newIds, id]);
185
206
  };
186
- return (_jsxs("div", { className: "mt-4 flex flex-col gap-4", children: [_jsx("div", { className: "flex gap-3 self-end", children: variant ? (_jsxs(_Fragment, { children: [_jsx(ConfirmationDialog, { onConfirm: deleteVariant, children: _jsx(Button, { variant: 'destructive', children: t('forms.removeVariant') }) }), _jsx(Button, { onClick: updateVariant, children: t('forms.updateVariant') })] })) : (_jsx(Button, { onClick: createVariant, children: t('addVariantDialog.add') })) }), _jsxs("div", { className: "flex gap-4", children: [_jsxs("div", { className: "flex w-2/3 flex-col gap-4", children: [!!variant && (_jsx(StockCard, { priceValue: formValues.price, taxRateValue: formValues.taxCategoryId, outOfStockThresholdValue: formValues.outOfStockThreshold, stockLevelsValue: formValues.stockLevels, stockOnHandValue: formValues.stockOnHand, useGlobalOutOfStockThresholdValue: formValues.useGlobalOutOfStockThreshold, onThresholdChange: (e) => form.setField('outOfStockThreshold', +e.target.value), onUseGlobalChange: (e) => form.setField('useGlobalOutOfStockThreshold', e), onTrackInventoryChange: (e) => form.setField('trackInventory', e), onStockOnHandChange: (e) => form.setField('stockOnHand', +e.target.value), onStockLocationsChange: (e) => form.setField('stockLevels', e), allStockLocations: variant?.stockLevels, stockAllocated: variant?.stockAllocated, trackInventoryValue: formValues.trackInventory })), _jsx(PriceCard, { currencyCode: variant?.currencyCode || CurrencyCode.PLN, priceValue: formValues.prices, onPriceChange: (e) => form.setField('prices', e), taxRateValue: formValues.taxCategoryId ?? undefined, onTaxRateChange: (id) => form.setField('taxCategoryId', id) }), _jsx(AssetsCard, { onAddAsset: handleAddAsset, featuredAssetId: formValues.featuredAssetId, assetsIds: formValues.assetIds, onFeaturedAssetChange: (id) => form.setField('featuredAssetId', id), onAssetsChange: (ids) => form.setField('assetIds', ids) }), _jsx(EntityCustomFields, { entityName: "productVariant", id: variant?.id, hideButton: true, onChange: (customFields, translations) => {
207
+ return (_jsxs("div", { className: "mt-4 flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2 rounded-lg border bg-muted/30 p-4 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-xs font-medium tracking-wide text-muted-foreground uppercase", children: t('variants') }), _jsx("h3", { className: "truncate text-lg font-semibold", children: variantDisplayName })] }), _jsxs("div", { className: "text-sm text-muted-foreground sm:text-right", children: [_jsxs("span", { className: "font-medium text-foreground", children: [t('sku'), ":"] }), " ", variantDisplaySku || '—'] })] }), _jsx("div", { className: "flex gap-3 self-end", children: variant ? (_jsxs(_Fragment, { children: [_jsx(ConfirmationDialog, { onConfirm: deleteVariant, children: _jsx(Button, { variant: 'destructive', children: t('forms.removeVariant') }) }), _jsx(Button, { onClick: updateVariant, children: t('forms.updateVariant') })] })) : (_jsx(Button, { onClick: createVariant, children: t('addVariantDialog.add') })) }), _jsxs("div", { className: "flex gap-4", children: [_jsxs("div", { className: "flex w-2/3 flex-col gap-4", children: [!!variant && (_jsx(StockCard, { priceValue: formValues.price, taxRateValue: formValues.taxCategoryId, outOfStockThresholdValue: formValues.outOfStockThreshold, stockLevelsValue: formValues.stockLevels, stockOnHandValue: formValues.stockOnHand, useGlobalOutOfStockThresholdValue: formValues.useGlobalOutOfStockThreshold, onThresholdChange: (e) => form.setField('outOfStockThreshold', +e.target.value), onUseGlobalChange: (e) => form.setField('useGlobalOutOfStockThreshold', e), onTrackInventoryChange: (e) => form.setField('trackInventory', e), onStockOnHandChange: (e) => form.setField('stockOnHand', +e.target.value), onStockLocationsChange: (e) => form.setField('stockLevels', e), allStockLocations: variant?.stockLevels, stockAllocated: variant?.stockAllocated, trackInventoryValue: formValues.trackInventory })), _jsx(PriceCard, { currencyCode: variant?.currencyCode || CurrencyCode.PLN, priceValue: formValues.prices, onPriceChange: (e) => form.setField('prices', e), taxRateValue: formValues.taxCategoryId ?? undefined, onTaxRateChange: (id) => form.setField('taxCategoryId', id), showDefaultPriceWhenEmpty: !variant }), _jsx(AssetsCard, { onAddAsset: handleAddAsset, featuredAssetId: formValues.featuredAssetId, assetsIds: formValues.assetIds, onFeaturedAssetChange: (id) => form.setField('featuredAssetId', id), onAssetsChange: (ids) => form.setField('assetIds', ids) }), _jsx(EntityCustomFields, { entityName: "productVariant", id: variant?.id, hideButton: true, onChange: (customFields, translations) => {
187
208
  form.setField('customFields', customFields);
188
209
  if (translations)
189
210
  form.setField('translations', translations);
190
211
  }, initialValues: variant && 'customFields' in variant
191
212
  ? { customFields: variant.customFields, translations: variant.translations }
192
- : { customFields: {} } })] }), _jsxs("div", { className: "flex w-1/3 flex-col gap-4", children: [_jsx(CustomCard, { title: t('name'), icon: _jsx(CardIcons.basic, {}), color: "purple", children: _jsxs("div", { className: "flex flex-col gap-y-4", children: [_jsx(Input, { label: t('sku'), placeholder: t('sku'), value: formValues.sku ?? undefined, onChange: (e) => form.setField('sku', e.target.value) }), _jsx(Input, { label: t('name'), placeholder: t('name'), value: currentTranslationValue?.name ?? undefined, onChange: (e) => setTranslationField('name', e) })] }) }), _jsx(EntityChannelManager, { entity: "productVariant", entityId: variant?.id, entityChannels: variant?.channels ?? [], onRemoveSuccess: onActionCompleted, entityName: variant?.name, entityVariantList: {
213
+ : { customFields: {} } })] }), _jsxs("div", { className: "flex w-1/3 flex-col gap-4", children: [_jsx(CustomCard, { title: t('name'), icon: _jsx(CardIcons.basic, {}), color: "purple", children: _jsxs("div", { className: "flex flex-col gap-y-4", children: [_jsx(Input, { label: t('sku'), placeholder: t('sku'), value: formValues.sku ?? undefined, onChange: (e) => form.setField('sku', e.target.value) }), _jsx(Input, { label: t('name'), placeholder: t('name'), value: currentTranslationValue?.name ?? undefined, onChange: (e) => setTranslationField('name', e) })] }) }), variant && (_jsx(EntityChannelManager, { entity: "productVariant", entityId: variant.id, entityChannels: variant.channels ?? [], onRemoveSuccess: onActionCompleted, entityName: variant.name, entityVariantList: {
193
214
  items: [
194
- { price: variant?.price, priceWithTax: variant?.priceWithTax, currencyCode: variant?.currencyCode },
215
+ { price: variant.price, priceWithTax: variant.priceWithTax, currencyCode: variant.currencyCode },
195
216
  ],
196
- } }), _jsx(OptionsCard, { optionGroups: variant?.options || [], productId: productId, optionIds: formValues.optionIds ?? undefined, onChange: (e) => form.setField('optionIds', e), createMode: !variant }), !!variant && (_jsx(FacetValuesCard, { facetValuesIds: formValues.facetValueIds ?? undefined, onChange: (e) => form.setField('facetValueIds', e) }))] })] })] }));
217
+ } })), _jsx(OptionsCard, { optionGroups: variant?.options || [], productId: productId, optionIds: formValues.optionIds ?? undefined, onChange: (e) => form.setField('optionIds', e), createMode: !variant }), !!variant && (_jsx(FacetValuesCard, { facetValuesIds: formValues.facetValueIds ?? undefined, onChange: (e) => form.setField('facetValueIds', e) }))] })] })] }));
197
218
  };
@@ -42,5 +42,5 @@ export const VariantsTab = () => {
42
42
  useEffect(() => {
43
43
  fetchData();
44
44
  }, [fetchData]);
45
- return (_jsxs("div", { className: "flex flex-col", children: [getMarker(), _jsx("div", { className: "flex flex-col items-end gap-4", children: _jsxs(Tabs, { defaultValue: variants?.[0]?.id, className: "w-full", value: activeTab, onValueChange: handleTabChange, children: [_jsxs(TabsList, { className: "h-auto flex-wrap justify-start", children: [_jsxs(TabsTrigger, { value: NEW_VARIANT_TAB_VALUE, className: "text-blue-600", children: [_jsx(PlusCircle, { size: 16, className: "mr-2 translate-y-px" }), t('addVariantDialog.new')] }, 'new-variant'), variants?.map((v) => (_jsx(TabsTrigger, { value: v.id, children: v.name }, v.id + '-trigger')))] }), _jsx(TabsContent, { value: NEW_VARIANT_TAB_VALUE, children: id && _jsx(Variant, { currentTranslationLng: contentLanguage, onActionCompleted: fetchData, productId: id }) }, 'new-variant-content'), id && variants?.length ? (variants?.map((v) => (_jsx(TabsContent, { value: v.id, children: _jsx(Variant, { currentTranslationLng: contentLanguage, variant: v, onActionCompleted: fetchData, productId: id }) }, v.id + '-content')))) : (_jsx("div", { className: "flex w-full items-center justify-center", children: activeTab !== NEW_VARIANT_TAB_VALUE && (_jsx(EmptyState, { columnsLength: 1, title: t('variantsTab.emptyState.title'), description: t('variantsTab.emptyState.description') })) }))] }) })] }));
45
+ return (_jsxs("div", { className: "flex flex-col", children: [getMarker(), _jsx("div", { className: "flex flex-col items-end gap-4", children: _jsxs(Tabs, { defaultValue: variants?.[0]?.id, className: "w-full", value: activeTab, onValueChange: handleTabChange, children: [_jsxs(TabsList, { className: "h-auto flex-wrap justify-start", children: [_jsxs(TabsTrigger, { value: NEW_VARIANT_TAB_VALUE, className: "text-blue-600", children: [_jsx(PlusCircle, { size: 16, className: "mr-2 translate-y-px" }), t('addVariantDialog.new')] }, 'new-variant'), variants?.map((v) => (_jsx(TabsTrigger, { value: v.id, className: "max-w-xs", children: _jsxs("span", { className: "flex min-w-0 flex-col items-start text-left leading-tight", children: [_jsx("span", { className: "max-w-full truncate", children: v.name?.trim() || t('variantsTab.unnamedVariant') }), v.sku && (_jsx("span", { className: "max-w-full truncate text-xs font-normal text-muted-foreground", children: v.sku }))] }) }, v.id + '-trigger')))] }), _jsx(TabsContent, { value: NEW_VARIANT_TAB_VALUE, children: id && _jsx(Variant, { currentTranslationLng: contentLanguage, onActionCompleted: fetchData, productId: id }) }, 'new-variant-content'), id && variants?.length ? (variants?.map((v) => (_jsx(TabsContent, { value: v.id, children: _jsx(Variant, { currentTranslationLng: contentLanguage, variant: v, onActionCompleted: fetchData, productId: id }) }, v.id + '-content')))) : (_jsx("div", { className: "flex w-full items-center justify-center", children: activeTab !== NEW_VARIANT_TAB_VALUE && (_jsx(EmptyState, { columnsLength: 1, title: t('variantsTab.emptyState.title'), description: t('variantsTab.emptyState.description') })) }))] }) })] }));
46
46
  };
@@ -1,9 +1,38 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useParams } from 'react-router';
3
- import { useTranslation, useValidators, createDeenruvForm, DetailView, useMutation } from '@deenruv/react-ui-devkit';
3
+ import { useTranslation, useValidators, createDeenruvForm, DetailView, useMutation, useSettings, } from '@deenruv/react-ui-devkit';
4
4
  import { $, Permission, scalars, typedGql } from '@deenruv/admin-types';
5
5
  import { PromotionDetailView } from "./_components/PromotionDetailView";
6
6
  import { PromotionDetailSidebar } from "./_components/PromotionDetailSidebar";
7
+ const DEFAULT_PROMOTION_LANGUAGE_CODE = 'en';
8
+ const ensureDefaultPromotionTranslation = (translations, defaultLanguageCode) => {
9
+ const sourceTranslation = translations.find((translation) => !!translation.name?.trim()) ?? translations[0];
10
+ if (!sourceTranslation?.name?.trim())
11
+ return translations;
12
+ let hasDefaultLanguage = false;
13
+ const normalizedTranslations = translations.map((translation) => {
14
+ if (translation.languageCode !== defaultLanguageCode)
15
+ return translation;
16
+ hasDefaultLanguage = true;
17
+ if (translation.name?.trim())
18
+ return translation;
19
+ return {
20
+ ...translation,
21
+ name: sourceTranslation.name,
22
+ description: translation.description ?? sourceTranslation.description ?? '',
23
+ };
24
+ });
25
+ if (hasDefaultLanguage)
26
+ return normalizedTranslations;
27
+ return [
28
+ ...normalizedTranslations,
29
+ {
30
+ languageCode: defaultLanguageCode,
31
+ name: sourceTranslation.name,
32
+ description: sourceTranslation.description ?? '',
33
+ },
34
+ ];
35
+ };
7
36
  const EditPromotionMutation = typedGql('mutation', { scalars })({
8
37
  updatePromotion: [{ input: $('input', 'UpdatePromotionInput!') }, { '...on Promotion': { id: true } }],
9
38
  });
@@ -20,6 +49,7 @@ export const PromotionsDetailPage = () => {
20
49
  const [create] = useMutation(CreatePromotionMutation);
21
50
  const [remove] = useMutation(DeletePromotionMutation);
22
51
  const { translationsValidator, configurableOperationArrayValidator } = useValidators();
52
+ const defaultLanguageCode = useSettings((state) => state.selectedChannel?.defaultLanguageCode ?? DEFAULT_PROMOTION_LANGUAGE_CODE);
23
53
  return (_jsx("div", { className: "relative flex flex-col gap-y-4", children: _jsx(DetailView, { id: id, locationId: "promotions-detail-view", main: {
24
54
  name: 'promotion',
25
55
  label: 'Promotion',
@@ -50,9 +80,10 @@ export const PromotionsDetailPage = () => {
50
80
  throw new Error('Fill required fields.');
51
81
  const conditions = data.conditions;
52
82
  const actions = data.actions;
83
+ const translations = data.translations;
53
84
  const input = {
54
- translations: data.translations,
55
- enabled: data.enabled || false,
85
+ translations: id ? translations : ensureDefaultPromotionTranslation(translations, defaultLanguageCode),
86
+ enabled: typeof data.enabled === 'boolean' ? data.enabled : true,
56
87
  actions,
57
88
  conditions: conditions?.map((el) => ({
58
89
  ...el,
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useTranslation, Label, Switch, CustomCard, CardIcons } from '@deenruv/react-ui-devkit';
3
3
  export const EnabledCard = ({ onEnabledChange, enabledValue }) => {
4
- const { t } = useTranslation('products');
5
- return (_jsx(CustomCard, { title: t('details.basicInfo'), icon: _jsx(CardIcons.default, {}), color: "teal", children: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Switch, { id: "product-enabled", checked: enabledValue, onCheckedChange: onEnabledChange }), _jsx(Label, { htmlFor: "product-enabled", children: t('enabled') })] }) }));
4
+ const { t } = useTranslation('promotions');
5
+ return (_jsx(CustomCard, { title: t('enabled.header'), icon: _jsx(CardIcons.default, {}), color: "teal", children: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Switch, { id: "promotion-enabled", checked: enabledValue ?? false, onCheckedChange: onEnabledChange }), _jsx(Label, { htmlFor: "promotion-enabled", children: t('enabled.label') })] }) }));
6
6
  };
@@ -6,6 +6,7 @@ import { useEffect } from 'react';
6
6
  export const PromotionDetailSidebar = () => {
7
7
  const { id, form } = useDetailView('promotions-detail-view', 'CreatePromotionInput', 'enabled');
8
8
  const { base } = form;
9
+ const enabledValue = base.watch('enabled');
9
10
  // Always call useQuery unconditionally to preserve hook order.
10
11
  // Pass a placeholder id when none exists; the result will simply be ignored.
11
12
  const { data } = useQuery(PromotionQuery, { initialVariables: { id: id ?? '' } });
@@ -14,5 +15,5 @@ export const PromotionDetailSidebar = () => {
14
15
  base.setField('enabled', data.promotion.enabled);
15
16
  }
16
17
  }, [data, id]);
17
- return (_jsx("div", { className: "flex w-full flex-col gap-4", children: _jsx(EnabledCard, { enabledValue: base.watch('enabled'), onEnabledChange: (e) => base.setField('enabled', e) }) }));
18
+ return (_jsx("div", { className: "flex w-full flex-col gap-4", children: _jsx(EnabledCard, { enabledValue: id ? enabledValue : (enabledValue ?? true), onEnabledChange: (e) => base.setField('enabled', e) }) }));
18
19
  };
@@ -2,7 +2,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useState } from 'react';
3
3
  import { useTranslation, cn, Table, TableBody, TableCell, TableRow, useServer } from '@deenruv/react-ui-devkit';
4
4
  import { CircleCheckBig } from 'lucide-react';
5
- import permissionsJson from "../../../locales/en/permissions.json";
6
5
  export const PermissionsTable = ({ currentPermissions, onPermissionsChange }) => {
7
6
  const { t } = useTranslation('permissions');
8
7
  const [groupedPermissions, setGroupedPermissions] = useState();
@@ -3,6 +3,10 @@ import { useCallback } from 'react';
3
3
  import { useParams } from 'react-router';
4
4
  import { useTranslation, DetailView, createDeenruvForm, getMutation, useMutation } from '@deenruv/react-ui-devkit';
5
5
  import { ShippingMethodDetailView } from "./_components/ShippingMethodDetailView.js";
6
+ const isMissingConfigArgValue = (value) => value == null || value.trim() === '';
7
+ const hasMissingConfigArgs = (operation) => {
8
+ return !!operation?.arguments?.some((argument) => isMissingConfigArgValue(argument.value));
9
+ };
6
10
  const CreateShippingMethodMutation = getMutation('createShippingMethod');
7
11
  const EditShippingMethodMutation = getMutation('updateShippingMethod');
8
12
  const DeleteShippingMethodMutation = getMutation('deleteShippingMethod');
@@ -63,11 +67,11 @@ export const ShippingMethodsDetailPage = () => {
63
67
  checker: {
64
68
  validate: (v) => {
65
69
  const hasCode = !!v?.code;
66
- const hasArguments = v?.arguments.filter((a) => a.value).length;
70
+ const hasInvalidArguments = hasMissingConfigArgs(v);
67
71
  const errors = [];
68
72
  if (!hasCode)
69
73
  errors.push(t('validation.checkerCodeRequired'));
70
- if (!hasArguments)
74
+ if (hasInvalidArguments)
71
75
  errors.push(t('validation.checkerArgsRequired'));
72
76
  return errors;
73
77
  },
@@ -75,12 +79,12 @@ export const ShippingMethodsDetailPage = () => {
75
79
  calculator: {
76
80
  validate: (v) => {
77
81
  const hasCode = !!v?.code;
78
- const hasInvalidArguments = v?.arguments.filter((a) => !a.value || a.value === 'false').length; // args have 'false' value by default
82
+ const hasInvalidArguments = hasMissingConfigArgs(v);
79
83
  const errors = [];
80
84
  if (!hasCode)
81
- errors.push(t('validation.checkerCodeRequired'));
85
+ errors.push(t('validation.calculatorCodeRequired'));
82
86
  if (hasInvalidArguments)
83
- errors.push(t('validation.checkerArgsRequired'));
87
+ errors.push(t('validation.calculatorArgsRequired'));
84
88
  return errors;
85
89
  },
86
90
  },
@@ -1,7 +1,28 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useState } from 'react';
3
- import { Button, Label, apiClient, ErrorMessage, generateInputComponents, usePluginStore, CustomFieldsProvider, CardIcons, CustomCard, SimpleSelect, useTranslation, PaymentMethodHandlerSelector, } from '@deenruv/react-ui-devkit';
3
+ import { Button, apiClient, ErrorMessage, generateInputComponents, usePluginStore, InputFieldComponent, CardIcons, CustomCard, SimpleSelect, useTranslation, PaymentMethodHandlerSelector, } from '@deenruv/react-ui-devkit';
4
4
  import { X } from 'lucide-react';
5
+ const decodeConfigArgValue = (value) => {
6
+ try {
7
+ const result = JSON.parse(value);
8
+ if (result && typeof result === 'object' && !Array.isArray(result)) {
9
+ return JSON.stringify(result);
10
+ }
11
+ return result;
12
+ }
13
+ catch {
14
+ return value;
15
+ }
16
+ };
17
+ const encodeConfigArgValue = (value) => {
18
+ return Array.isArray(value) ? JSON.stringify(value) : (value ?? '').toString();
19
+ };
20
+ const createInitialArguments = (args) => {
21
+ return args.map((arg) => ({
22
+ name: arg.name,
23
+ value: encodeConfigArgValue(arg.defaultValue),
24
+ }));
25
+ };
5
26
  export const CalculatorCard = ({ currentCalculatorValue, onCalculatorValueChange, errors, }) => {
6
27
  const { t } = useTranslation('shippingMethods');
7
28
  const [calculators, setCalculators] = useState([]);
@@ -22,21 +43,16 @@ export const CalculatorCard = ({ currentCalculatorValue, onCalculatorValueChange
22
43
  }, [fetchOptions]);
23
44
  const handleCalculatorValueChange = useCallback((code, args) => {
24
45
  const correspondingCalculator = calculators.find((h) => h.code === code);
25
- console.log('args', args);
26
46
  if (correspondingCalculator)
27
47
  onCalculatorValueChange({
28
48
  code: correspondingCalculator.code,
29
- arguments: args ||
30
- correspondingCalculator.args.map((a) => ({
31
- name: a.name,
32
- value: 'false',
33
- })),
49
+ arguments: args ?? createInitialArguments(correspondingCalculator.args),
34
50
  });
35
51
  }, [calculators, onCalculatorValueChange]);
36
52
  const clearInput = useCallback(() => {
37
53
  onCalculatorValueChange(undefined);
38
54
  }, [onCalculatorValueChange]);
39
- return (_jsx(CustomCard, { title: t('details.calculator.title'), icon: _jsx(CardIcons.calc, {}), color: "indigo", children: _jsxs("div", { className: "flex basis-full flex-col gap-3 md:basis-1/2", children: [_jsxs("div", { className: "flex items-end gap-1", children: [_jsx(SimpleSelect, { label: t('details.calculator.type'), value: currentCalculatorValue ? currentCalculatorValue.code : '', onValueChange: handleCalculatorValueChange, options: allCalculatorsOptions }), currentCalculatorValue?.code && (_jsx(Button, { variant: 'secondary', className: "p-2", onClick: clearInput, children: _jsx(X, { size: 20 }) }))] }), _jsx("div", { className: "flex gap-3", children: currentCalculatorValue?.arguments.map((e, i) => {
55
+ return (_jsx(CustomCard, { title: t('details.calculator.title'), icon: _jsx(CardIcons.calc, {}), color: "indigo", children: _jsxs("div", { className: "flex basis-full flex-col gap-3 md:basis-1/2", children: [_jsxs("div", { className: "flex items-end gap-1", children: [_jsx(SimpleSelect, { label: t('details.calculator.type'), value: currentCalculatorValue ? currentCalculatorValue.code : '', onValueChange: handleCalculatorValueChange, options: allCalculatorsOptions }), currentCalculatorValue?.code && (_jsx(Button, { variant: 'secondary', className: "p-2", onClick: clearInput, children: _jsx(X, { size: 20 }) }))] }), _jsx("div", { className: "flex gap-3", children: currentCalculatorValue?.arguments.map((e) => {
40
56
  const calculator = calculators?.find((ch) => ch.code === currentCalculatorValue.code);
41
57
  const argument = calculator?.args.find((a) => a.name === e.name);
42
58
  if (!argument)
@@ -48,7 +64,7 @@ export const CalculatorCard = ({ currentCalculatorValue, onCalculatorValueChange
48
64
  description: [{ languageCode: 'en', value: argument.description || '' }],
49
65
  },
50
66
  ], getInputComponent).map((field) => {
51
- const value = e.value;
67
+ const value = decodeConfigArgValue(e.value);
52
68
  const setValue = (data) => {
53
69
  try {
54
70
  onCalculatorValueChange({
@@ -58,7 +74,7 @@ export const CalculatorCard = ({ currentCalculatorValue, onCalculatorValueChange
58
74
  if (a.name === field.name) {
59
75
  return {
60
76
  name: a.name,
61
- value: JSON.stringify(data),
77
+ value: encodeConfigArgValue(data),
62
78
  };
63
79
  }
64
80
  }
@@ -73,7 +89,7 @@ export const CalculatorCard = ({ currentCalculatorValue, onCalculatorValueChange
73
89
  console.error('Error setting value');
74
90
  }
75
91
  };
76
- return (_jsx(CustomFieldsProvider, { field: field, value: value, setValue: setValue, additionalData: {}, children: _jsxs("div", { children: [_jsx("div", { children: _jsx(Label, { children: field.name }) }), field.component] }, field.name) }, field.name));
92
+ return (_jsx(InputFieldComponent, { field: field, value: value, setValue: setValue, additionalData: {} }, field.name));
77
93
  });
78
94
  }) }), _jsx(ErrorMessage, { errors: errors })] }) }));
79
95
  };
@@ -1,7 +1,28 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useState } from 'react';
3
- import { Button, Label, apiClient, ErrorMessage, generateInputComponents, usePluginStore, CustomFieldsProvider, CustomCard, CardIcons, SimpleSelect, useTranslation, PaymentMethodHandlerSelector, } from '@deenruv/react-ui-devkit';
3
+ import { Button, apiClient, ErrorMessage, generateInputComponents, usePluginStore, InputFieldComponent, CustomCard, CardIcons, SimpleSelect, useTranslation, PaymentMethodHandlerSelector, } from '@deenruv/react-ui-devkit';
4
4
  import { X } from 'lucide-react';
5
+ const decodeConfigArgValue = (value) => {
6
+ try {
7
+ const result = JSON.parse(value);
8
+ if (result && typeof result === 'object' && !Array.isArray(result)) {
9
+ return JSON.stringify(result);
10
+ }
11
+ return result;
12
+ }
13
+ catch {
14
+ return value;
15
+ }
16
+ };
17
+ const encodeConfigArgValue = (value) => {
18
+ return Array.isArray(value) ? JSON.stringify(value) : (value ?? '').toString();
19
+ };
20
+ const createInitialArguments = (args) => {
21
+ return args.map((arg) => ({
22
+ name: arg.name,
23
+ value: encodeConfigArgValue(arg.defaultValue),
24
+ }));
25
+ };
5
26
  export const CheckerCard = ({ currentCheckerValue, onCheckerValueChange, errors }) => {
6
27
  const { t } = useTranslation('shippingMethods');
7
28
  const [checkers, setCheckers] = useState([]);
@@ -25,20 +46,15 @@ export const CheckerCard = ({ currentCheckerValue, onCheckerValueChange, errors
25
46
  if (correspondingChecker)
26
47
  onCheckerValueChange({
27
48
  code: correspondingChecker.code,
28
- arguments: args ||
29
- correspondingChecker.args.map((a) => ({
30
- name: a.name,
31
- value: 'false',
32
- })),
49
+ arguments: args ?? createInitialArguments(correspondingChecker.args),
33
50
  });
34
51
  }, [checkers, onCheckerValueChange]);
35
52
  const clearInput = useCallback(() => {
36
- console.log('CLICK');
37
53
  onCheckerValueChange(undefined);
38
54
  }, [onCheckerValueChange]);
39
- return (_jsx(CustomCard, { title: t('details.options.title'), icon: _jsx(CardIcons.check, {}), color: "teal", upperRight: _jsx(ErrorMessage, { errors: errors }), children: _jsxs("div", { className: "flex basis-full flex-col gap-3 md:basis-1/2", children: [_jsxs("div", { className: "flex items-end gap-1", children: [_jsx(SimpleSelect, { label: t('details.options.checker'), value: currentCheckerValue ? currentCheckerValue.code : '', onValueChange: handleCheckerValueChange, options: allCheckersOptions }), currentCheckerValue?.code && (_jsx(Button, { variant: 'secondary', className: "p-2", onClick: clearInput, children: _jsx(X, { size: 20 }) }))] }), _jsx("div", { className: "flex", children: currentCheckerValue?.arguments.map((e, i) => {
55
+ return (_jsx(CustomCard, { title: t('details.options.title'), icon: _jsx(CardIcons.check, {}), color: "teal", upperRight: _jsx(ErrorMessage, { errors: errors }), children: _jsxs("div", { className: "flex basis-full flex-col gap-3 md:basis-1/2", children: [_jsxs("div", { className: "flex items-end gap-1", children: [_jsx(SimpleSelect, { label: t('details.options.checker'), value: currentCheckerValue ? currentCheckerValue.code : '', onValueChange: handleCheckerValueChange, options: allCheckersOptions }), currentCheckerValue?.code && (_jsx(Button, { variant: 'secondary', className: "p-2", onClick: clearInput, children: _jsx(X, { size: 20 }) }))] }), _jsx("div", { className: "flex", children: currentCheckerValue?.arguments.map((e) => {
40
56
  const checker = checkers?.find((ch) => ch.code === currentCheckerValue.code);
41
- const argument = checker?.args.find((a) => a.name === a.name);
57
+ const argument = checker?.args.find((a) => a.name === e.name);
42
58
  if (!argument)
43
59
  return null;
44
60
  return generateInputComponents([
@@ -48,7 +64,7 @@ export const CheckerCard = ({ currentCheckerValue, onCheckerValueChange, errors
48
64
  description: [{ languageCode: 'en', value: argument.description || '' }],
49
65
  },
50
66
  ], getInputComponent).map((field) => {
51
- const value = e.value;
67
+ const value = decodeConfigArgValue(e.value);
52
68
  const setValue = (data) => {
53
69
  try {
54
70
  onCheckerValueChange({
@@ -56,7 +72,7 @@ export const CheckerCard = ({ currentCheckerValue, onCheckerValueChange, errors
56
72
  arguments: currentCheckerValue.arguments.map((a) => {
57
73
  try {
58
74
  if (a.name === field.name) {
59
- return { name: field.name, value: JSON.stringify(data) };
75
+ return { name: field.name, value: encodeConfigArgValue(data) };
60
76
  }
61
77
  }
62
78
  catch {
@@ -70,7 +86,7 @@ export const CheckerCard = ({ currentCheckerValue, onCheckerValueChange, errors
70
86
  console.error('Error setting value');
71
87
  }
72
88
  };
73
- return (_jsx(CustomFieldsProvider, { field: field, value: value, setValue: setValue, additionalData: {}, children: _jsxs("div", { children: [_jsx("div", { children: _jsx(Label, { children: field.name }) }), field.component] }, field.name) }, field.name));
89
+ return (_jsx(InputFieldComponent, { field: field, value: value, setValue: setValue, additionalData: {} }, field.name));
74
90
  });
75
91
  }) })] }) }));
76
92
  };
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const ADMIN_DASHBOARD_VERSION = '1.0.16';
1
+ export const ADMIN_DASHBOARD_VERSION = '1.0.17-dev.4';