@griddo/ax 1.65.10 → 1.65.13
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/package.json +3 -2
- package/src/components/Button/index.tsx +15 -2
- package/src/components/Fields/AnalyticsField/PageAnalytics/index.test.tsx +204 -0
- package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/atoms.tsx +1 -0
- package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/index.test.tsx +146 -0
- package/src/components/Fields/ArrayFieldGroup/ArrayFieldInline/index.tsx +2 -1
- package/src/components/Fields/ArrayFieldGroup/ArrayFieldItem/index.tsx +1 -1
- package/src/components/Fields/ArrayFieldGroup/index.test.tsx +277 -0
- package/src/components/Fields/ArrayFieldGroup/index.tsx +0 -1
- package/src/components/Fields/AsyncCheckGroup/index.test.tsx +108 -0
- package/src/components/Fields/AsyncCheckGroup/index.tsx +3 -3
- package/src/components/Fields/AsyncSelect/index.test.tsx +306 -0
- package/src/components/Fields/AsyncSelect/index.tsx +18 -17
- package/src/components/Fields/HeadingField/index.test.tsx +71 -0
- package/src/components/Fields/HeadingField/index.tsx +1 -1
- package/src/components/Fields/Select/index.tsx +39 -24
- package/src/components/Fields/UrlField/index.tsx +38 -4
- package/src/components/Fields/UrlField/utils.tsx +74 -14
- package/src/components/FieldsBehavior/index.tsx +1 -1
- package/src/types/index.tsx +6 -5
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import "@testing-library/jest-dom";
|
|
4
|
+
import AsyncSelect from "./index";
|
|
5
|
+
import { ThemeProvider } from "styled-components";
|
|
6
|
+
import { parseTheme } from "@griddo/core";
|
|
7
|
+
import globalTheme from "../../../themes/theme.json";
|
|
8
|
+
import { render, screen, cleanup, act } from "@testing-library/react";
|
|
9
|
+
import { ISite } from "@ax/types";
|
|
10
|
+
import { mock } from "jest-mock-extended";
|
|
11
|
+
|
|
12
|
+
afterEach(cleanup);
|
|
13
|
+
|
|
14
|
+
const defaultProps = mock<IAsyncSelectProps>();
|
|
15
|
+
|
|
16
|
+
const defaultSite = mock<ISite>();
|
|
17
|
+
defaultSite.id = 113;
|
|
18
|
+
|
|
19
|
+
jest.mock("axios");
|
|
20
|
+
const mockedAxios = axios as jest.MockedFunction<typeof axios>;
|
|
21
|
+
|
|
22
|
+
describe("AsyncSelect component rendering", () => {
|
|
23
|
+
test("should render the component AsyncSelect", async () => {
|
|
24
|
+
defaultProps.name = "texto de prueba";
|
|
25
|
+
await act(async () => {
|
|
26
|
+
render(
|
|
27
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
28
|
+
<AsyncSelect {...defaultProps} />
|
|
29
|
+
</ThemeProvider>
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
expect(screen.getByTestId("asyncSelect")).toBeTruthy();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("AsyncSelect component events", () => {
|
|
37
|
+
test("should call the api and receive data in pages", async () => {
|
|
38
|
+
defaultProps.site = defaultSite;
|
|
39
|
+
defaultProps.entity = "pages";
|
|
40
|
+
defaultProps.options = {
|
|
41
|
+
excludeDetailPages: true,
|
|
42
|
+
};
|
|
43
|
+
defaultProps.lang = "en_GB";
|
|
44
|
+
defaultProps.selectedContent = { id: 1 };
|
|
45
|
+
defaultProps.value = [3622, 3621];
|
|
46
|
+
|
|
47
|
+
const data = {
|
|
48
|
+
data: [
|
|
49
|
+
{
|
|
50
|
+
value: 3622,
|
|
51
|
+
label: "Home",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
value: 3731,
|
|
55
|
+
label: "English child",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
value: 3730,
|
|
59
|
+
label: "English Parent",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
value: 3787,
|
|
63
|
+
label: "English test",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
value: 3745,
|
|
67
|
+
label: "New Page",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
value: 3784,
|
|
71
|
+
label: "Prueba",
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
status: 200,
|
|
75
|
+
statusText: "Ok",
|
|
76
|
+
headers: {},
|
|
77
|
+
config: {},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
mockedAxios.mockResolvedValue(data);
|
|
81
|
+
|
|
82
|
+
await act(async () => {
|
|
83
|
+
render(
|
|
84
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
85
|
+
<AsyncSelect {...defaultProps} />
|
|
86
|
+
</ThemeProvider>
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(screen.getByTestId("asyncSelect")).toHaveTextContent("Home");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("should call the api and receive data in pages with no selectedContent", async () => {
|
|
94
|
+
defaultProps.site = defaultSite;
|
|
95
|
+
defaultProps.entity = "pages";
|
|
96
|
+
defaultProps.options = {
|
|
97
|
+
excludeDetailPages: true,
|
|
98
|
+
};
|
|
99
|
+
defaultProps.lang = "en_GB";
|
|
100
|
+
defaultProps.selectedContent = null;
|
|
101
|
+
defaultProps.value = 3622;
|
|
102
|
+
|
|
103
|
+
const data = {
|
|
104
|
+
data: [
|
|
105
|
+
{
|
|
106
|
+
value: 3622,
|
|
107
|
+
label: "Home",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
value: 3731,
|
|
111
|
+
label: "English child",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
value: 3730,
|
|
115
|
+
label: "English Parent",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
value: 3787,
|
|
119
|
+
label: "English test",
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
value: 3745,
|
|
123
|
+
label: "New Page",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
value: 3784,
|
|
127
|
+
label: "Prueba",
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
status: 200,
|
|
131
|
+
statusText: "Ok",
|
|
132
|
+
headers: {},
|
|
133
|
+
config: {},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
mockedAxios.mockResolvedValue(data);
|
|
137
|
+
|
|
138
|
+
await act(async () => {
|
|
139
|
+
render(
|
|
140
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
141
|
+
<AsyncSelect {...defaultProps} />
|
|
142
|
+
</ThemeProvider>
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
expect(screen.getByTestId("asyncSelect")).toHaveTextContent("Home");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("should call the api and receive data in categories", async () => {
|
|
150
|
+
defaultProps.site = defaultSite;
|
|
151
|
+
defaultProps.entity = "categories";
|
|
152
|
+
defaultProps.options = {
|
|
153
|
+
excludeDetailPages: true,
|
|
154
|
+
};
|
|
155
|
+
defaultProps.lang = "en_GB";
|
|
156
|
+
defaultProps.value = 3622;
|
|
157
|
+
|
|
158
|
+
const data = {
|
|
159
|
+
data: [
|
|
160
|
+
{
|
|
161
|
+
value: 3622,
|
|
162
|
+
label: "Home",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
value: 3731,
|
|
166
|
+
label: "English child",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
value: 3730,
|
|
170
|
+
label: "English Parent",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
value: 3787,
|
|
174
|
+
label: "English test",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
value: 3745,
|
|
178
|
+
label: "New Page",
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
value: 3784,
|
|
182
|
+
label: "Prueba",
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
status: 200,
|
|
186
|
+
statusText: "Ok",
|
|
187
|
+
headers: {},
|
|
188
|
+
config: {},
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
mockedAxios.mockResolvedValue(data);
|
|
192
|
+
|
|
193
|
+
await act(async () => {
|
|
194
|
+
render(
|
|
195
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
196
|
+
<AsyncSelect {...defaultProps} />
|
|
197
|
+
</ThemeProvider>
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
expect(screen.getByTestId("asyncSelect")).toHaveTextContent("Home");
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("should call the api and not receiving data", async () => {
|
|
205
|
+
defaultProps.site = defaultSite;
|
|
206
|
+
defaultProps.entity = "categories";
|
|
207
|
+
defaultProps.options = {
|
|
208
|
+
excludeDetailPages: true,
|
|
209
|
+
};
|
|
210
|
+
defaultProps.lang = "en_GB";
|
|
211
|
+
|
|
212
|
+
const data = {
|
|
213
|
+
data: [],
|
|
214
|
+
status: 500,
|
|
215
|
+
statusText: "Ok",
|
|
216
|
+
headers: {},
|
|
217
|
+
config: {},
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
mockedAxios.mockResolvedValue(data);
|
|
221
|
+
|
|
222
|
+
await act(async () => {
|
|
223
|
+
render(
|
|
224
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
225
|
+
<AsyncSelect {...defaultProps} />
|
|
226
|
+
</ThemeProvider>
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
expect(screen.getByTestId("asyncSelect")).not.toHaveTextContent("Home");
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("should call the api with source", async () => {
|
|
234
|
+
defaultProps.site = defaultSite;
|
|
235
|
+
defaultProps.entity = "categories";
|
|
236
|
+
defaultProps.source = "source";
|
|
237
|
+
defaultProps.options = {
|
|
238
|
+
excludeDetailPages: true,
|
|
239
|
+
};
|
|
240
|
+
defaultProps.lang = "en_GB";
|
|
241
|
+
defaultProps.value = 3787;
|
|
242
|
+
|
|
243
|
+
const data = {
|
|
244
|
+
data: [
|
|
245
|
+
{
|
|
246
|
+
value: 3622,
|
|
247
|
+
title: "Home",
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
value: 3731,
|
|
251
|
+
title: "English child",
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
value: 3730,
|
|
255
|
+
title: "English Parent",
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
value: 3787,
|
|
259
|
+
title: "English test",
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
value: 3745,
|
|
263
|
+
title: "New Page",
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
value: 3784,
|
|
267
|
+
title: "Prueba",
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
status: 200,
|
|
271
|
+
statusText: "Ok",
|
|
272
|
+
headers: {},
|
|
273
|
+
config: {},
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
mockedAxios.mockResolvedValue(data);
|
|
277
|
+
|
|
278
|
+
await act(async () => {
|
|
279
|
+
render(
|
|
280
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
281
|
+
<AsyncSelect {...defaultProps} />
|
|
282
|
+
</ThemeProvider>
|
|
283
|
+
);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
expect(screen.getByTestId("asyncSelect")).toHaveTextContent("English test");
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
interface IAsyncSelectProps {
|
|
291
|
+
name: string;
|
|
292
|
+
value: any;
|
|
293
|
+
entity?: string;
|
|
294
|
+
entityId?: string | number;
|
|
295
|
+
error?: boolean;
|
|
296
|
+
disabled?: boolean;
|
|
297
|
+
onChange: (value: string) => void;
|
|
298
|
+
site: ISite;
|
|
299
|
+
lang: string;
|
|
300
|
+
selectedContent: any;
|
|
301
|
+
mandatory?: boolean;
|
|
302
|
+
placeholder?: string;
|
|
303
|
+
filter?: any[];
|
|
304
|
+
options?: any;
|
|
305
|
+
source?: string;
|
|
306
|
+
}
|
|
@@ -33,7 +33,6 @@ const AsyncSelect = (props: IAsyncSelectProps): JSX.Element => {
|
|
|
33
33
|
|
|
34
34
|
const isPage = entity === "pages";
|
|
35
35
|
const isCategories = entity === "categories";
|
|
36
|
-
|
|
37
36
|
useEffect(() => {
|
|
38
37
|
const getItems = async () => {
|
|
39
38
|
let data = [];
|
|
@@ -123,21 +122,23 @@ const AsyncSelect = (props: IAsyncSelectProps): JSX.Element => {
|
|
|
123
122
|
const className = error ? "react-select-error" : "";
|
|
124
123
|
|
|
125
124
|
return (
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
125
|
+
<div data-testid="asyncSelect">
|
|
126
|
+
<S.StyledSelect
|
|
127
|
+
name={name}
|
|
128
|
+
value={getObjectValue(value, state.items) || ""}
|
|
129
|
+
cacheOptions
|
|
130
|
+
loadOptions={loadOptions}
|
|
131
|
+
defaultOptions={state.items}
|
|
132
|
+
onInputChange={handleInputChange}
|
|
133
|
+
onChange={handleChange}
|
|
134
|
+
classNamePrefix="react-select"
|
|
135
|
+
error={error}
|
|
136
|
+
isDisabled={disabled}
|
|
137
|
+
className={className}
|
|
138
|
+
mandatory={mandatory}
|
|
139
|
+
hasEmptyOption={state.hasEmptyOption}
|
|
140
|
+
/>
|
|
141
|
+
</div>
|
|
141
142
|
);
|
|
142
143
|
};
|
|
143
144
|
|
|
@@ -159,7 +160,7 @@ interface IAsyncSelectProps {
|
|
|
159
160
|
error?: boolean;
|
|
160
161
|
disabled?: boolean;
|
|
161
162
|
onChange: (value: string) => void;
|
|
162
|
-
site: ISite;
|
|
163
|
+
site: ISite | null;
|
|
163
164
|
lang: string;
|
|
164
165
|
selectedContent: any;
|
|
165
166
|
mandatory?: boolean;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import HeadingField from "./index";
|
|
3
|
+
import { ThemeProvider } from "styled-components";
|
|
4
|
+
import { parseTheme } from "@griddo/core";
|
|
5
|
+
import globalTheme from "../../../themes/theme.json";
|
|
6
|
+
import { render, screen, cleanup } from "@testing-library/react";
|
|
7
|
+
|
|
8
|
+
afterEach(cleanup);
|
|
9
|
+
|
|
10
|
+
const defaultProps = {
|
|
11
|
+
value: {
|
|
12
|
+
content: "",
|
|
13
|
+
tag: "",
|
|
14
|
+
},
|
|
15
|
+
title: "",
|
|
16
|
+
onChange: jest.fn(),
|
|
17
|
+
options: [
|
|
18
|
+
{
|
|
19
|
+
value: "",
|
|
20
|
+
label: "",
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
showAdvanced: false,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
describe("HeadingField component rendering", () => {
|
|
27
|
+
it("should render the component with only TextField", () => {
|
|
28
|
+
render(
|
|
29
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
30
|
+
<HeadingField {...defaultProps} />
|
|
31
|
+
</ThemeProvider>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const textFieldContainer = screen.getByTestId("textFieldContainer");
|
|
35
|
+
|
|
36
|
+
expect(textFieldContainer).toBeTruthy();
|
|
37
|
+
});
|
|
38
|
+
it("should render the component complete", () => {
|
|
39
|
+
const props = {
|
|
40
|
+
value: {
|
|
41
|
+
content: "value1",
|
|
42
|
+
tag: "tagValue",
|
|
43
|
+
},
|
|
44
|
+
title: "Title",
|
|
45
|
+
onChange: jest.fn(),
|
|
46
|
+
options: [
|
|
47
|
+
{
|
|
48
|
+
value: "value1",
|
|
49
|
+
label: "Value 1",
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
showAdvanced: true,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
render(
|
|
56
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
57
|
+
<HeadingField {...props} />
|
|
58
|
+
</ThemeProvider>
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const textFieldContainer = screen.getByTestId("textFieldContainer");
|
|
62
|
+
const textFieldAdvancedWrapper = screen.getByTestId("textFieldAdvancedWrapper");
|
|
63
|
+
const contentWrapper = screen.getByTestId("contentWrapper");
|
|
64
|
+
const selectComponent = screen.getByTestId("selectComponent");
|
|
65
|
+
|
|
66
|
+
expect(textFieldContainer).toBeTruthy();
|
|
67
|
+
expect(textFieldAdvancedWrapper).toBeTruthy();
|
|
68
|
+
expect(contentWrapper).toBeTruthy();
|
|
69
|
+
expect(selectComponent).toBeTruthy();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -16,7 +16,7 @@ const HeadingField = (props: IHeadingFieldProps): JSX.Element => {
|
|
|
16
16
|
<>
|
|
17
17
|
<TextField {...props} value={contentValue} onChange={handleChange} />
|
|
18
18
|
{showAdvanced && (
|
|
19
|
-
<S.AdvancedWrapper>
|
|
19
|
+
<S.AdvancedWrapper data-testid="textFieldAdvancedWrapper">
|
|
20
20
|
<FieldsBehavior fieldType="Select" options={options} value={value.tag} onChange={handleSelectChange} />
|
|
21
21
|
</S.AdvancedWrapper>
|
|
22
22
|
)}
|
|
@@ -3,15 +3,28 @@ import React, { useState } from "react";
|
|
|
3
3
|
import * as S from "./style";
|
|
4
4
|
|
|
5
5
|
const Select = (props: ISelectProps): JSX.Element => {
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
name,
|
|
8
|
+
value,
|
|
9
|
+
options,
|
|
10
|
+
error,
|
|
11
|
+
defaultValue,
|
|
12
|
+
placeholder,
|
|
13
|
+
isMulti,
|
|
14
|
+
disabled,
|
|
15
|
+
type,
|
|
16
|
+
mandatory,
|
|
17
|
+
onChange,
|
|
18
|
+
alignRight,
|
|
19
|
+
} = props;
|
|
7
20
|
const className = error ? `react-select-error ${type}` : type;
|
|
8
21
|
const emptyOption = { value: null, label: placeholder || "Empty" };
|
|
9
|
-
|
|
22
|
+
|
|
10
23
|
const isMandatory = !mandatory && type !== "inline";
|
|
11
24
|
const [hasEmptyOption, setHasEmptyOption] = useState(isMandatory);
|
|
12
|
-
|
|
13
|
-
const optionValues: any = hasEmptyOption ? [emptyOption
|
|
14
|
-
|
|
25
|
+
|
|
26
|
+
const optionValues: any = hasEmptyOption ? [emptyOption, ...options] : options;
|
|
27
|
+
|
|
15
28
|
const handleChange = (selectedValue: IOptionProps) => {
|
|
16
29
|
onChange(selectedValue.value);
|
|
17
30
|
};
|
|
@@ -20,7 +33,7 @@ const Select = (props: ISelectProps): JSX.Element => {
|
|
|
20
33
|
const inputValue = newValue.replace(/\W/g, "");
|
|
21
34
|
setHasEmptyOption(isMandatory && inputValue.length === 0);
|
|
22
35
|
return inputValue;
|
|
23
|
-
}
|
|
36
|
+
};
|
|
24
37
|
|
|
25
38
|
// tslint:disable-next-line: no-shadowed-variable
|
|
26
39
|
const getObjectValue = (value: string, options: IOptionProps[]) => {
|
|
@@ -29,28 +42,30 @@ const Select = (props: ISelectProps): JSX.Element => {
|
|
|
29
42
|
} else {
|
|
30
43
|
return options.find((option) => option.value === value);
|
|
31
44
|
}
|
|
32
|
-
}
|
|
45
|
+
};
|
|
33
46
|
|
|
34
47
|
const searchable = type === "inline" ? false : true;
|
|
35
48
|
|
|
36
49
|
return (
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
<div data-testid="selectComponent">
|
|
51
|
+
<S.StyledSelect
|
|
52
|
+
name={name}
|
|
53
|
+
value={getObjectValue(value, optionValues)}
|
|
54
|
+
options={optionValues}
|
|
55
|
+
isMulti={isMulti}
|
|
56
|
+
isDisabled={disabled}
|
|
57
|
+
placeholder={placeholder}
|
|
58
|
+
defaultValue={defaultValue}
|
|
59
|
+
className={className}
|
|
60
|
+
classNamePrefix="react-select"
|
|
61
|
+
error={error}
|
|
62
|
+
onChange={handleChange}
|
|
63
|
+
isSearchable={searchable}
|
|
64
|
+
hasEmptyOption={hasEmptyOption}
|
|
65
|
+
onInputChange={handleInputChange}
|
|
66
|
+
alignRight={alignRight}
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
54
69
|
);
|
|
55
70
|
};
|
|
56
71
|
|
|
@@ -6,7 +6,7 @@ import { isReqOk } from "@ax/helpers";
|
|
|
6
6
|
import { IPage, IUrlField, Field, ISelectOption } from "@ax/types";
|
|
7
7
|
import { pages as pagesApi } from "@ax/api";
|
|
8
8
|
import PageFinder from "./PageFinder";
|
|
9
|
-
import { findAnchorsFromPage } from "./utils";
|
|
9
|
+
import { findAnchorsFromPage, findAnchorsFromTab, findTabsFromPage } from "./utils";
|
|
10
10
|
|
|
11
11
|
import * as S from "./style";
|
|
12
12
|
|
|
@@ -14,8 +14,11 @@ const UrlField = (props: IUrlFieldProps): JSX.Element => {
|
|
|
14
14
|
const { value, onChange, showAdvanced, handlePanel, inFloatingPanel, disabled, handleValidation, validators } = props;
|
|
15
15
|
const { isOpen, toggleModal } = useModal();
|
|
16
16
|
const [anchorOptions, setAnchorOptions] = useState<ISelectOption[]>([]);
|
|
17
|
+
const [tabOptions, setTabOptions] = useState<ISelectOption[]>([]);
|
|
17
18
|
const [isVisible, setIsVisible] = useState<boolean>(false);
|
|
19
|
+
const [isTabsVisible, setTabsVisible] = useState<boolean>(false);
|
|
18
20
|
const [internalPageName, setInternalPageName] = useState(null);
|
|
21
|
+
const [pageData, setPageData] = useState<IPage | null>(null);
|
|
19
22
|
|
|
20
23
|
const pageID = value && value.linkTo ? value.linkTo : null;
|
|
21
24
|
|
|
@@ -24,17 +27,23 @@ const UrlField = (props: IUrlFieldProps): JSX.Element => {
|
|
|
24
27
|
const response = await pagesApi.getPageInfo(id);
|
|
25
28
|
if (isReqOk(response.status)) {
|
|
26
29
|
const { data } = response;
|
|
30
|
+
setPageData(data);
|
|
27
31
|
setInternalPageName(data.title);
|
|
28
32
|
|
|
29
33
|
onChange({
|
|
30
34
|
...value,
|
|
31
35
|
...(!data.follow && { noFollow: true }),
|
|
32
|
-
...(!value?.title && { title: data.title })
|
|
36
|
+
...(!value?.title && { title: data.title }),
|
|
33
37
|
});
|
|
34
38
|
|
|
35
|
-
const
|
|
39
|
+
const tabs: ISelectOption[] = findTabsFromPage(data);
|
|
40
|
+
setTabOptions(tabs);
|
|
41
|
+
if (tabs.length > 0) setTabsVisible(true);
|
|
42
|
+
|
|
43
|
+
const anchors: ISelectOption[] =
|
|
44
|
+
tabs.length && value?.subSlug ? findAnchorsFromTab(data, value.subSlug) : findAnchorsFromPage(data);
|
|
36
45
|
setAnchorOptions(anchors);
|
|
37
|
-
if (anchors.length > 0) setIsVisible(true);
|
|
46
|
+
if (anchors.length > 0 && (!tabs.length || (tabs.length && value?.subSlug))) setIsVisible(true);
|
|
38
47
|
} else {
|
|
39
48
|
setAnchorOptions([]);
|
|
40
49
|
}
|
|
@@ -42,6 +51,7 @@ const UrlField = (props: IUrlFieldProps): JSX.Element => {
|
|
|
42
51
|
|
|
43
52
|
let isMounted = true;
|
|
44
53
|
if (isMounted && pageID) {
|
|
54
|
+
setTabsVisible(false);
|
|
45
55
|
setIsVisible(false);
|
|
46
56
|
getPageInfo(pageID);
|
|
47
57
|
}
|
|
@@ -79,6 +89,17 @@ const UrlField = (props: IUrlFieldProps): JSX.Element => {
|
|
|
79
89
|
|
|
80
90
|
const handleAnchorChange = (newValue: string) => onChange({ ...value, anchor: newValue });
|
|
81
91
|
|
|
92
|
+
const handleTabChange = (newValue: string) => {
|
|
93
|
+
onChange({ ...value, subSlug: newValue });
|
|
94
|
+
if (pageData && newValue) {
|
|
95
|
+
const anchors: ISelectOption[] = findAnchorsFromTab(pageData, newValue);
|
|
96
|
+
setAnchorOptions(anchors);
|
|
97
|
+
if (anchors.length > 0) setIsVisible(true);
|
|
98
|
+
} else {
|
|
99
|
+
setIsVisible(false);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
82
103
|
const validator = { format: "fullURL" };
|
|
83
104
|
const defensiveHref = value ? value.href : "";
|
|
84
105
|
|
|
@@ -132,6 +153,19 @@ const UrlField = (props: IUrlFieldProps): JSX.Element => {
|
|
|
132
153
|
return (
|
|
133
154
|
<>
|
|
134
155
|
{field}
|
|
156
|
+
{value && value.linkTo && isTabsVisible && (
|
|
157
|
+
<S.AnchorWrapper>
|
|
158
|
+
<FieldsBehavior
|
|
159
|
+
title="Tab"
|
|
160
|
+
options={tabOptions}
|
|
161
|
+
name="tab"
|
|
162
|
+
fieldType="Select"
|
|
163
|
+
value={value.subSlug}
|
|
164
|
+
onChange={handleTabChange}
|
|
165
|
+
placeholder="Select Tab"
|
|
166
|
+
/>
|
|
167
|
+
</S.AnchorWrapper>
|
|
168
|
+
)}
|
|
135
169
|
{value && value.linkTo && isVisible && (
|
|
136
170
|
<S.AnchorWrapper>
|
|
137
171
|
<FieldsBehavior
|