@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.
- package/dist/DeenruvAdminPanel.js +4 -4
- package/dist/components/GlobalSearch.js +5 -5
- package/dist/components/Menu/ActiveAdmins.js +1 -1
- package/dist/components/Menu/ChannelSwitcher.js +1 -1
- package/dist/components/Menu/LanguagesDropdown.js +1 -1
- package/dist/components/Menu/Navigation.js +4 -4
- package/dist/components/Menu/NavigationFooter.js +2 -2
- package/dist/components/Menu/Notifications.js +1 -1
- package/dist/components/Menu/index.js +12 -14
- package/dist/index.css +54 -44
- package/dist/locales/en/collections.json +7 -0
- package/dist/locales/en/common.json +1 -0
- package/dist/locales/en/orders.json +8 -0
- package/dist/locales/en/products.json +14 -2
- package/dist/locales/en/promotions.json +4 -0
- package/dist/locales/pl/collections.json +7 -0
- package/dist/locales/pl/common.json +1 -0
- package/dist/locales/pl/orders.json +8 -0
- package/dist/locales/pl/products.json +14 -2
- package/dist/locales/pl/promotions.json +4 -0
- package/dist/pages/Root.js +1 -1
- package/dist/pages/collections/Detail.js +20 -5
- package/dist/pages/collections/_components/CollectionDetailView.js +15 -2
- package/dist/pages/collections/_components/FiltersCard.js +51 -11
- package/dist/pages/customers/_components/PersonalDataCard.js +2 -1
- package/dist/pages/extensions/Extensions.js +3 -7
- package/dist/pages/orders/Detail.js +38 -5
- package/dist/pages/orders/List.js +1 -16
- package/dist/pages/orders/_components/CancelAndRefundDialog.js +1 -2
- package/dist/pages/orders/_components/OrderLineCustomFields.js +1 -1
- package/dist/pages/orders/_components/ProductsTable.js +1 -2
- package/dist/pages/orders/_components/RefundPaymentCard.js +1 -2
- package/dist/pages/products/Detail.js +58 -4
- package/dist/pages/products/_components/AssetsCard.js +15 -2
- package/dist/pages/products/_components/OptionsCard.js +7 -5
- package/dist/pages/products/_components/PriceCard.js +21 -8
- package/dist/pages/products/_components/ProductDetailView.js +7 -3
- package/dist/pages/products/_components/Variant.js +40 -19
- package/dist/pages/products/_components/VariantsTab.js +1 -1
- package/dist/pages/promotions/Detail.js +34 -3
- package/dist/pages/promotions/_components/EnabledCard.js +2 -2
- package/dist/pages/promotions/_components/PromotionDetailSidebar.js +2 -1
- package/dist/pages/roles/_components/PermissionsTable.js +0 -1
- package/dist/pages/shipping-methods/Detail.js +9 -5
- package/dist/pages/shipping-methods/_components/CalculatorCard.js +27 -11
- package/dist/pages/shipping-methods/_components/CheckerCard.js +28 -12
- package/dist/version.js +1 -1
- 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
|
-
|
|
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
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
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 =
|
|
24
|
-
onPriceChange(newPrices
|
|
25
|
-
}, [
|
|
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: [
|
|
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,
|
|
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(
|
|
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,
|
|
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
|
-
|
|
73
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|
|
55
|
-
enabled: data.enabled
|
|
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('
|
|
5
|
-
return (_jsx(CustomCard, { title: t('
|
|
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:
|
|
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
|
|
70
|
+
const hasInvalidArguments = hasMissingConfigArgs(v);
|
|
67
71
|
const errors = [];
|
|
68
72
|
if (!hasCode)
|
|
69
73
|
errors.push(t('validation.checkerCodeRequired'));
|
|
70
|
-
if (
|
|
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
|
|
82
|
+
const hasInvalidArguments = hasMissingConfigArgs(v);
|
|
79
83
|
const errors = [];
|
|
80
84
|
if (!hasCode)
|
|
81
|
-
errors.push(t('validation.
|
|
85
|
+
errors.push(t('validation.calculatorCodeRequired'));
|
|
82
86
|
if (hasInvalidArguments)
|
|
83
|
-
errors.push(t('validation.
|
|
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,
|
|
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
|
|
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:
|
|
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(
|
|
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,
|
|
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
|
|
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 ===
|
|
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:
|
|
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(
|
|
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.
|
|
1
|
+
export const ADMIN_DASHBOARD_VERSION = '1.0.17-dev.4';
|