@onewelcome/react-lib-components 1.5.0 → 1.7.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/README.md +4 -4
- package/dist/Button/Button.d.ts +0 -1
- package/dist/DataGrid/datagrid.interfaces.d.ts +1 -0
- package/dist/Form/Checkbox/Checkbox.d.ts +1 -1
- package/dist/Form/FileUpload/FileItem/FileItem.d.ts +17 -0
- package/dist/Form/FileUpload/FileUpload.d.ts +26 -0
- package/dist/Form/FormHelperText/FormHelperText.d.ts +1 -1
- package/dist/Form/FormSelectorWrapper/FormSelectorWrapper.d.ts +1 -1
- package/dist/Form/Input/Input.d.ts +2 -2
- package/dist/Form/Radio/Radio.d.ts +1 -1
- package/dist/Form/Select/Select.d.ts +1 -1
- package/dist/Form/Textarea/Textarea.d.ts +1 -6
- package/dist/Form/Toggle/Toggle.d.ts +1 -1
- package/dist/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.d.ts +1 -1
- package/dist/Form/Wrapper/InputWrapper/InputWrapper.d.ts +1 -1
- package/dist/Form/Wrapper/RadioWrapper/RadioWrapper.d.ts +1 -1
- package/dist/Form/Wrapper/SelectWrapper/SelectWrapper.d.ts +1 -1
- package/dist/Form/Wrapper/TextareaWrapper/TextareaWrapper.d.ts +1 -1
- package/dist/Form/form.interfaces.d.ts +1 -0
- package/dist/Icon/Icon.d.ts +4 -1
- package/dist/Link/Link.d.ts +1 -2
- package/dist/Notifications/Banner/Banner.d.ts +11 -0
- package/dist/ProgressBar/ProgressBar.d.ts +2 -1
- package/dist/Tabs/TabButton.d.ts +0 -1
- package/dist/_BaseStyling_/BaseStyling.d.ts +5 -0
- package/dist/hooks/useDetermineStatusIcon.d.ts +3 -0
- package/dist/hooks/useUploadFile.d.ts +22 -0
- package/dist/index.d.ts +1 -0
- package/dist/react-lib-components.cjs.development.js +431 -326
- package/dist/react-lib-components.cjs.development.js.map +1 -1
- package/dist/react-lib-components.cjs.production.min.js +1 -1
- package/dist/react-lib-components.cjs.production.min.js.map +1 -1
- package/dist/react-lib-components.esm.js +431 -327
- package/dist/react-lib-components.esm.js.map +1 -1
- package/dist/util/helper.d.ts +5 -0
- package/package.json +28 -25
- package/src/Button/BaseButton.module.scss +2 -2
- package/src/Button/Button.module.scss +4 -5
- package/src/Button/Button.tsx +0 -1
- package/src/Button/IconButton.module.scss +4 -5
- package/src/DataGrid/DataGrid.tsx +3 -2
- package/src/DataGrid/DataGridActions/DataGridActions.tsx +16 -9
- package/src/DataGrid/DataGridBody/DataGridCell.module.scss +2 -2
- package/src/DataGrid/DataGridHeader/DataGridHeader.test.tsx +8 -3
- package/src/DataGrid/DataGridHeader/DataGridHeader.tsx +3 -1
- package/src/DataGrid/datagrid.interfaces.ts +1 -0
- package/src/Form/FileUpload/FileItem/FileItem.modules.scss +75 -0
- package/src/Form/FileUpload/FileItem/FileItem.test.tsx +103 -0
- package/src/Form/FileUpload/FileItem/FileItem.tsx +141 -0
- package/src/Form/FileUpload/FileUpload.module.scss +106 -0
- package/src/Form/FileUpload/FileUpload.test.tsx +374 -0
- package/src/Form/FileUpload/FileUpload.tsx +251 -0
- package/src/Form/Input/Input.module.scss +36 -26
- package/src/Form/Input/Input.test.tsx +10 -0
- package/src/Form/Input/Input.tsx +7 -5
- package/src/Form/Select/Select.module.scss +9 -6
- package/src/Form/Select/Select.test.tsx +11 -0
- package/src/Form/Select/Select.tsx +5 -9
- package/src/Form/Select/SelectService.ts +2 -2
- package/src/Form/Textarea/Textarea.module.scss +21 -13
- package/src/Form/Textarea/Textarea.test.tsx +8 -0
- package/src/Form/Textarea/Textarea.tsx +6 -12
- package/src/Form/Toggle/Toggle.module.scss +3 -3
- package/src/Form/Wrapper/InputWrapper/InputWrapper.module.scss +7 -3
- package/src/Form/Wrapper/InputWrapper/InputWrapper.tsx +2 -0
- package/src/Form/Wrapper/SelectWrapper/SelectWrapper.tsx +12 -1
- package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.module.scss +15 -14
- package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.tsx +2 -1
- package/src/Form/Wrapper/Wrapper/Wrapper.module.scss +2 -2
- package/src/Form/form.interfaces.ts +1 -0
- package/src/Icon/Icon.module.scss +12 -0
- package/src/Icon/Icon.tsx +4 -1
- package/src/Link/Link.module.scss +5 -5
- package/src/Link/Link.tsx +14 -13
- package/src/Notifications/Banner/Banner.module.scss +76 -0
- package/src/Notifications/Banner/Banner.test.tsx +84 -0
- package/src/Notifications/Banner/Banner.tsx +78 -0
- package/src/Notifications/BaseModal/BaseModal.module.scss +2 -2
- package/src/Notifications/Snackbar/SnackbarContainer/SnackbarContainer.module.scss +2 -2
- package/src/Notifications/Snackbar/SnackbarItem/SnackbarItem.module.scss +4 -4
- package/src/Notifications/Snackbar/SnackbarItem/SnackbarItem.tsx +3 -2
- package/src/Popover/Popover.module.scss +2 -2
- package/src/ProgressBar/ProgressBar.module.scss +11 -9
- package/src/ProgressBar/ProgressBar.test.tsx +21 -0
- package/src/ProgressBar/ProgressBar.tsx +7 -2
- package/src/Skeleton/Skeleton.module.scss +2 -2
- package/src/Tabs/TabButton.tsx +1 -2
- package/src/Tabs/Tabs.module.scss +2 -2
- package/src/Tabs/Tabs.tsx +13 -10
- package/src/Tiles/Tile.module.scss +4 -4
- package/src/Tooltip/Tooltip.module.scss +3 -3
- package/src/Typography/Typography.module.scss +2 -2
- package/src/_BaseStyling_/BaseStyling.tsx +13 -3
- package/src/hooks/useDetermineStatusIcon.test.ts +28 -0
- package/src/hooks/useDetermineStatusIcon.tsx +35 -0
- package/src/hooks/useUploadFile.test.ts +211 -0
- package/src/hooks/useUploadFile.tsx +136 -0
- package/src/index.ts +1 -0
- package/src/mixins.module.scss +24 -5
- package/src/util/helper.test.tsx +156 -1
- package/src/util/helper.tsx +33 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 OneWelcome B.V.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { FileType } from "../Form/FileUpload/FileUpload";
|
|
18
|
+
import { useEffect, useState } from "react";
|
|
19
|
+
import { getValueByPath } from "../util/helper";
|
|
20
|
+
|
|
21
|
+
export interface UploadResponseType {
|
|
22
|
+
fileList: FileType[];
|
|
23
|
+
status: XMLHttpRequest["status"];
|
|
24
|
+
}
|
|
25
|
+
export interface UseUploadFileCallback {
|
|
26
|
+
onComplete?: (response: UploadResponseType) => void;
|
|
27
|
+
onProgress?: Function;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface UploadFileRequestParams {
|
|
31
|
+
url: string;
|
|
32
|
+
headers?: Headers;
|
|
33
|
+
responseErrorPath?: string;
|
|
34
|
+
networkErrorText?: string;
|
|
35
|
+
withCredentials?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const useUploadFile = (
|
|
39
|
+
files: FileType[],
|
|
40
|
+
request: UploadFileRequestParams,
|
|
41
|
+
callbacks?: UseUploadFileCallback
|
|
42
|
+
) => {
|
|
43
|
+
const { url, headers, withCredentials, networkErrorText, responseErrorPath } = request;
|
|
44
|
+
|
|
45
|
+
const { onComplete, onProgress } = callbacks || {};
|
|
46
|
+
|
|
47
|
+
const [uploadingFiles, setUploadingFiles] = useState<FileType[]>([]);
|
|
48
|
+
const [updatedFiles, setUpdatedFiles] = useState<FileType[]>([...files]);
|
|
49
|
+
|
|
50
|
+
const getUpdatedList = (
|
|
51
|
+
fileName: string,
|
|
52
|
+
fileStatus: FileType["status"],
|
|
53
|
+
progress?: number,
|
|
54
|
+
error?: string
|
|
55
|
+
) => {
|
|
56
|
+
return files.map(file => {
|
|
57
|
+
if (file.name === fileName) {
|
|
58
|
+
file.progress = progress;
|
|
59
|
+
file.error = error;
|
|
60
|
+
file.status = fileStatus;
|
|
61
|
+
}
|
|
62
|
+
return { ...file };
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const recordProgress = (e: ProgressEvent<XMLHttpRequestEventTarget>, fileName: string) => {
|
|
67
|
+
const progress = (e.loaded / e.total) * 100;
|
|
68
|
+
const updatedData = getUpdatedList(fileName, "uploading", progress);
|
|
69
|
+
setUpdatedFiles(updatedData);
|
|
70
|
+
onProgress && onProgress(fileName, progress);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const getFileStatus = (
|
|
74
|
+
requestStatus: XMLHttpRequest["status"],
|
|
75
|
+
responseText: XMLHttpRequest["responseText"]
|
|
76
|
+
) => {
|
|
77
|
+
let fileStatus: FileType["status"] = undefined;
|
|
78
|
+
let error = "";
|
|
79
|
+
if (requestStatus >= 200 && requestStatus < 400) {
|
|
80
|
+
fileStatus = "completed";
|
|
81
|
+
} else if (requestStatus === 0) {
|
|
82
|
+
fileStatus = "retry";
|
|
83
|
+
error =
|
|
84
|
+
networkErrorText || "Network error. Check internet connection and retry uploading the file";
|
|
85
|
+
} else if (requestStatus >= 400 && requestStatus < 500) {
|
|
86
|
+
const response = responseText && JSON.parse(JSON.stringify(responseText));
|
|
87
|
+
fileStatus = "error";
|
|
88
|
+
error = responseErrorPath ? getValueByPath(response, responseErrorPath) : "Bad request";
|
|
89
|
+
} else if (requestStatus >= 500) {
|
|
90
|
+
const response = responseText && JSON.parse(JSON.stringify(responseText));
|
|
91
|
+
fileStatus = "error";
|
|
92
|
+
error = responseErrorPath ? getValueByPath(response, responseErrorPath) : "Server Error";
|
|
93
|
+
}
|
|
94
|
+
return { fileStatus, error };
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const handleOnComplete = (xhr: XMLHttpRequest, fileName: string) => {
|
|
98
|
+
const { status, readyState, responseText } = xhr;
|
|
99
|
+
if (readyState === xhr.DONE) {
|
|
100
|
+
const { fileStatus, error } = getFileStatus(status, responseText);
|
|
101
|
+
const updatedList = getUpdatedList(fileName, fileStatus, undefined, error);
|
|
102
|
+
setUpdatedFiles(updatedList);
|
|
103
|
+
const response = { fileList: updatedList, status };
|
|
104
|
+
setUploadingFiles(prevState => prevState.filter(selected => selected.name === fileName));
|
|
105
|
+
onComplete && onComplete(response);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const uploadFile = (file: FileType) => {
|
|
110
|
+
const xhr = new XMLHttpRequest();
|
|
111
|
+
xhr.upload.addEventListener("progress", e => recordProgress(e, file.name));
|
|
112
|
+
xhr.addEventListener("readystatechange", () => handleOnComplete(xhr, file.name));
|
|
113
|
+
headers && headers.forEach((value, key) => xhr.setRequestHeader(key, value));
|
|
114
|
+
withCredentials && (xhr.withCredentials = true);
|
|
115
|
+
xhr.open("POST", url, true);
|
|
116
|
+
const formData = new FormData();
|
|
117
|
+
formData.append("file", file.data as File);
|
|
118
|
+
formData.append("name", file.name);
|
|
119
|
+
xhr.send(formData);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (!url || !files.length) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
files.forEach(file => {
|
|
128
|
+
if (!file.status && !uploadingFiles.find(selected => selected.name === file.name)) {
|
|
129
|
+
setUploadingFiles(prevState => [...prevState, file]);
|
|
130
|
+
uploadFile(file);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}, [url, files]);
|
|
134
|
+
|
|
135
|
+
return { updatedFiles, setUpdatedFiles, uploadingFiles };
|
|
136
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -123,3 +123,4 @@ export { HeaderCell } from "./DataGrid/datagrid.interfaces";
|
|
|
123
123
|
export { DataGrid, Props as DataGridProps } from "./DataGrid/DataGrid";
|
|
124
124
|
export { DataGridRow, Props as DataGridRowProps } from "./DataGrid/DataGridBody/DataGridRow";
|
|
125
125
|
export { DataGridCell, Props as DataGridCellProps } from "./DataGrid/DataGridBody/DataGridCell";
|
|
126
|
+
export { Banner, Props as BannerProps } from "./Notifications/Banner/Banner";
|
package/src/mixins.module.scss
CHANGED
|
@@ -156,17 +156,26 @@
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
@mixin outline
|
|
159
|
+
@mixin outline(
|
|
160
|
+
$color: var(--light-grey-border),
|
|
161
|
+
$style: var(--input-border-style),
|
|
162
|
+
$width: var(--input-border-width),
|
|
163
|
+
$borderRadius: var(--input-border-radius),
|
|
164
|
+
$backgroundColor: ""
|
|
165
|
+
) {
|
|
160
166
|
.outline {
|
|
161
167
|
pointer-events: none;
|
|
162
168
|
position: absolute;
|
|
163
169
|
margin: 0;
|
|
164
170
|
padding: 0;
|
|
165
171
|
inset: 0;
|
|
166
|
-
border-color:
|
|
167
|
-
border-style:
|
|
168
|
-
border-width:
|
|
169
|
-
border-radius:
|
|
172
|
+
border-color: $color;
|
|
173
|
+
border-style: $style;
|
|
174
|
+
border-width: $width;
|
|
175
|
+
border-radius: $borderRadius;
|
|
176
|
+
@if ($backgroundColor != "") {
|
|
177
|
+
background-color: $backgroundColor;
|
|
178
|
+
}
|
|
170
179
|
@include transition(all, 0.2s, ease-in-out);
|
|
171
180
|
}
|
|
172
181
|
}
|
|
@@ -249,3 +258,13 @@
|
|
|
249
258
|
transition-duration: 0.1ms;
|
|
250
259
|
}
|
|
251
260
|
}
|
|
261
|
+
|
|
262
|
+
@mixin width-size($size) {
|
|
263
|
+
.w-#{$size} {
|
|
264
|
+
width: $size * 1%;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
@for $i from 1 through 100 {
|
|
269
|
+
@include width-size($i + 5);
|
|
270
|
+
}
|
package/src/util/helper.test.tsx
CHANGED
|
@@ -16,7 +16,15 @@
|
|
|
16
16
|
|
|
17
17
|
import React, { useCallback, useEffect, useState } from "react";
|
|
18
18
|
import { fireEvent, waitFor } from "@testing-library/dom";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
generateID,
|
|
21
|
+
filterProps,
|
|
22
|
+
debounce,
|
|
23
|
+
throttle,
|
|
24
|
+
areArraysDifferent,
|
|
25
|
+
getValueByPath,
|
|
26
|
+
isEqual
|
|
27
|
+
} from "./helper";
|
|
20
28
|
import { render } from "@testing-library/react";
|
|
21
29
|
|
|
22
30
|
/* Generate an ID of 20 characters with a string woven in */
|
|
@@ -165,3 +173,150 @@ describe("throttling works", () => {
|
|
|
165
173
|
expect(exampleFunction).not.toHaveBeenCalledTimes(10);
|
|
166
174
|
});
|
|
167
175
|
});
|
|
176
|
+
|
|
177
|
+
describe("areArraysDifferent works as expected", () => {
|
|
178
|
+
it("should return true for different arrays", () => {
|
|
179
|
+
const arr1 = [
|
|
180
|
+
{
|
|
181
|
+
name: "test1"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: "test2"
|
|
185
|
+
}
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
const arr2 = [
|
|
189
|
+
{
|
|
190
|
+
name: "test1"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: "test3"
|
|
194
|
+
}
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
const result = areArraysDifferent(arr1, arr2, "name");
|
|
198
|
+
expect(result).toBe(true);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("should return false for arrays with same values", () => {
|
|
202
|
+
const arr1 = [
|
|
203
|
+
{
|
|
204
|
+
name: "test1"
|
|
205
|
+
}
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
const arr2 = [
|
|
209
|
+
{
|
|
210
|
+
name: "test1"
|
|
211
|
+
}
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
const result = areArraysDifferent(arr1, arr2, "name");
|
|
215
|
+
expect(result).toBe(false);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("should return false for falsy values", () => {
|
|
219
|
+
const arr1 = [
|
|
220
|
+
{
|
|
221
|
+
name: "test1"
|
|
222
|
+
}
|
|
223
|
+
];
|
|
224
|
+
|
|
225
|
+
const arr2 = [
|
|
226
|
+
{
|
|
227
|
+
label: "test1"
|
|
228
|
+
}
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
const result = areArraysDifferent(arr1, arr2, "name");
|
|
232
|
+
expect(result).toBe(true);
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe("return correct values from getValueByPath", () => {
|
|
237
|
+
it("should return the correct value form a multi layered object", () => {
|
|
238
|
+
const val = "test";
|
|
239
|
+
const obj = {
|
|
240
|
+
firstNode: {
|
|
241
|
+
secondNode: {
|
|
242
|
+
thirdNode: {
|
|
243
|
+
val
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const result = getValueByPath(obj, "firstNode.secondNode.thirdNode.val");
|
|
250
|
+
expect(result).toBe(val);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
describe("verifies if isEqual returns the correct value", () => {
|
|
255
|
+
it("should return true for equal values objects", () => {
|
|
256
|
+
const obj1 = {
|
|
257
|
+
name1: "test1",
|
|
258
|
+
name2: {
|
|
259
|
+
val: "test2"
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const obj2 = {
|
|
264
|
+
name1: "test1",
|
|
265
|
+
name2: {
|
|
266
|
+
val: "test2"
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const res = isEqual(obj1, obj2);
|
|
271
|
+
expect(res).toBe(true);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it("should return false for unequal values objects", () => {
|
|
275
|
+
const obj1 = {
|
|
276
|
+
name1: "test1",
|
|
277
|
+
name2: {
|
|
278
|
+
val: "test2"
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const obj2 = {
|
|
283
|
+
name1: "test1"
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const res = isEqual(obj1, obj2);
|
|
287
|
+
expect(res).toBe(false);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("should return false for falsy values", () => {
|
|
291
|
+
const obj1 = {
|
|
292
|
+
name1: "test1",
|
|
293
|
+
name2: {
|
|
294
|
+
val: "test2"
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
const obj2 = null;
|
|
298
|
+
|
|
299
|
+
const res = isEqual(obj1, obj2);
|
|
300
|
+
expect(res).toBe(false);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("should return false for different types", () => {
|
|
304
|
+
const obj1 = [
|
|
305
|
+
{
|
|
306
|
+
name1: "test1",
|
|
307
|
+
name2: {
|
|
308
|
+
val: "test2"
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
];
|
|
312
|
+
const obj2 = {
|
|
313
|
+
name1: "test1",
|
|
314
|
+
name2: {
|
|
315
|
+
val: "test2"
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const res = isEqual(obj1, obj2);
|
|
320
|
+
expect(res).toBe(false);
|
|
321
|
+
});
|
|
322
|
+
});
|
package/src/util/helper.tsx
CHANGED
|
@@ -143,3 +143,36 @@ export const throttle = (fn: (...args: unknown[]) => unknown, delay: number) =>
|
|
|
143
143
|
}
|
|
144
144
|
};
|
|
145
145
|
};
|
|
146
|
+
|
|
147
|
+
export const isEqual = (x: any, y: any): boolean => {
|
|
148
|
+
const typesCoincide = x && y && typeof x === "object" && typeof y === "object";
|
|
149
|
+
return typesCoincide
|
|
150
|
+
? Object.keys(x).length === Object.keys(y).length &&
|
|
151
|
+
Object.keys(x).every(key => isEqual(x[key], y[key]))
|
|
152
|
+
: x === y;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export const areArraysDifferent = (
|
|
156
|
+
arr1: Record<string, any>[],
|
|
157
|
+
arr2: Record<string, any>[],
|
|
158
|
+
key: string
|
|
159
|
+
) => {
|
|
160
|
+
if (arr1.length !== arr2.length) {
|
|
161
|
+
return true;
|
|
162
|
+
} else {
|
|
163
|
+
const firstFilteredArray = arr1.filter(arr1Item =>
|
|
164
|
+
arr2.some((arr2Item: { [x: string]: any }) => !isEqual(arr1Item[key], arr2Item[key]))
|
|
165
|
+
);
|
|
166
|
+
const secondFilteredArray = arr2.filter(arr2Item =>
|
|
167
|
+
arr1.some((arr1Item: { [x: string]: any }) => !isEqual(arr1Item[key], arr2Item[key]))
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
return !!firstFilteredArray.length || !!secondFilteredArray.length;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export const getValueByPath = (obj: { [key: string]: any }, path: string): any => {
|
|
175
|
+
return path.split(".").reduce((res, prop) => {
|
|
176
|
+
return res[prop];
|
|
177
|
+
}, obj);
|
|
178
|
+
};
|