@empty-complete-org/medusa-product-attributes 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/index.js +192 -230
- package/.medusa/server/src/admin/index.mjs +192 -230
- package/package.json +1 -1
|
@@ -180,15 +180,17 @@ const en = {
|
|
|
180
180
|
};
|
|
181
181
|
const locales = { ru, en };
|
|
182
182
|
function detectLang() {
|
|
183
|
-
var _a;
|
|
184
|
-
if (typeof window === "undefined") return "
|
|
183
|
+
var _a, _b, _c;
|
|
184
|
+
if (typeof window === "undefined") return "ru";
|
|
185
185
|
const stored = window.localStorage.getItem("i18nextLng");
|
|
186
186
|
if (stored) {
|
|
187
187
|
const short = stored.slice(0, 2).toLowerCase();
|
|
188
188
|
if (locales[short]) return short;
|
|
189
189
|
}
|
|
190
|
-
const
|
|
191
|
-
|
|
190
|
+
const htmlLang = (_b = (_a = document.documentElement) == null ? void 0 : _a.lang) == null ? void 0 : _b.slice(0, 2).toLowerCase();
|
|
191
|
+
if (htmlLang && locales[htmlLang]) return htmlLang;
|
|
192
|
+
const nav = (((_c = window.navigator) == null ? void 0 : _c.language) || "ru").slice(0, 2).toLowerCase();
|
|
193
|
+
return locales[nav] ? nav : "ru";
|
|
192
194
|
}
|
|
193
195
|
function useT() {
|
|
194
196
|
const dict = React.useMemo(() => {
|
|
@@ -197,7 +199,7 @@ function useT() {
|
|
|
197
199
|
}, []);
|
|
198
200
|
return (key, fallback) => dict[key] ?? fallback ?? key;
|
|
199
201
|
}
|
|
200
|
-
const emptyForm$
|
|
202
|
+
const emptyForm$1 = () => ({ label: "", type: "text", unit: "" });
|
|
201
203
|
const CategoryAttributeTemplatesWidget = ({
|
|
202
204
|
data
|
|
203
205
|
}) => {
|
|
@@ -208,7 +210,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
208
210
|
const queryKey = ["category-custom-attributes", categoryId];
|
|
209
211
|
const [showAddForm, setShowAddForm] = React.useState(false);
|
|
210
212
|
const [showTemplateList, setShowTemplateList] = React.useState(false);
|
|
211
|
-
const [addForm, setAddForm] = React.useState(emptyForm$
|
|
213
|
+
const [addForm, setAddForm] = React.useState(emptyForm$1());
|
|
212
214
|
const [confirmDeleteId, setConfirmDeleteId] = React.useState(null);
|
|
213
215
|
const [mutationError, setMutationError] = React.useState(null);
|
|
214
216
|
const templatesQuery = reactQuery.useQuery({
|
|
@@ -248,7 +250,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
248
250
|
onSuccess: () => {
|
|
249
251
|
qc.invalidateQueries({ queryKey });
|
|
250
252
|
setShowAddForm(false);
|
|
251
|
-
setAddForm(emptyForm$
|
|
253
|
+
setAddForm(emptyForm$1());
|
|
252
254
|
setMutationError(null);
|
|
253
255
|
},
|
|
254
256
|
onError: (err) => {
|
|
@@ -273,7 +275,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
273
275
|
unit: addForm.type === "number" && addForm.unit.trim() ? addForm.unit.trim() : null
|
|
274
276
|
});
|
|
275
277
|
};
|
|
276
|
-
const
|
|
278
|
+
const typeLabel = (v) => t(`type.${v}`, v);
|
|
277
279
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
|
|
278
280
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
|
|
279
281
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("attributes") }),
|
|
@@ -287,16 +289,13 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
287
289
|
children: t("fromTemplate")
|
|
288
290
|
}
|
|
289
291
|
),
|
|
290
|
-
/* @__PURE__ */ jsxRuntime.
|
|
292
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
291
293
|
ui.Button,
|
|
292
294
|
{
|
|
293
295
|
variant: "secondary",
|
|
294
296
|
size: "small",
|
|
295
297
|
onClick: () => setShowAddForm(true),
|
|
296
|
-
children:
|
|
297
|
-
"+ ",
|
|
298
|
-
t("add")
|
|
299
|
-
]
|
|
298
|
+
children: t("add")
|
|
300
299
|
}
|
|
301
300
|
)
|
|
302
301
|
] })
|
|
@@ -325,7 +324,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
325
324
|
children: [
|
|
326
325
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: p.label }),
|
|
327
326
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "grey", children: [
|
|
328
|
-
|
|
327
|
+
typeLabel(p.type),
|
|
329
328
|
p.unit ? `, ${p.unit}` : ""
|
|
330
329
|
] })
|
|
331
330
|
]
|
|
@@ -344,10 +343,9 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
344
343
|
children: [
|
|
345
344
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-sm text-ui-fg-subtle", children: attr.label }),
|
|
346
345
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "grey", children: [
|
|
347
|
-
|
|
346
|
+
typeLabel(attr.type),
|
|
348
347
|
attr.unit ? `, ${attr.unit}` : ""
|
|
349
|
-
] })
|
|
350
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "blue", children: "из родителя" })
|
|
348
|
+
] })
|
|
351
349
|
]
|
|
352
350
|
},
|
|
353
351
|
attr.id
|
|
@@ -395,7 +393,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
395
393
|
children: [
|
|
396
394
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-sm text-ui-fg-base", children: attr.label }),
|
|
397
395
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "grey", children: [
|
|
398
|
-
|
|
396
|
+
typeLabel(attr.type),
|
|
399
397
|
attr.unit ? `, ${attr.unit}` : ""
|
|
400
398
|
] }),
|
|
401
399
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -467,7 +465,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
467
465
|
size: "small",
|
|
468
466
|
onClick: () => {
|
|
469
467
|
setShowAddForm(false);
|
|
470
|
-
setAddForm(emptyForm$
|
|
468
|
+
setAddForm(emptyForm$1());
|
|
471
469
|
setMutationError(null);
|
|
472
470
|
},
|
|
473
471
|
children: "Отмена"
|
|
@@ -685,71 +683,6 @@ const ProductAttributeValuesWidget = ({
|
|
|
685
683
|
adminSdk.defineWidgetConfig({
|
|
686
684
|
zone: "product.details.after"
|
|
687
685
|
});
|
|
688
|
-
var __defProp$1 = Object.defineProperty;
|
|
689
|
-
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
|
|
690
|
-
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
691
|
-
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
|
|
692
|
-
var __defNormalProp$1 = (obj, key, value2) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
|
|
693
|
-
var __spreadValues$1 = (a, b) => {
|
|
694
|
-
for (var prop in b || (b = {}))
|
|
695
|
-
if (__hasOwnProp$1.call(b, prop))
|
|
696
|
-
__defNormalProp$1(a, prop, b[prop]);
|
|
697
|
-
if (__getOwnPropSymbols$1)
|
|
698
|
-
for (var prop of __getOwnPropSymbols$1(b)) {
|
|
699
|
-
if (__propIsEnum$1.call(b, prop))
|
|
700
|
-
__defNormalProp$1(a, prop, b[prop]);
|
|
701
|
-
}
|
|
702
|
-
return a;
|
|
703
|
-
};
|
|
704
|
-
var __objRest$1 = (source, exclude) => {
|
|
705
|
-
var target = {};
|
|
706
|
-
for (var prop in source)
|
|
707
|
-
if (__hasOwnProp$1.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
708
|
-
target[prop] = source[prop];
|
|
709
|
-
if (source != null && __getOwnPropSymbols$1)
|
|
710
|
-
for (var prop of __getOwnPropSymbols$1(source)) {
|
|
711
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum$1.call(source, prop))
|
|
712
|
-
target[prop] = source[prop];
|
|
713
|
-
}
|
|
714
|
-
return target;
|
|
715
|
-
};
|
|
716
|
-
const Globe = React__namespace.forwardRef(
|
|
717
|
-
(_a, ref) => {
|
|
718
|
-
var _b = _a, { color = "currentColor" } = _b, props = __objRest$1(_b, ["color"]);
|
|
719
|
-
return /* @__PURE__ */ React__namespace.createElement(
|
|
720
|
-
"svg",
|
|
721
|
-
__spreadValues$1({
|
|
722
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
723
|
-
width: 15,
|
|
724
|
-
height: 15,
|
|
725
|
-
viewBox: "0 0 15 15",
|
|
726
|
-
fill: "none",
|
|
727
|
-
ref
|
|
728
|
-
}, props),
|
|
729
|
-
/* @__PURE__ */ React__namespace.createElement(
|
|
730
|
-
"path",
|
|
731
|
-
{
|
|
732
|
-
stroke: color,
|
|
733
|
-
strokeLinecap: "round",
|
|
734
|
-
strokeLinejoin: "round",
|
|
735
|
-
strokeWidth: 1.5,
|
|
736
|
-
d: "M7.5 13.945c1.473 0 2.667-2.886 2.667-6.445S8.973 1.056 7.5 1.056 4.833 3.94 4.833 7.5s1.194 6.445 2.667 6.445M1.056 7.5h12.888"
|
|
737
|
-
}
|
|
738
|
-
),
|
|
739
|
-
/* @__PURE__ */ React__namespace.createElement(
|
|
740
|
-
"path",
|
|
741
|
-
{
|
|
742
|
-
stroke: color,
|
|
743
|
-
strokeLinecap: "round",
|
|
744
|
-
strokeLinejoin: "round",
|
|
745
|
-
strokeWidth: 1.5,
|
|
746
|
-
d: "M7.5 13.945a6.444 6.444 0 1 0 0-12.89 6.444 6.444 0 0 0 0 12.89"
|
|
747
|
-
}
|
|
748
|
-
)
|
|
749
|
-
);
|
|
750
|
-
}
|
|
751
|
-
);
|
|
752
|
-
Globe.displayName = "Globe";
|
|
753
686
|
var __defProp = Object.defineProperty;
|
|
754
687
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
755
688
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
@@ -778,7 +711,7 @@ var __objRest = (source, exclude) => {
|
|
|
778
711
|
}
|
|
779
712
|
return target;
|
|
780
713
|
};
|
|
781
|
-
const
|
|
714
|
+
const Tag = React__namespace.forwardRef(
|
|
782
715
|
(_a, ref) => {
|
|
783
716
|
var _b = _a, { color = "currentColor" } = _b, props = __objRest(_b, ["color"]);
|
|
784
717
|
return /* @__PURE__ */ React__namespace.createElement(
|
|
@@ -791,56 +724,73 @@ const SquaresPlus = React__namespace.forwardRef(
|
|
|
791
724
|
fill: "none",
|
|
792
725
|
ref
|
|
793
726
|
}, props),
|
|
794
|
-
/* @__PURE__ */ React__namespace.createElement(
|
|
727
|
+
/* @__PURE__ */ React__namespace.createElement("g", { clipPath: "url(#a)" }, /* @__PURE__ */ React__namespace.createElement(
|
|
795
728
|
"path",
|
|
796
729
|
{
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
d: "M5.056 1.944H2.833a.89.89 0 0 0-.889.89v2.221c0 .491.398.89.89.89h2.222c.49 0 .888-.399.888-.89V2.833a.89.89 0 0 0-.888-.889M12.167 1.944H9.944a.89.89 0 0 0-.888.89v2.221c0 .491.398.89.888.89h2.223c.49 0 .889-.399.889-.89V2.833a.89.89 0 0 0-.89-.889M5.056 9.056H2.833a.89.89 0 0 0-.889.889v2.222c0 .49.398.889.89.889h2.222c.49 0 .888-.398.888-.89V9.946a.89.89 0 0 0-.888-.89M11.056 8.611v4.445M13.278 10.833H8.833"
|
|
730
|
+
fill: color,
|
|
731
|
+
fillRule: "evenodd",
|
|
732
|
+
d: "M2.25 2.389a.14.14 0 0 1 .139-.139h4.375c.272 0 .534.108.727.301l5.11 5.111a1.027 1.027 0 0 1 0 1.453l-3.486 3.487a1.027 1.027 0 0 1-1.453 0L2.552 7.49a1.03 1.03 0 0 1-.302-.727zM2.389.75A1.64 1.64 0 0 0 .75 2.389v4.375c0 .67.267 1.313.74 1.787l5.112 5.111a2.527 2.527 0 0 0 3.574 0l3.486-3.486a2.527 2.527 0 0 0 0-3.574L8.552 1.49A2.53 2.53 0 0 0 6.763.75zm3.778 4.305a1.111 1.111 0 1 1-2.223 0 1.111 1.111 0 0 1 2.223 0",
|
|
733
|
+
clipRule: "evenodd"
|
|
802
734
|
}
|
|
803
|
-
)
|
|
735
|
+
)),
|
|
736
|
+
/* @__PURE__ */ React__namespace.createElement("defs", null, /* @__PURE__ */ React__namespace.createElement("clipPath", { id: "a" }, /* @__PURE__ */ React__namespace.createElement("path", { fill: "#fff", d: "M0 0h15v15H0z" })))
|
|
804
737
|
);
|
|
805
738
|
}
|
|
806
739
|
);
|
|
807
|
-
|
|
808
|
-
const emptyForm
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
740
|
+
Tag.displayName = "Tag";
|
|
741
|
+
const emptyForm = () => ({ label: "", type: "text", unit: "", description: "" });
|
|
742
|
+
const ProductAttributesSettingsPage = () => {
|
|
743
|
+
const t = useT();
|
|
744
|
+
const [tab, setTab] = React.useState("globals");
|
|
745
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "p-0", children: [
|
|
746
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-6 border-b border-ui-border-base px-6 pt-4", children: [
|
|
747
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabButton, { active: tab === "globals", onClick: () => setTab("globals"), children: t("globals") }),
|
|
748
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabButton, { active: tab === "templates", onClick: () => setTab("templates"), children: t("templates") })
|
|
749
|
+
] }),
|
|
750
|
+
tab === "globals" ? /* @__PURE__ */ jsxRuntime.jsx(GlobalsTab, {}) : /* @__PURE__ */ jsxRuntime.jsx(TemplatesTab, {})
|
|
751
|
+
] });
|
|
752
|
+
};
|
|
753
|
+
const TabButton = ({
|
|
754
|
+
active,
|
|
755
|
+
onClick,
|
|
756
|
+
children
|
|
757
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
758
|
+
"button",
|
|
759
|
+
{
|
|
760
|
+
onClick,
|
|
761
|
+
className: `-mb-px border-b-2 px-1 pb-3 text-sm font-medium transition-colors ${active ? "border-ui-border-interactive text-ui-fg-base" : "border-transparent text-ui-fg-subtle hover:text-ui-fg-base"}`,
|
|
762
|
+
children
|
|
763
|
+
}
|
|
764
|
+
);
|
|
765
|
+
const GlobalsTab = () => {
|
|
766
|
+
const t = useT();
|
|
816
767
|
const qc = reactQuery.useQueryClient();
|
|
817
|
-
const queryKey = ["
|
|
768
|
+
const queryKey = ["global-attributes"];
|
|
818
769
|
const [showAddForm, setShowAddForm] = React.useState(false);
|
|
819
|
-
const [addForm, setAddForm] = React.useState(emptyForm
|
|
770
|
+
const [addForm, setAddForm] = React.useState(emptyForm());
|
|
820
771
|
const [confirmDeleteId, setConfirmDeleteId] = React.useState(null);
|
|
821
772
|
const { data, isLoading, isError } = reactQuery.useQuery({
|
|
822
773
|
queryKey,
|
|
823
|
-
queryFn: () => sdk.client.fetch(`/admin/
|
|
774
|
+
queryFn: () => sdk.client.fetch(`/admin/global-attributes`)
|
|
824
775
|
});
|
|
825
|
-
const
|
|
776
|
+
const attrs = (data == null ? void 0 : data.global_attributes) ?? [];
|
|
826
777
|
const createMutation = reactQuery.useMutation({
|
|
827
|
-
mutationFn: (body) => sdk.client.fetch(`/admin/
|
|
778
|
+
mutationFn: (body) => sdk.client.fetch(`/admin/global-attributes`, {
|
|
828
779
|
method: "POST",
|
|
829
780
|
body: {
|
|
830
781
|
label: body.label,
|
|
831
782
|
type: body.type,
|
|
832
|
-
unit: body.type === "number" && body.unit ? body.unit : null
|
|
833
|
-
description: body.description || null
|
|
783
|
+
unit: body.type === "number" && body.unit ? body.unit : null
|
|
834
784
|
}
|
|
835
785
|
}),
|
|
836
786
|
onSuccess: () => {
|
|
837
787
|
qc.invalidateQueries({ queryKey });
|
|
838
788
|
setShowAddForm(false);
|
|
839
|
-
setAddForm(emptyForm
|
|
789
|
+
setAddForm(emptyForm());
|
|
840
790
|
}
|
|
841
791
|
});
|
|
842
792
|
const deleteMutation = reactQuery.useMutation({
|
|
843
|
-
mutationFn: (id) => sdk.client.fetch(`/admin/
|
|
793
|
+
mutationFn: (id) => sdk.client.fetch(`/admin/global-attributes`, {
|
|
844
794
|
method: "PATCH",
|
|
845
795
|
body: { id, deleted_at: (/* @__PURE__ */ new Date()).toISOString() }
|
|
846
796
|
}),
|
|
@@ -858,86 +808,57 @@ const AttributeTemplatesSettingsPage = () => {
|
|
|
858
808
|
description: addForm.description.trim()
|
|
859
809
|
});
|
|
860
810
|
};
|
|
861
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
862
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-
|
|
811
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y", children: [
|
|
812
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between px-6 py-4", children: [
|
|
863
813
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
864
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "
|
|
865
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
814
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("globals") }),
|
|
815
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("globalsDesc") })
|
|
866
816
|
] }),
|
|
867
|
-
!showAddForm && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => setShowAddForm(true), children: "
|
|
817
|
+
!showAddForm && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => setShowAddForm(true), children: t("add") })
|
|
868
818
|
] }),
|
|
869
|
-
isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: "
|
|
870
|
-
isError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error text-sm", children: "
|
|
871
|
-
!isLoading && !isError &&
|
|
872
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children:
|
|
873
|
-
(
|
|
874
|
-
/* @__PURE__ */ jsxRuntime.
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
/* @__PURE__ */ jsxRuntime.
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
883
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
884
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: p.label }),
|
|
885
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "grey", children: [
|
|
886
|
-
typeLabel$1(p.type),
|
|
887
|
-
p.unit ? `, ${p.unit}` : ""
|
|
888
|
-
] })
|
|
889
|
-
] }),
|
|
890
|
-
p.description && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: p.description })
|
|
819
|
+
isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }) }),
|
|
820
|
+
isError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error text-sm", children: t("loadFailed") }) }),
|
|
821
|
+
!isLoading && !isError && attrs.length === 0 && !showAddForm && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("noGlobals") }) }),
|
|
822
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children: attrs.map(
|
|
823
|
+
(a) => confirmDeleteId === a.id ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-6 py-3 text-sm", children: [
|
|
824
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: t("confirmDelete").replace("{name}", a.label) }),
|
|
825
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "danger", onClick: () => deleteMutation.mutate(a.id), isLoading: deleteMutation.isPending, children: t("delete") }),
|
|
826
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", onClick: () => setConfirmDeleteId(null), children: t("cancel") })
|
|
827
|
+
] }, a.id) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-6 py-3", children: [
|
|
828
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-sm", children: a.label }),
|
|
829
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "grey", children: [
|
|
830
|
+
t(`type.${a.type}`, a.type),
|
|
831
|
+
a.unit ? `, ${a.unit}` : ""
|
|
891
832
|
] }),
|
|
892
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setConfirmDeleteId(
|
|
893
|
-
] },
|
|
833
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setConfirmDeleteId(a.id), className: "text-xs text-ui-fg-error hover:underline", children: t("delete") })
|
|
834
|
+
] }, a.id)
|
|
894
835
|
) }),
|
|
895
|
-
showAddForm && /* @__PURE__ */ jsxRuntime.
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "text", children: "Текст" }),
|
|
900
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "number", children: "Число" }),
|
|
901
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "file", children: "Файл" }),
|
|
902
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "boolean", children: "Да/Нет" })
|
|
903
|
-
] }),
|
|
904
|
-
addForm.type === "number" && /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { value: addForm.unit, onChange: (e) => setAddForm((f) => ({ ...f, unit: e.target.value })), placeholder: "ед.", className: "w-28 h-8 text-sm" })
|
|
905
|
-
] }),
|
|
906
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Input, { value: addForm.description, onChange: (e) => setAddForm((f) => ({ ...f, description: e.target.value })), placeholder: "Описание (необязательно)", className: "h-8 text-sm" }),
|
|
907
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
908
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => {
|
|
909
|
-
setShowAddForm(false);
|
|
910
|
-
setAddForm(emptyForm$1());
|
|
911
|
-
}, children: "Отмена" }),
|
|
912
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", onClick: handleAdd, isLoading: createMutation.isPending, children: "Создать" })
|
|
913
|
-
] })
|
|
914
|
-
] })
|
|
836
|
+
showAddForm && /* @__PURE__ */ jsxRuntime.jsx(AddForm, { t, form: addForm, setForm: setAddForm, onCancel: () => {
|
|
837
|
+
setShowAddForm(false);
|
|
838
|
+
setAddForm(emptyForm());
|
|
839
|
+
}, onSubmit: handleAdd, isLoading: createMutation.isPending, withDescription: false })
|
|
915
840
|
] });
|
|
916
841
|
};
|
|
917
|
-
const
|
|
918
|
-
|
|
919
|
-
icon: SquaresPlus
|
|
920
|
-
});
|
|
921
|
-
const emptyForm = () => ({ label: "", type: "text", unit: "" });
|
|
922
|
-
const typeLabel = (t) => t === "text" ? "Текст" : t === "number" ? "Число" : t === "file" ? "Файл" : t === "boolean" ? "Да/Нет" : t;
|
|
923
|
-
const GlobalAttributesSettingsPage = () => {
|
|
842
|
+
const TemplatesTab = () => {
|
|
843
|
+
const t = useT();
|
|
924
844
|
const qc = reactQuery.useQueryClient();
|
|
925
|
-
const queryKey = ["
|
|
845
|
+
const queryKey = ["attribute-templates"];
|
|
926
846
|
const [showAddForm, setShowAddForm] = React.useState(false);
|
|
927
847
|
const [addForm, setAddForm] = React.useState(emptyForm());
|
|
928
848
|
const [confirmDeleteId, setConfirmDeleteId] = React.useState(null);
|
|
929
849
|
const { data, isLoading, isError } = reactQuery.useQuery({
|
|
930
850
|
queryKey,
|
|
931
|
-
queryFn: () => sdk.client.fetch(`/admin/
|
|
851
|
+
queryFn: () => sdk.client.fetch(`/admin/attribute-templates`)
|
|
932
852
|
});
|
|
933
|
-
const
|
|
853
|
+
const templates2 = (data == null ? void 0 : data.attribute_templates) ?? [];
|
|
934
854
|
const createMutation = reactQuery.useMutation({
|
|
935
|
-
mutationFn: (body) => sdk.client.fetch(`/admin/
|
|
855
|
+
mutationFn: (body) => sdk.client.fetch(`/admin/attribute-templates`, {
|
|
936
856
|
method: "POST",
|
|
937
857
|
body: {
|
|
938
858
|
label: body.label,
|
|
939
859
|
type: body.type,
|
|
940
|
-
unit: body.type === "number" && body.unit ? body.unit : null
|
|
860
|
+
unit: body.type === "number" && body.unit ? body.unit : null,
|
|
861
|
+
description: body.description || null
|
|
941
862
|
}
|
|
942
863
|
}),
|
|
943
864
|
onSuccess: () => {
|
|
@@ -947,7 +868,7 @@ const GlobalAttributesSettingsPage = () => {
|
|
|
947
868
|
}
|
|
948
869
|
});
|
|
949
870
|
const deleteMutation = reactQuery.useMutation({
|
|
950
|
-
mutationFn: (id) => sdk.client.fetch(`/admin/
|
|
871
|
+
mutationFn: (id) => sdk.client.fetch(`/admin/attribute-templates`, {
|
|
951
872
|
method: "PATCH",
|
|
952
873
|
body: { id, deleted_at: (/* @__PURE__ */ new Date()).toISOString() }
|
|
953
874
|
}),
|
|
@@ -959,60 +880,113 @@ const GlobalAttributesSettingsPage = () => {
|
|
|
959
880
|
const handleAdd = () => {
|
|
960
881
|
if (!addForm.label.trim()) return;
|
|
961
882
|
createMutation.mutate({
|
|
883
|
+
...addForm,
|
|
962
884
|
label: addForm.label.trim(),
|
|
963
|
-
|
|
964
|
-
|
|
885
|
+
unit: addForm.unit.trim(),
|
|
886
|
+
description: addForm.description.trim()
|
|
965
887
|
});
|
|
966
888
|
};
|
|
967
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
968
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-
|
|
889
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y", children: [
|
|
890
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between px-6 py-4", children: [
|
|
969
891
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
970
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "
|
|
971
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
892
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("templates") }),
|
|
893
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("templatesDesc") })
|
|
972
894
|
] }),
|
|
973
|
-
!showAddForm && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => setShowAddForm(true), children: "
|
|
895
|
+
!showAddForm && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => setShowAddForm(true), children: t("add") })
|
|
974
896
|
] }),
|
|
975
|
-
isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: "
|
|
976
|
-
isError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error text-sm", children: "
|
|
977
|
-
!isLoading && !isError &&
|
|
978
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children:
|
|
979
|
-
(
|
|
980
|
-
/* @__PURE__ */ jsxRuntime.
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
897
|
+
isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }) }),
|
|
898
|
+
isError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error text-sm", children: t("loadFailed") }) }),
|
|
899
|
+
!isLoading && !isError && templates2.length === 0 && !showAddForm && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("noTemplates") }) }),
|
|
900
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children: templates2.map(
|
|
901
|
+
(p) => confirmDeleteId === p.id ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-6 py-3 text-sm", children: [
|
|
902
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: t("confirmDelete").replace("{name}", p.label) }),
|
|
903
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "danger", onClick: () => deleteMutation.mutate(p.id), isLoading: deleteMutation.isPending, children: t("delete") }),
|
|
904
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", onClick: () => setConfirmDeleteId(null), children: t("cancel") })
|
|
905
|
+
] }, p.id) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-6 py-3", children: [
|
|
906
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
907
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
908
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: p.label }),
|
|
909
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "grey", children: [
|
|
910
|
+
t(`type.${p.type}`, p.type),
|
|
911
|
+
p.unit ? `, ${p.unit}` : ""
|
|
912
|
+
] })
|
|
913
|
+
] }),
|
|
914
|
+
p.description && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: p.description })
|
|
992
915
|
] }),
|
|
993
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setConfirmDeleteId(
|
|
994
|
-
] },
|
|
916
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setConfirmDeleteId(p.id), className: "text-xs text-ui-fg-error hover:underline", children: t("delete") })
|
|
917
|
+
] }, p.id)
|
|
995
918
|
) }),
|
|
996
|
-
showAddForm && /* @__PURE__ */ jsxRuntime.
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "number", children: "Число" }),
|
|
1001
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "file", children: "Файл" }),
|
|
1002
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "boolean", children: "Да/Нет" })
|
|
1003
|
-
] }),
|
|
1004
|
-
addForm.type === "number" && /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { value: addForm.unit, onChange: (e) => setAddForm((f) => ({ ...f, unit: e.target.value })), placeholder: "ед.", className: "w-28 h-8 text-sm" }),
|
|
1005
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", onClick: handleAdd, isLoading: createMutation.isPending, children: "Создать" }),
|
|
1006
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => {
|
|
1007
|
-
setShowAddForm(false);
|
|
1008
|
-
setAddForm(emptyForm());
|
|
1009
|
-
}, children: "Отмена" })
|
|
1010
|
-
] })
|
|
919
|
+
showAddForm && /* @__PURE__ */ jsxRuntime.jsx(AddForm, { t, form: addForm, setForm: setAddForm, onCancel: () => {
|
|
920
|
+
setShowAddForm(false);
|
|
921
|
+
setAddForm(emptyForm());
|
|
922
|
+
}, onSubmit: handleAdd, isLoading: createMutation.isPending, withDescription: true })
|
|
1011
923
|
] });
|
|
1012
924
|
};
|
|
925
|
+
const AddForm = ({
|
|
926
|
+
t,
|
|
927
|
+
form,
|
|
928
|
+
setForm,
|
|
929
|
+
onCancel,
|
|
930
|
+
onSubmit,
|
|
931
|
+
isLoading,
|
|
932
|
+
withDescription
|
|
933
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 px-6 py-4", children: [
|
|
934
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
935
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
936
|
+
ui.Input,
|
|
937
|
+
{
|
|
938
|
+
value: form.label,
|
|
939
|
+
onChange: (e) => setForm((f) => ({ ...f, label: e.target.value })),
|
|
940
|
+
placeholder: t("name"),
|
|
941
|
+
className: "flex-1 h-8 text-sm",
|
|
942
|
+
autoFocus: true
|
|
943
|
+
}
|
|
944
|
+
),
|
|
945
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
946
|
+
"select",
|
|
947
|
+
{
|
|
948
|
+
value: form.type,
|
|
949
|
+
onChange: (e) => setForm((f) => ({
|
|
950
|
+
...f,
|
|
951
|
+
type: e.target.value,
|
|
952
|
+
unit: e.target.value === "number" ? f.unit : ""
|
|
953
|
+
})),
|
|
954
|
+
className: "h-8 rounded border border-ui-border-base bg-ui-bg-base px-2 text-sm",
|
|
955
|
+
children: [
|
|
956
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "text", children: t("type.text") }),
|
|
957
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "number", children: t("type.number") }),
|
|
958
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "file", children: t("type.file") }),
|
|
959
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "boolean", children: t("type.boolean") })
|
|
960
|
+
]
|
|
961
|
+
}
|
|
962
|
+
),
|
|
963
|
+
form.type === "number" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
964
|
+
ui.Input,
|
|
965
|
+
{
|
|
966
|
+
value: form.unit,
|
|
967
|
+
onChange: (e) => setForm((f) => ({ ...f, unit: e.target.value })),
|
|
968
|
+
placeholder: t("unit"),
|
|
969
|
+
className: "w-28 h-8 text-sm"
|
|
970
|
+
}
|
|
971
|
+
)
|
|
972
|
+
] }),
|
|
973
|
+
withDescription && /* @__PURE__ */ jsxRuntime.jsx(
|
|
974
|
+
ui.Input,
|
|
975
|
+
{
|
|
976
|
+
value: form.description,
|
|
977
|
+
onChange: (e) => setForm((f) => ({ ...f, description: e.target.value })),
|
|
978
|
+
placeholder: t("description"),
|
|
979
|
+
className: "h-8 text-sm"
|
|
980
|
+
}
|
|
981
|
+
),
|
|
982
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
983
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: onCancel, children: t("cancel") }),
|
|
984
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", onClick: onSubmit, isLoading, children: t("create") })
|
|
985
|
+
] })
|
|
986
|
+
] });
|
|
1013
987
|
const config = adminSdk.defineRouteConfig({
|
|
1014
|
-
label: "
|
|
1015
|
-
icon:
|
|
988
|
+
label: "Product Attributes",
|
|
989
|
+
icon: Tag
|
|
1016
990
|
});
|
|
1017
991
|
const widgetModule = { widgets: [
|
|
1018
992
|
{
|
|
@@ -1027,29 +1001,17 @@ const widgetModule = { widgets: [
|
|
|
1027
1001
|
const routeModule = {
|
|
1028
1002
|
routes: [
|
|
1029
1003
|
{
|
|
1030
|
-
Component:
|
|
1031
|
-
path: "/settings/
|
|
1032
|
-
},
|
|
1033
|
-
{
|
|
1034
|
-
Component: GlobalAttributesSettingsPage,
|
|
1035
|
-
path: "/settings/global-attributes"
|
|
1004
|
+
Component: ProductAttributesSettingsPage,
|
|
1005
|
+
path: "/settings/product-attributes"
|
|
1036
1006
|
}
|
|
1037
1007
|
]
|
|
1038
1008
|
};
|
|
1039
1009
|
const menuItemModule = {
|
|
1040
1010
|
menuItems: [
|
|
1041
|
-
{
|
|
1042
|
-
label: config$1.label,
|
|
1043
|
-
icon: config$1.icon,
|
|
1044
|
-
path: "/settings/attribute-templates",
|
|
1045
|
-
nested: void 0,
|
|
1046
|
-
rank: void 0,
|
|
1047
|
-
translationNs: void 0
|
|
1048
|
-
},
|
|
1049
1011
|
{
|
|
1050
1012
|
label: config.label,
|
|
1051
1013
|
icon: config.icon,
|
|
1052
|
-
path: "/settings/
|
|
1014
|
+
path: "/settings/product-attributes",
|
|
1053
1015
|
nested: void 0,
|
|
1054
1016
|
rank: void 0,
|
|
1055
1017
|
translationNs: void 0
|
|
@@ -160,15 +160,17 @@ const en = {
|
|
|
160
160
|
};
|
|
161
161
|
const locales = { ru, en };
|
|
162
162
|
function detectLang() {
|
|
163
|
-
var _a;
|
|
164
|
-
if (typeof window === "undefined") return "
|
|
163
|
+
var _a, _b, _c;
|
|
164
|
+
if (typeof window === "undefined") return "ru";
|
|
165
165
|
const stored = window.localStorage.getItem("i18nextLng");
|
|
166
166
|
if (stored) {
|
|
167
167
|
const short = stored.slice(0, 2).toLowerCase();
|
|
168
168
|
if (locales[short]) return short;
|
|
169
169
|
}
|
|
170
|
-
const
|
|
171
|
-
|
|
170
|
+
const htmlLang = (_b = (_a = document.documentElement) == null ? void 0 : _a.lang) == null ? void 0 : _b.slice(0, 2).toLowerCase();
|
|
171
|
+
if (htmlLang && locales[htmlLang]) return htmlLang;
|
|
172
|
+
const nav = (((_c = window.navigator) == null ? void 0 : _c.language) || "ru").slice(0, 2).toLowerCase();
|
|
173
|
+
return locales[nav] ? nav : "ru";
|
|
172
174
|
}
|
|
173
175
|
function useT() {
|
|
174
176
|
const dict = useMemo(() => {
|
|
@@ -177,7 +179,7 @@ function useT() {
|
|
|
177
179
|
}, []);
|
|
178
180
|
return (key, fallback) => dict[key] ?? fallback ?? key;
|
|
179
181
|
}
|
|
180
|
-
const emptyForm$
|
|
182
|
+
const emptyForm$1 = () => ({ label: "", type: "text", unit: "" });
|
|
181
183
|
const CategoryAttributeTemplatesWidget = ({
|
|
182
184
|
data
|
|
183
185
|
}) => {
|
|
@@ -188,7 +190,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
188
190
|
const queryKey = ["category-custom-attributes", categoryId];
|
|
189
191
|
const [showAddForm, setShowAddForm] = useState(false);
|
|
190
192
|
const [showTemplateList, setShowTemplateList] = useState(false);
|
|
191
|
-
const [addForm, setAddForm] = useState(emptyForm$
|
|
193
|
+
const [addForm, setAddForm] = useState(emptyForm$1());
|
|
192
194
|
const [confirmDeleteId, setConfirmDeleteId] = useState(null);
|
|
193
195
|
const [mutationError, setMutationError] = useState(null);
|
|
194
196
|
const templatesQuery = useQuery({
|
|
@@ -228,7 +230,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
228
230
|
onSuccess: () => {
|
|
229
231
|
qc.invalidateQueries({ queryKey });
|
|
230
232
|
setShowAddForm(false);
|
|
231
|
-
setAddForm(emptyForm$
|
|
233
|
+
setAddForm(emptyForm$1());
|
|
232
234
|
setMutationError(null);
|
|
233
235
|
},
|
|
234
236
|
onError: (err) => {
|
|
@@ -253,7 +255,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
253
255
|
unit: addForm.type === "number" && addForm.unit.trim() ? addForm.unit.trim() : null
|
|
254
256
|
});
|
|
255
257
|
};
|
|
256
|
-
const
|
|
258
|
+
const typeLabel = (v) => t(`type.${v}`, v);
|
|
257
259
|
return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
|
|
258
260
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
|
|
259
261
|
/* @__PURE__ */ jsx(Heading, { level: "h2", children: t("attributes") }),
|
|
@@ -267,16 +269,13 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
267
269
|
children: t("fromTemplate")
|
|
268
270
|
}
|
|
269
271
|
),
|
|
270
|
-
/* @__PURE__ */
|
|
272
|
+
/* @__PURE__ */ jsx(
|
|
271
273
|
Button,
|
|
272
274
|
{
|
|
273
275
|
variant: "secondary",
|
|
274
276
|
size: "small",
|
|
275
277
|
onClick: () => setShowAddForm(true),
|
|
276
|
-
children:
|
|
277
|
-
"+ ",
|
|
278
|
-
t("add")
|
|
279
|
-
]
|
|
278
|
+
children: t("add")
|
|
280
279
|
}
|
|
281
280
|
)
|
|
282
281
|
] })
|
|
@@ -305,7 +304,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
305
304
|
children: [
|
|
306
305
|
/* @__PURE__ */ jsx("span", { children: p.label }),
|
|
307
306
|
/* @__PURE__ */ jsxs(Badge, { size: "2xsmall", color: "grey", children: [
|
|
308
|
-
|
|
307
|
+
typeLabel(p.type),
|
|
309
308
|
p.unit ? `, ${p.unit}` : ""
|
|
310
309
|
] })
|
|
311
310
|
]
|
|
@@ -324,10 +323,9 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
324
323
|
children: [
|
|
325
324
|
/* @__PURE__ */ jsx("span", { className: "flex-1 text-sm text-ui-fg-subtle", children: attr.label }),
|
|
326
325
|
/* @__PURE__ */ jsxs(Badge, { size: "2xsmall", color: "grey", children: [
|
|
327
|
-
|
|
326
|
+
typeLabel(attr.type),
|
|
328
327
|
attr.unit ? `, ${attr.unit}` : ""
|
|
329
|
-
] })
|
|
330
|
-
/* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "blue", children: "из родителя" })
|
|
328
|
+
] })
|
|
331
329
|
]
|
|
332
330
|
},
|
|
333
331
|
attr.id
|
|
@@ -375,7 +373,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
375
373
|
children: [
|
|
376
374
|
/* @__PURE__ */ jsx("span", { className: "flex-1 text-sm text-ui-fg-base", children: attr.label }),
|
|
377
375
|
/* @__PURE__ */ jsxs(Badge, { size: "2xsmall", color: "grey", children: [
|
|
378
|
-
|
|
376
|
+
typeLabel(attr.type),
|
|
379
377
|
attr.unit ? `, ${attr.unit}` : ""
|
|
380
378
|
] }),
|
|
381
379
|
/* @__PURE__ */ jsx(
|
|
@@ -447,7 +445,7 @@ const CategoryAttributeTemplatesWidget = ({
|
|
|
447
445
|
size: "small",
|
|
448
446
|
onClick: () => {
|
|
449
447
|
setShowAddForm(false);
|
|
450
|
-
setAddForm(emptyForm$
|
|
448
|
+
setAddForm(emptyForm$1());
|
|
451
449
|
setMutationError(null);
|
|
452
450
|
},
|
|
453
451
|
children: "Отмена"
|
|
@@ -665,71 +663,6 @@ const ProductAttributeValuesWidget = ({
|
|
|
665
663
|
defineWidgetConfig({
|
|
666
664
|
zone: "product.details.after"
|
|
667
665
|
});
|
|
668
|
-
var __defProp$1 = Object.defineProperty;
|
|
669
|
-
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
|
|
670
|
-
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
671
|
-
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
|
|
672
|
-
var __defNormalProp$1 = (obj, key, value2) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
|
|
673
|
-
var __spreadValues$1 = (a, b) => {
|
|
674
|
-
for (var prop in b || (b = {}))
|
|
675
|
-
if (__hasOwnProp$1.call(b, prop))
|
|
676
|
-
__defNormalProp$1(a, prop, b[prop]);
|
|
677
|
-
if (__getOwnPropSymbols$1)
|
|
678
|
-
for (var prop of __getOwnPropSymbols$1(b)) {
|
|
679
|
-
if (__propIsEnum$1.call(b, prop))
|
|
680
|
-
__defNormalProp$1(a, prop, b[prop]);
|
|
681
|
-
}
|
|
682
|
-
return a;
|
|
683
|
-
};
|
|
684
|
-
var __objRest$1 = (source, exclude) => {
|
|
685
|
-
var target = {};
|
|
686
|
-
for (var prop in source)
|
|
687
|
-
if (__hasOwnProp$1.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
688
|
-
target[prop] = source[prop];
|
|
689
|
-
if (source != null && __getOwnPropSymbols$1)
|
|
690
|
-
for (var prop of __getOwnPropSymbols$1(source)) {
|
|
691
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum$1.call(source, prop))
|
|
692
|
-
target[prop] = source[prop];
|
|
693
|
-
}
|
|
694
|
-
return target;
|
|
695
|
-
};
|
|
696
|
-
const Globe = React.forwardRef(
|
|
697
|
-
(_a, ref) => {
|
|
698
|
-
var _b = _a, { color = "currentColor" } = _b, props = __objRest$1(_b, ["color"]);
|
|
699
|
-
return /* @__PURE__ */ React.createElement(
|
|
700
|
-
"svg",
|
|
701
|
-
__spreadValues$1({
|
|
702
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
703
|
-
width: 15,
|
|
704
|
-
height: 15,
|
|
705
|
-
viewBox: "0 0 15 15",
|
|
706
|
-
fill: "none",
|
|
707
|
-
ref
|
|
708
|
-
}, props),
|
|
709
|
-
/* @__PURE__ */ React.createElement(
|
|
710
|
-
"path",
|
|
711
|
-
{
|
|
712
|
-
stroke: color,
|
|
713
|
-
strokeLinecap: "round",
|
|
714
|
-
strokeLinejoin: "round",
|
|
715
|
-
strokeWidth: 1.5,
|
|
716
|
-
d: "M7.5 13.945c1.473 0 2.667-2.886 2.667-6.445S8.973 1.056 7.5 1.056 4.833 3.94 4.833 7.5s1.194 6.445 2.667 6.445M1.056 7.5h12.888"
|
|
717
|
-
}
|
|
718
|
-
),
|
|
719
|
-
/* @__PURE__ */ React.createElement(
|
|
720
|
-
"path",
|
|
721
|
-
{
|
|
722
|
-
stroke: color,
|
|
723
|
-
strokeLinecap: "round",
|
|
724
|
-
strokeLinejoin: "round",
|
|
725
|
-
strokeWidth: 1.5,
|
|
726
|
-
d: "M7.5 13.945a6.444 6.444 0 1 0 0-12.89 6.444 6.444 0 0 0 0 12.89"
|
|
727
|
-
}
|
|
728
|
-
)
|
|
729
|
-
);
|
|
730
|
-
}
|
|
731
|
-
);
|
|
732
|
-
Globe.displayName = "Globe";
|
|
733
666
|
var __defProp = Object.defineProperty;
|
|
734
667
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
735
668
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
@@ -758,7 +691,7 @@ var __objRest = (source, exclude) => {
|
|
|
758
691
|
}
|
|
759
692
|
return target;
|
|
760
693
|
};
|
|
761
|
-
const
|
|
694
|
+
const Tag = React.forwardRef(
|
|
762
695
|
(_a, ref) => {
|
|
763
696
|
var _b = _a, { color = "currentColor" } = _b, props = __objRest(_b, ["color"]);
|
|
764
697
|
return /* @__PURE__ */ React.createElement(
|
|
@@ -771,56 +704,73 @@ const SquaresPlus = React.forwardRef(
|
|
|
771
704
|
fill: "none",
|
|
772
705
|
ref
|
|
773
706
|
}, props),
|
|
774
|
-
/* @__PURE__ */ React.createElement(
|
|
707
|
+
/* @__PURE__ */ React.createElement("g", { clipPath: "url(#a)" }, /* @__PURE__ */ React.createElement(
|
|
775
708
|
"path",
|
|
776
709
|
{
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
d: "M5.056 1.944H2.833a.89.89 0 0 0-.889.89v2.221c0 .491.398.89.89.89h2.222c.49 0 .888-.399.888-.89V2.833a.89.89 0 0 0-.888-.889M12.167 1.944H9.944a.89.89 0 0 0-.888.89v2.221c0 .491.398.89.888.89h2.223c.49 0 .889-.399.889-.89V2.833a.89.89 0 0 0-.89-.889M5.056 9.056H2.833a.89.89 0 0 0-.889.889v2.222c0 .49.398.889.89.889h2.222c.49 0 .888-.398.888-.89V9.946a.89.89 0 0 0-.888-.89M11.056 8.611v4.445M13.278 10.833H8.833"
|
|
710
|
+
fill: color,
|
|
711
|
+
fillRule: "evenodd",
|
|
712
|
+
d: "M2.25 2.389a.14.14 0 0 1 .139-.139h4.375c.272 0 .534.108.727.301l5.11 5.111a1.027 1.027 0 0 1 0 1.453l-3.486 3.487a1.027 1.027 0 0 1-1.453 0L2.552 7.49a1.03 1.03 0 0 1-.302-.727zM2.389.75A1.64 1.64 0 0 0 .75 2.389v4.375c0 .67.267 1.313.74 1.787l5.112 5.111a2.527 2.527 0 0 0 3.574 0l3.486-3.486a2.527 2.527 0 0 0 0-3.574L8.552 1.49A2.53 2.53 0 0 0 6.763.75zm3.778 4.305a1.111 1.111 0 1 1-2.223 0 1.111 1.111 0 0 1 2.223 0",
|
|
713
|
+
clipRule: "evenodd"
|
|
782
714
|
}
|
|
783
|
-
)
|
|
715
|
+
)),
|
|
716
|
+
/* @__PURE__ */ React.createElement("defs", null, /* @__PURE__ */ React.createElement("clipPath", { id: "a" }, /* @__PURE__ */ React.createElement("path", { fill: "#fff", d: "M0 0h15v15H0z" })))
|
|
784
717
|
);
|
|
785
718
|
}
|
|
786
719
|
);
|
|
787
|
-
|
|
788
|
-
const emptyForm
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
720
|
+
Tag.displayName = "Tag";
|
|
721
|
+
const emptyForm = () => ({ label: "", type: "text", unit: "", description: "" });
|
|
722
|
+
const ProductAttributesSettingsPage = () => {
|
|
723
|
+
const t = useT();
|
|
724
|
+
const [tab, setTab] = useState("globals");
|
|
725
|
+
return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
|
|
726
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6 border-b border-ui-border-base px-6 pt-4", children: [
|
|
727
|
+
/* @__PURE__ */ jsx(TabButton, { active: tab === "globals", onClick: () => setTab("globals"), children: t("globals") }),
|
|
728
|
+
/* @__PURE__ */ jsx(TabButton, { active: tab === "templates", onClick: () => setTab("templates"), children: t("templates") })
|
|
729
|
+
] }),
|
|
730
|
+
tab === "globals" ? /* @__PURE__ */ jsx(GlobalsTab, {}) : /* @__PURE__ */ jsx(TemplatesTab, {})
|
|
731
|
+
] });
|
|
732
|
+
};
|
|
733
|
+
const TabButton = ({
|
|
734
|
+
active,
|
|
735
|
+
onClick,
|
|
736
|
+
children
|
|
737
|
+
}) => /* @__PURE__ */ jsx(
|
|
738
|
+
"button",
|
|
739
|
+
{
|
|
740
|
+
onClick,
|
|
741
|
+
className: `-mb-px border-b-2 px-1 pb-3 text-sm font-medium transition-colors ${active ? "border-ui-border-interactive text-ui-fg-base" : "border-transparent text-ui-fg-subtle hover:text-ui-fg-base"}`,
|
|
742
|
+
children
|
|
743
|
+
}
|
|
744
|
+
);
|
|
745
|
+
const GlobalsTab = () => {
|
|
746
|
+
const t = useT();
|
|
796
747
|
const qc = useQueryClient();
|
|
797
|
-
const queryKey = ["
|
|
748
|
+
const queryKey = ["global-attributes"];
|
|
798
749
|
const [showAddForm, setShowAddForm] = useState(false);
|
|
799
|
-
const [addForm, setAddForm] = useState(emptyForm
|
|
750
|
+
const [addForm, setAddForm] = useState(emptyForm());
|
|
800
751
|
const [confirmDeleteId, setConfirmDeleteId] = useState(null);
|
|
801
752
|
const { data, isLoading, isError } = useQuery({
|
|
802
753
|
queryKey,
|
|
803
|
-
queryFn: () => sdk.client.fetch(`/admin/
|
|
754
|
+
queryFn: () => sdk.client.fetch(`/admin/global-attributes`)
|
|
804
755
|
});
|
|
805
|
-
const
|
|
756
|
+
const attrs = (data == null ? void 0 : data.global_attributes) ?? [];
|
|
806
757
|
const createMutation = useMutation({
|
|
807
|
-
mutationFn: (body) => sdk.client.fetch(`/admin/
|
|
758
|
+
mutationFn: (body) => sdk.client.fetch(`/admin/global-attributes`, {
|
|
808
759
|
method: "POST",
|
|
809
760
|
body: {
|
|
810
761
|
label: body.label,
|
|
811
762
|
type: body.type,
|
|
812
|
-
unit: body.type === "number" && body.unit ? body.unit : null
|
|
813
|
-
description: body.description || null
|
|
763
|
+
unit: body.type === "number" && body.unit ? body.unit : null
|
|
814
764
|
}
|
|
815
765
|
}),
|
|
816
766
|
onSuccess: () => {
|
|
817
767
|
qc.invalidateQueries({ queryKey });
|
|
818
768
|
setShowAddForm(false);
|
|
819
|
-
setAddForm(emptyForm
|
|
769
|
+
setAddForm(emptyForm());
|
|
820
770
|
}
|
|
821
771
|
});
|
|
822
772
|
const deleteMutation = useMutation({
|
|
823
|
-
mutationFn: (id) => sdk.client.fetch(`/admin/
|
|
773
|
+
mutationFn: (id) => sdk.client.fetch(`/admin/global-attributes`, {
|
|
824
774
|
method: "PATCH",
|
|
825
775
|
body: { id, deleted_at: (/* @__PURE__ */ new Date()).toISOString() }
|
|
826
776
|
}),
|
|
@@ -838,86 +788,57 @@ const AttributeTemplatesSettingsPage = () => {
|
|
|
838
788
|
description: addForm.description.trim()
|
|
839
789
|
});
|
|
840
790
|
};
|
|
841
|
-
return /* @__PURE__ */ jsxs(
|
|
842
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-
|
|
791
|
+
return /* @__PURE__ */ jsxs("div", { className: "divide-y", children: [
|
|
792
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between px-6 py-4", children: [
|
|
843
793
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
844
|
-
/* @__PURE__ */ jsx(Heading, { level: "
|
|
845
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
794
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", children: t("globals") }),
|
|
795
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("globalsDesc") })
|
|
846
796
|
] }),
|
|
847
|
-
!showAddForm && /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => setShowAddForm(true), children: "
|
|
797
|
+
!showAddForm && /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => setShowAddForm(true), children: t("add") })
|
|
848
798
|
] }),
|
|
849
|
-
isLoading && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "
|
|
850
|
-
isError && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-error text-sm", children: "
|
|
851
|
-
!isLoading && !isError &&
|
|
852
|
-
/* @__PURE__ */ jsx("div", { className: "divide-y", children:
|
|
853
|
-
(
|
|
854
|
-
/* @__PURE__ */
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
/* @__PURE__ */
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
863
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
864
|
-
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: p.label }),
|
|
865
|
-
/* @__PURE__ */ jsxs(Badge, { size: "2xsmall", color: "grey", children: [
|
|
866
|
-
typeLabel$1(p.type),
|
|
867
|
-
p.unit ? `, ${p.unit}` : ""
|
|
868
|
-
] })
|
|
869
|
-
] }),
|
|
870
|
-
p.description && /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-subtle", children: p.description })
|
|
799
|
+
isLoading && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }) }),
|
|
800
|
+
isError && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-error text-sm", children: t("loadFailed") }) }),
|
|
801
|
+
!isLoading && !isError && attrs.length === 0 && !showAddForm && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("noGlobals") }) }),
|
|
802
|
+
/* @__PURE__ */ jsx("div", { className: "divide-y", children: attrs.map(
|
|
803
|
+
(a) => confirmDeleteId === a.id ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-6 py-3 text-sm", children: [
|
|
804
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: t("confirmDelete").replace("{name}", a.label) }),
|
|
805
|
+
/* @__PURE__ */ jsx(Button, { size: "small", variant: "danger", onClick: () => deleteMutation.mutate(a.id), isLoading: deleteMutation.isPending, children: t("delete") }),
|
|
806
|
+
/* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", onClick: () => setConfirmDeleteId(null), children: t("cancel") })
|
|
807
|
+
] }, a.id) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-6 py-3", children: [
|
|
808
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-sm", children: a.label }),
|
|
809
|
+
/* @__PURE__ */ jsxs(Badge, { size: "2xsmall", color: "grey", children: [
|
|
810
|
+
t(`type.${a.type}`, a.type),
|
|
811
|
+
a.unit ? `, ${a.unit}` : ""
|
|
871
812
|
] }),
|
|
872
|
-
/* @__PURE__ */ jsx("button", { onClick: () => setConfirmDeleteId(
|
|
873
|
-
] },
|
|
813
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setConfirmDeleteId(a.id), className: "text-xs text-ui-fg-error hover:underline", children: t("delete") })
|
|
814
|
+
] }, a.id)
|
|
874
815
|
) }),
|
|
875
|
-
showAddForm && /* @__PURE__ */
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
/* @__PURE__ */ jsx("option", { value: "text", children: "Текст" }),
|
|
880
|
-
/* @__PURE__ */ jsx("option", { value: "number", children: "Число" }),
|
|
881
|
-
/* @__PURE__ */ jsx("option", { value: "file", children: "Файл" }),
|
|
882
|
-
/* @__PURE__ */ jsx("option", { value: "boolean", children: "Да/Нет" })
|
|
883
|
-
] }),
|
|
884
|
-
addForm.type === "number" && /* @__PURE__ */ jsx(Input, { value: addForm.unit, onChange: (e) => setAddForm((f) => ({ ...f, unit: e.target.value })), placeholder: "ед.", className: "w-28 h-8 text-sm" })
|
|
885
|
-
] }),
|
|
886
|
-
/* @__PURE__ */ jsx(Input, { value: addForm.description, onChange: (e) => setAddForm((f) => ({ ...f, description: e.target.value })), placeholder: "Описание (необязательно)", className: "h-8 text-sm" }),
|
|
887
|
-
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
888
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => {
|
|
889
|
-
setShowAddForm(false);
|
|
890
|
-
setAddForm(emptyForm$1());
|
|
891
|
-
}, children: "Отмена" }),
|
|
892
|
-
/* @__PURE__ */ jsx(Button, { size: "small", onClick: handleAdd, isLoading: createMutation.isPending, children: "Создать" })
|
|
893
|
-
] })
|
|
894
|
-
] })
|
|
816
|
+
showAddForm && /* @__PURE__ */ jsx(AddForm, { t, form: addForm, setForm: setAddForm, onCancel: () => {
|
|
817
|
+
setShowAddForm(false);
|
|
818
|
+
setAddForm(emptyForm());
|
|
819
|
+
}, onSubmit: handleAdd, isLoading: createMutation.isPending, withDescription: false })
|
|
895
820
|
] });
|
|
896
821
|
};
|
|
897
|
-
const
|
|
898
|
-
|
|
899
|
-
icon: SquaresPlus
|
|
900
|
-
});
|
|
901
|
-
const emptyForm = () => ({ label: "", type: "text", unit: "" });
|
|
902
|
-
const typeLabel = (t) => t === "text" ? "Текст" : t === "number" ? "Число" : t === "file" ? "Файл" : t === "boolean" ? "Да/Нет" : t;
|
|
903
|
-
const GlobalAttributesSettingsPage = () => {
|
|
822
|
+
const TemplatesTab = () => {
|
|
823
|
+
const t = useT();
|
|
904
824
|
const qc = useQueryClient();
|
|
905
|
-
const queryKey = ["
|
|
825
|
+
const queryKey = ["attribute-templates"];
|
|
906
826
|
const [showAddForm, setShowAddForm] = useState(false);
|
|
907
827
|
const [addForm, setAddForm] = useState(emptyForm());
|
|
908
828
|
const [confirmDeleteId, setConfirmDeleteId] = useState(null);
|
|
909
829
|
const { data, isLoading, isError } = useQuery({
|
|
910
830
|
queryKey,
|
|
911
|
-
queryFn: () => sdk.client.fetch(`/admin/
|
|
831
|
+
queryFn: () => sdk.client.fetch(`/admin/attribute-templates`)
|
|
912
832
|
});
|
|
913
|
-
const
|
|
833
|
+
const templates2 = (data == null ? void 0 : data.attribute_templates) ?? [];
|
|
914
834
|
const createMutation = useMutation({
|
|
915
|
-
mutationFn: (body) => sdk.client.fetch(`/admin/
|
|
835
|
+
mutationFn: (body) => sdk.client.fetch(`/admin/attribute-templates`, {
|
|
916
836
|
method: "POST",
|
|
917
837
|
body: {
|
|
918
838
|
label: body.label,
|
|
919
839
|
type: body.type,
|
|
920
|
-
unit: body.type === "number" && body.unit ? body.unit : null
|
|
840
|
+
unit: body.type === "number" && body.unit ? body.unit : null,
|
|
841
|
+
description: body.description || null
|
|
921
842
|
}
|
|
922
843
|
}),
|
|
923
844
|
onSuccess: () => {
|
|
@@ -927,7 +848,7 @@ const GlobalAttributesSettingsPage = () => {
|
|
|
927
848
|
}
|
|
928
849
|
});
|
|
929
850
|
const deleteMutation = useMutation({
|
|
930
|
-
mutationFn: (id) => sdk.client.fetch(`/admin/
|
|
851
|
+
mutationFn: (id) => sdk.client.fetch(`/admin/attribute-templates`, {
|
|
931
852
|
method: "PATCH",
|
|
932
853
|
body: { id, deleted_at: (/* @__PURE__ */ new Date()).toISOString() }
|
|
933
854
|
}),
|
|
@@ -939,60 +860,113 @@ const GlobalAttributesSettingsPage = () => {
|
|
|
939
860
|
const handleAdd = () => {
|
|
940
861
|
if (!addForm.label.trim()) return;
|
|
941
862
|
createMutation.mutate({
|
|
863
|
+
...addForm,
|
|
942
864
|
label: addForm.label.trim(),
|
|
943
|
-
|
|
944
|
-
|
|
865
|
+
unit: addForm.unit.trim(),
|
|
866
|
+
description: addForm.description.trim()
|
|
945
867
|
});
|
|
946
868
|
};
|
|
947
|
-
return /* @__PURE__ */ jsxs(
|
|
948
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-
|
|
869
|
+
return /* @__PURE__ */ jsxs("div", { className: "divide-y", children: [
|
|
870
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between px-6 py-4", children: [
|
|
949
871
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
950
|
-
/* @__PURE__ */ jsx(Heading, { level: "
|
|
951
|
-
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "
|
|
872
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", children: t("templates") }),
|
|
873
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("templatesDesc") })
|
|
952
874
|
] }),
|
|
953
|
-
!showAddForm && /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => setShowAddForm(true), children: "
|
|
875
|
+
!showAddForm && /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => setShowAddForm(true), children: t("add") })
|
|
954
876
|
] }),
|
|
955
|
-
isLoading && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "
|
|
956
|
-
isError && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-error text-sm", children: "
|
|
957
|
-
!isLoading && !isError &&
|
|
958
|
-
/* @__PURE__ */ jsx("div", { className: "divide-y", children:
|
|
959
|
-
(
|
|
960
|
-
/* @__PURE__ */
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
877
|
+
isLoading && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }) }),
|
|
878
|
+
isError && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-error text-sm", children: t("loadFailed") }) }),
|
|
879
|
+
!isLoading && !isError && templates2.length === 0 && !showAddForm && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("noTemplates") }) }),
|
|
880
|
+
/* @__PURE__ */ jsx("div", { className: "divide-y", children: templates2.map(
|
|
881
|
+
(p) => confirmDeleteId === p.id ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-6 py-3 text-sm", children: [
|
|
882
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: t("confirmDelete").replace("{name}", p.label) }),
|
|
883
|
+
/* @__PURE__ */ jsx(Button, { size: "small", variant: "danger", onClick: () => deleteMutation.mutate(p.id), isLoading: deleteMutation.isPending, children: t("delete") }),
|
|
884
|
+
/* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", onClick: () => setConfirmDeleteId(null), children: t("cancel") })
|
|
885
|
+
] }, p.id) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-6 py-3", children: [
|
|
886
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
887
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
888
|
+
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: p.label }),
|
|
889
|
+
/* @__PURE__ */ jsxs(Badge, { size: "2xsmall", color: "grey", children: [
|
|
890
|
+
t(`type.${p.type}`, p.type),
|
|
891
|
+
p.unit ? `, ${p.unit}` : ""
|
|
892
|
+
] })
|
|
893
|
+
] }),
|
|
894
|
+
p.description && /* @__PURE__ */ jsx(Text, { size: "xsmall", className: "text-ui-fg-subtle", children: p.description })
|
|
972
895
|
] }),
|
|
973
|
-
/* @__PURE__ */ jsx("button", { onClick: () => setConfirmDeleteId(
|
|
974
|
-
] },
|
|
896
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setConfirmDeleteId(p.id), className: "text-xs text-ui-fg-error hover:underline", children: t("delete") })
|
|
897
|
+
] }, p.id)
|
|
975
898
|
) }),
|
|
976
|
-
showAddForm && /* @__PURE__ */
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
/* @__PURE__ */ jsx("option", { value: "number", children: "Число" }),
|
|
981
|
-
/* @__PURE__ */ jsx("option", { value: "file", children: "Файл" }),
|
|
982
|
-
/* @__PURE__ */ jsx("option", { value: "boolean", children: "Да/Нет" })
|
|
983
|
-
] }),
|
|
984
|
-
addForm.type === "number" && /* @__PURE__ */ jsx(Input, { value: addForm.unit, onChange: (e) => setAddForm((f) => ({ ...f, unit: e.target.value })), placeholder: "ед.", className: "w-28 h-8 text-sm" }),
|
|
985
|
-
/* @__PURE__ */ jsx(Button, { size: "small", onClick: handleAdd, isLoading: createMutation.isPending, children: "Создать" }),
|
|
986
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => {
|
|
987
|
-
setShowAddForm(false);
|
|
988
|
-
setAddForm(emptyForm());
|
|
989
|
-
}, children: "Отмена" })
|
|
990
|
-
] })
|
|
899
|
+
showAddForm && /* @__PURE__ */ jsx(AddForm, { t, form: addForm, setForm: setAddForm, onCancel: () => {
|
|
900
|
+
setShowAddForm(false);
|
|
901
|
+
setAddForm(emptyForm());
|
|
902
|
+
}, onSubmit: handleAdd, isLoading: createMutation.isPending, withDescription: true })
|
|
991
903
|
] });
|
|
992
904
|
};
|
|
905
|
+
const AddForm = ({
|
|
906
|
+
t,
|
|
907
|
+
form,
|
|
908
|
+
setForm,
|
|
909
|
+
onCancel,
|
|
910
|
+
onSubmit,
|
|
911
|
+
isLoading,
|
|
912
|
+
withDescription
|
|
913
|
+
}) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 px-6 py-4", children: [
|
|
914
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
915
|
+
/* @__PURE__ */ jsx(
|
|
916
|
+
Input,
|
|
917
|
+
{
|
|
918
|
+
value: form.label,
|
|
919
|
+
onChange: (e) => setForm((f) => ({ ...f, label: e.target.value })),
|
|
920
|
+
placeholder: t("name"),
|
|
921
|
+
className: "flex-1 h-8 text-sm",
|
|
922
|
+
autoFocus: true
|
|
923
|
+
}
|
|
924
|
+
),
|
|
925
|
+
/* @__PURE__ */ jsxs(
|
|
926
|
+
"select",
|
|
927
|
+
{
|
|
928
|
+
value: form.type,
|
|
929
|
+
onChange: (e) => setForm((f) => ({
|
|
930
|
+
...f,
|
|
931
|
+
type: e.target.value,
|
|
932
|
+
unit: e.target.value === "number" ? f.unit : ""
|
|
933
|
+
})),
|
|
934
|
+
className: "h-8 rounded border border-ui-border-base bg-ui-bg-base px-2 text-sm",
|
|
935
|
+
children: [
|
|
936
|
+
/* @__PURE__ */ jsx("option", { value: "text", children: t("type.text") }),
|
|
937
|
+
/* @__PURE__ */ jsx("option", { value: "number", children: t("type.number") }),
|
|
938
|
+
/* @__PURE__ */ jsx("option", { value: "file", children: t("type.file") }),
|
|
939
|
+
/* @__PURE__ */ jsx("option", { value: "boolean", children: t("type.boolean") })
|
|
940
|
+
]
|
|
941
|
+
}
|
|
942
|
+
),
|
|
943
|
+
form.type === "number" && /* @__PURE__ */ jsx(
|
|
944
|
+
Input,
|
|
945
|
+
{
|
|
946
|
+
value: form.unit,
|
|
947
|
+
onChange: (e) => setForm((f) => ({ ...f, unit: e.target.value })),
|
|
948
|
+
placeholder: t("unit"),
|
|
949
|
+
className: "w-28 h-8 text-sm"
|
|
950
|
+
}
|
|
951
|
+
)
|
|
952
|
+
] }),
|
|
953
|
+
withDescription && /* @__PURE__ */ jsx(
|
|
954
|
+
Input,
|
|
955
|
+
{
|
|
956
|
+
value: form.description,
|
|
957
|
+
onChange: (e) => setForm((f) => ({ ...f, description: e.target.value })),
|
|
958
|
+
placeholder: t("description"),
|
|
959
|
+
className: "h-8 text-sm"
|
|
960
|
+
}
|
|
961
|
+
),
|
|
962
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
963
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: onCancel, children: t("cancel") }),
|
|
964
|
+
/* @__PURE__ */ jsx(Button, { size: "small", onClick: onSubmit, isLoading, children: t("create") })
|
|
965
|
+
] })
|
|
966
|
+
] });
|
|
993
967
|
const config = defineRouteConfig({
|
|
994
|
-
label: "
|
|
995
|
-
icon:
|
|
968
|
+
label: "Product Attributes",
|
|
969
|
+
icon: Tag
|
|
996
970
|
});
|
|
997
971
|
const widgetModule = { widgets: [
|
|
998
972
|
{
|
|
@@ -1007,29 +981,17 @@ const widgetModule = { widgets: [
|
|
|
1007
981
|
const routeModule = {
|
|
1008
982
|
routes: [
|
|
1009
983
|
{
|
|
1010
|
-
Component:
|
|
1011
|
-
path: "/settings/
|
|
1012
|
-
},
|
|
1013
|
-
{
|
|
1014
|
-
Component: GlobalAttributesSettingsPage,
|
|
1015
|
-
path: "/settings/global-attributes"
|
|
984
|
+
Component: ProductAttributesSettingsPage,
|
|
985
|
+
path: "/settings/product-attributes"
|
|
1016
986
|
}
|
|
1017
987
|
]
|
|
1018
988
|
};
|
|
1019
989
|
const menuItemModule = {
|
|
1020
990
|
menuItems: [
|
|
1021
|
-
{
|
|
1022
|
-
label: config$1.label,
|
|
1023
|
-
icon: config$1.icon,
|
|
1024
|
-
path: "/settings/attribute-templates",
|
|
1025
|
-
nested: void 0,
|
|
1026
|
-
rank: void 0,
|
|
1027
|
-
translationNs: void 0
|
|
1028
|
-
},
|
|
1029
991
|
{
|
|
1030
992
|
label: config.label,
|
|
1031
993
|
icon: config.icon,
|
|
1032
|
-
path: "/settings/
|
|
994
|
+
path: "/settings/product-attributes",
|
|
1033
995
|
nested: void 0,
|
|
1034
996
|
rank: void 0,
|
|
1035
997
|
translationNs: void 0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empty-complete-org/medusa-product-attributes",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Custom attributes module for Medusa v2 with support for text, number, file types and units of measurement",
|
|
5
5
|
"author": "empty-complete",
|
|
6
6
|
"license": "MIT",
|