@jasperoosthoek/react-toolbox 0.8.1 → 0.9.1
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/change-log.md +330 -312
- package/dist/components/buttons/ConfirmButton.d.ts +2 -2
- package/dist/components/buttons/DeleteConfirmButton.d.ts +2 -2
- package/dist/components/buttons/IconButtons.d.ts +40 -41
- package/dist/components/errors/Errors.d.ts +1 -2
- package/dist/components/forms/FormField.d.ts +22 -0
- package/dist/components/forms/FormFields.d.ts +1 -56
- package/dist/components/forms/FormModal.d.ts +7 -34
- package/dist/components/forms/FormModalProvider.d.ts +25 -15
- package/dist/components/forms/FormProvider.d.ts +66 -0
- package/dist/components/forms/fields/FormBadgesSelection.d.ts +26 -0
- package/dist/components/forms/fields/FormCheckbox.d.ts +7 -0
- package/dist/components/forms/fields/FormDropdown.d.ts +19 -0
- package/dist/components/forms/fields/FormInput.d.ts +17 -0
- package/dist/components/forms/fields/FormSelect.d.ts +12 -0
- package/dist/components/forms/fields/index.d.ts +5 -0
- package/dist/components/indicators/CheckIndicator.d.ts +1 -2
- package/dist/components/indicators/LoadingIndicator.d.ts +4 -4
- package/dist/components/login/LoginPage.d.ts +1 -1
- package/dist/components/tables/DataTable.d.ts +2 -2
- package/dist/components/tables/DragAndDropList.d.ts +2 -2
- package/dist/components/tables/SearchBox.d.ts +2 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -2
- package/dist/index.js.LICENSE.txt +0 -4
- package/dist/localization/LocalizationContext.d.ts +1 -1
- package/dist/utils/hooks.d.ts +1 -1
- package/dist/utils/timeAndDate.d.ts +5 -2
- package/dist/utils/utils.d.ts +3 -3
- package/package.json +10 -11
- package/src/__tests__/buttons.test.tsx +545 -0
- package/src/__tests__/errors.test.tsx +339 -0
- package/src/__tests__/forms.test.tsx +3021 -0
- package/src/__tests__/hooks.test.tsx +413 -0
- package/src/__tests__/indicators.test.tsx +284 -0
- package/src/__tests__/localization.test.tsx +462 -0
- package/src/__tests__/login.test.tsx +417 -0
- package/src/__tests__/setupTests.ts +328 -0
- package/src/__tests__/tables.test.tsx +609 -0
- package/src/__tests__/timeAndDate.test.tsx +308 -0
- package/src/__tests__/utils.test.tsx +422 -0
- package/src/components/forms/FormField.tsx +92 -0
- package/src/components/forms/FormFields.tsx +3 -423
- package/src/components/forms/FormModal.tsx +168 -243
- package/src/components/forms/FormModalProvider.tsx +164 -85
- package/src/components/forms/FormProvider.tsx +218 -0
- package/src/components/forms/fields/FormBadgesSelection.tsx +108 -0
- package/src/components/forms/fields/FormCheckbox.tsx +76 -0
- package/src/components/forms/fields/FormDropdown.tsx +123 -0
- package/src/components/forms/fields/FormInput.tsx +114 -0
- package/src/components/forms/fields/FormSelect.tsx +47 -0
- package/src/components/forms/fields/index.ts +6 -0
- package/src/index.ts +32 -29
- package/src/localization/LocalizationContext.tsx +156 -131
- package/src/localization/localization.ts +131 -131
- package/src/utils/hooks.ts +108 -94
- package/src/utils/timeAndDate.ts +33 -4
- package/src/utils/utils.ts +74 -66
- package/dist/components/forms/CreateEditModal.d.ts +0 -41
- package/dist/components/forms/CreateEditModalProvider.d.ts +0 -41
- package/dist/components/forms/FormFields.test.d.ts +0 -4
- package/dist/login/Login.d.ts +0 -70
- package/src/components/forms/FormFields.test.tsx +0 -107
package/src/utils/hooks.ts
CHANGED
|
@@ -1,95 +1,109 @@
|
|
|
1
|
-
import React, { useRef, useEffect, useState, useCallback } from 'react';
|
|
2
|
-
|
|
3
|
-
// https://stackoverflow.com/questions/53446020/how-to-compare-oldvalues-and-newvalues-on-react-hooks-useeffect
|
|
4
|
-
export const usePrevious = <T>(value: T): T | undefined => {
|
|
5
|
-
// Explicitly set initial value to `undefined`
|
|
6
|
-
const ref = useRef<T | undefined>(undefined);
|
|
7
|
-
|
|
8
|
-
useEffect(() => {
|
|
9
|
-
ref.current = value;
|
|
10
|
-
});
|
|
11
|
-
return ref.current;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
// https://stackoverflow.com/questions/54666401/how-to-use-throttle-or-debounce-with-react-hook
|
|
15
|
-
export const useDebouncedEffect = (effect: () => void, deps: any[], delay: number) => {
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
const handler = setTimeout(() => effect(), delay);
|
|
18
|
-
|
|
19
|
-
return () => clearTimeout(handler);
|
|
20
|
-
}, [...(deps || []), delay
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// https://stackoverflow.com/questions/30626030/can-you-force-a-react-component-to-rerender-without-calling-setstate
|
|
24
|
-
export const useForceUpdate = () => {
|
|
25
|
-
const [, updateState] = useState<any>(null);
|
|
26
|
-
return useCallback(() => updateState({}), []);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const useSetState = <T>(initialState: T): [T, (subState: Partial<T
|
|
30
|
-
const [state, setState] = useState(initialState);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
1
|
+
import React, { useRef, useEffect, useState, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
// https://stackoverflow.com/questions/53446020/how-to-compare-oldvalues-and-newvalues-on-react-hooks-useeffect
|
|
4
|
+
export const usePrevious = <T>(value: T): T | undefined => {
|
|
5
|
+
// Explicitly set initial value to `undefined`
|
|
6
|
+
const ref = useRef<T | undefined>(undefined);
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
ref.current = value;
|
|
10
|
+
});
|
|
11
|
+
return ref.current;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// https://stackoverflow.com/questions/54666401/how-to-use-throttle-or-debounce-with-react-hook
|
|
15
|
+
export const useDebouncedEffect = (effect: () => void, deps: any[], delay: number) => {
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const handler = setTimeout(() => effect(), delay);
|
|
18
|
+
|
|
19
|
+
return () => clearTimeout(handler);
|
|
20
|
+
}, [...(deps || []), delay]);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// https://stackoverflow.com/questions/30626030/can-you-force-a-react-component-to-rerender-without-calling-setstate
|
|
24
|
+
export const useForceUpdate = () => {
|
|
25
|
+
const [, updateState] = useState<any>(null);
|
|
26
|
+
return useCallback(() => updateState({}), []);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const useSetState = <T>(initialState: T): [T, (subState: Partial<T>, callback?: () => void) => void] => {
|
|
30
|
+
const [state, setState] = useState(initialState);
|
|
31
|
+
|
|
32
|
+
const setSubState = useCallback((obj: Partial<T>, callback?: () => void) => {
|
|
33
|
+
setState(prevState => {
|
|
34
|
+
const newState = { ...prevState, ...obj };
|
|
35
|
+
return newState;
|
|
36
|
+
});
|
|
37
|
+
if (callback) {
|
|
38
|
+
// Execute callback in next tick to ensure state is updated
|
|
39
|
+
Promise.resolve().then(callback);
|
|
40
|
+
}
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
43
|
+
return [state, setSubState];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// https://devtrium.com/posts/set-interval-react
|
|
47
|
+
export const useInterval = (func: () => void, value: number) => useEffect(() => {
|
|
48
|
+
if (typeof func !== 'function') {
|
|
49
|
+
throw('First argument of useInterval should be a function');
|
|
50
|
+
} else if(
|
|
51
|
+
typeof value !== 'number'
|
|
52
|
+
|| !isFinite(value)
|
|
53
|
+
|| value <= 0
|
|
54
|
+
) {
|
|
55
|
+
throw('Second argument of useInterval should be a positive number');
|
|
56
|
+
}
|
|
57
|
+
const interval = setInterval(func, value);
|
|
58
|
+
|
|
59
|
+
return () => clearInterval(interval);
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
export const useLocalStorage = <T,>(key: string, initialValue: T): [T, (value: T) => void] => {
|
|
63
|
+
// Get initial value from localStorage or use provided initial value
|
|
64
|
+
const [state, setState] = useState<T>(() => {
|
|
65
|
+
try {
|
|
66
|
+
const item = localStorage.getItem(key);
|
|
67
|
+
if (item === null) {
|
|
68
|
+
localStorage.setItem(key, JSON.stringify(initialValue));
|
|
69
|
+
return initialValue;
|
|
70
|
+
}
|
|
71
|
+
return JSON.parse(item) as T;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error('Error reading from localStorage:', error);
|
|
74
|
+
return initialValue;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
const handleStorageChange = (event: StorageEvent) => {
|
|
80
|
+
if (event.key === key && event.newValue) {
|
|
81
|
+
try {
|
|
82
|
+
setState(JSON.parse(event.newValue) as T);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error('Error parsing localStorage value:', error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
window.addEventListener('storage', handleStorageChange);
|
|
90
|
+
return () => window.removeEventListener('storage', handleStorageChange);
|
|
91
|
+
}, [key]);
|
|
92
|
+
|
|
93
|
+
const setLocalStorage = useCallback((value: T) => {
|
|
94
|
+
try {
|
|
95
|
+
setState(value);
|
|
96
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
97
|
+
// Dispatch storage event for components in the same window
|
|
98
|
+
window.dispatchEvent(new StorageEvent('storage', {
|
|
99
|
+
key,
|
|
100
|
+
newValue: JSON.stringify(value),
|
|
101
|
+
oldValue: localStorage.getItem(key),
|
|
102
|
+
}));
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error('Error writing to localStorage:', error);
|
|
105
|
+
}
|
|
106
|
+
}, [key]);
|
|
107
|
+
|
|
108
|
+
return [state, setLocalStorage];
|
|
95
109
|
};
|
package/src/utils/timeAndDate.ts
CHANGED
|
@@ -1,4 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export const
|
|
1
|
+
import { startOfDay, format, parseISO, isValid } from 'date-fns';
|
|
2
|
+
import { toZonedTime, fromZonedTime } from 'date-fns-tz';
|
|
3
|
+
|
|
4
|
+
export const getTimestamp = () => Math.round(new Date().getTime() / 1000);
|
|
5
|
+
|
|
6
|
+
export const getToday = () => {
|
|
7
|
+
const now = new Date();
|
|
8
|
+
const utcDate = toZonedTime(now, 'UTC');
|
|
9
|
+
return startOfDay(utcDate);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// Common date formatting utilities
|
|
13
|
+
export const formatDate = (date: Date | string, pattern: string = 'yyyy-MM-dd') => {
|
|
14
|
+
const dateObj = typeof date === 'string' ? parseISO(date) : date;
|
|
15
|
+
return isValid(dateObj) ? format(dateObj, pattern) : '';
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const formatDateTime = (date: Date | string, pattern: string = 'yyyy-MM-dd HH:mm') => {
|
|
19
|
+
const dateObj = typeof date === 'string' ? parseISO(date) : date;
|
|
20
|
+
return isValid(dateObj) ? format(dateObj, pattern) : '';
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Convert local date to UTC
|
|
24
|
+
export const toUtc = (date: Date | string, timezone?: string) => {
|
|
25
|
+
const dateObj = typeof date === 'string' ? parseISO(date) : date;
|
|
26
|
+
return timezone ? fromZonedTime(dateObj, timezone) : dateObj;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Convert UTC date to local timezone
|
|
30
|
+
export const fromUtc = (date: Date | string, timezone: string) => {
|
|
31
|
+
const dateObj = typeof date === 'string' ? parseISO(date) : date;
|
|
32
|
+
return toZonedTime(dateObj, timezone);
|
|
33
|
+
};
|
package/src/utils/utils.ts
CHANGED
|
@@ -1,66 +1,74 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
value ===
|
|
5
|
-
|| value ===
|
|
6
|
-
|| value ===
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
return `${
|
|
31
|
-
} else
|
|
32
|
-
//
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export const
|
|
41
|
-
|
|
42
|
-
export
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
1
|
+
export const isEmpty = (value: unknown) =>
|
|
2
|
+
value === undefined
|
|
3
|
+
|| value === null
|
|
4
|
+
|| value === false
|
|
5
|
+
|| (typeof value === 'object' && Object.keys(value).length === 0)
|
|
6
|
+
|| (typeof value === 'string' && value.trim().length === 0);
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export const snakeToCamelCase = (str: string) => str.replace(
|
|
10
|
+
/([-_])(.)/g,
|
|
11
|
+
(match, separator, char) => char.toUpperCase()
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export const camelToSnakeCase = (str: string) => {
|
|
15
|
+
return str
|
|
16
|
+
.replace(/([a-z])([A-Z])/g, '$1_$2') // Insert underscore between lowercase and uppercase
|
|
17
|
+
.replace(/([a-zA-Z])([0-9])/g, '$1_$2') // Insert underscore between letter and number
|
|
18
|
+
.replace(/([0-9])([a-zA-Z])/g, '$1_$2') // Insert underscore between number and letter
|
|
19
|
+
.toUpperCase();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const pluralToSingle = (str: string) => {
|
|
23
|
+
if (str.slice(-1) !== 's' && str.slice(-1) !== 'S') {
|
|
24
|
+
// This string is not plural: keep it unaltered
|
|
25
|
+
return str;
|
|
26
|
+
} else if (str.slice(-3).toLowerCase() === 'ies') {
|
|
27
|
+
// Handle special case of categories (case insensitive)
|
|
28
|
+
const prefix = str.slice(0, -3);
|
|
29
|
+
const lastChar = str.slice(-3, -2); // Get the character before 'ies'
|
|
30
|
+
return `${prefix}${lastChar === lastChar.toUpperCase() ? 'Y' : 'y'}`;
|
|
31
|
+
} else {
|
|
32
|
+
// Standard plural
|
|
33
|
+
return str.slice(0, -1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const arrayToObject = <T extends any[]>(array: T, byKey: string) => Object.fromEntries(array.map(obj => [obj[byKey], obj]));
|
|
38
|
+
|
|
39
|
+
export const roundFixed = (str: string | number, decimals?: number) => parseFloat(`${str}`).toFixed(decimals || 0);
|
|
40
|
+
export const round = (str: string | number, decimals?: number) => parseFloat(parseFloat(`${str}`).toFixed(decimals || 0));
|
|
41
|
+
|
|
42
|
+
export type DownloadFileOptions = {
|
|
43
|
+
headers?: Record<string, string>;
|
|
44
|
+
fetchFn?: typeof fetch;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const downloadFile = async (url: string, filename: string, options: DownloadFileOptions = {}) => {
|
|
48
|
+
try {
|
|
49
|
+
const fetchFn = options.fetchFn || fetch;
|
|
50
|
+
const response = await fetchFn(url, {
|
|
51
|
+
method: 'GET',
|
|
52
|
+
headers: options.headers || {},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const blob = await response.blob();
|
|
60
|
+
const downloadUrl = window.URL.createObjectURL(blob);
|
|
61
|
+
const link = document.createElement('a');
|
|
62
|
+
link.href = downloadUrl;
|
|
63
|
+
link.setAttribute('download', filename);
|
|
64
|
+
document.body.appendChild(link);
|
|
65
|
+
link.click();
|
|
66
|
+
|
|
67
|
+
// Cleanup
|
|
68
|
+
document.body.removeChild(link);
|
|
69
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error('Download failed:', error);
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import React, { ReactElement } from 'react';
|
|
2
|
-
import { FormComponentProps, FormSelectProps, FormOnChange, FormValue } from './FormFields';
|
|
3
|
-
export type FormField = {
|
|
4
|
-
initialValue?: any;
|
|
5
|
-
type?: 'string' | 'number';
|
|
6
|
-
required?: boolean;
|
|
7
|
-
formProps?: any;
|
|
8
|
-
component?: (props: FormComponentProps | FormSelectProps) => ReactElement;
|
|
9
|
-
onChange?: FormOnChange;
|
|
10
|
-
label?: ReactElement | string;
|
|
11
|
-
};
|
|
12
|
-
export type IncludeData<T> = {
|
|
13
|
-
[key in Exclude<string, keyof T>]: any;
|
|
14
|
-
};
|
|
15
|
-
export type InitialState<T> = Partial<{
|
|
16
|
-
[key in keyof T]: FormValue;
|
|
17
|
-
}>;
|
|
18
|
-
export type FormFields = {
|
|
19
|
-
[key: string]: FormField;
|
|
20
|
-
};
|
|
21
|
-
export type OnSave<T, K> = (state: ({
|
|
22
|
-
[key in keyof T]: FormValue;
|
|
23
|
-
}), callback: () => void) => void;
|
|
24
|
-
export type Validate = (state: any) => any;
|
|
25
|
-
export type ModalTitle = ReactElement | string;
|
|
26
|
-
export type Width = 25 | 50 | 75 | 100;
|
|
27
|
-
export type CreateEditModalProps<T extends FormFields, K extends IncludeData<T>> = {
|
|
28
|
-
initialState: InitialState<T> | K;
|
|
29
|
-
includeData?: K;
|
|
30
|
-
formFields: T;
|
|
31
|
-
show?: boolean;
|
|
32
|
-
onSave: OnSave<T, K>;
|
|
33
|
-
onHide: () => void;
|
|
34
|
-
validate?: Validate;
|
|
35
|
-
modalTitle?: ModalTitle;
|
|
36
|
-
loading?: boolean;
|
|
37
|
-
dialogClassName?: string;
|
|
38
|
-
width?: Width;
|
|
39
|
-
};
|
|
40
|
-
export declare const CreateEditModal: <T extends FormFields, K extends IncludeData<T>>({ initialState, formFields, includeData, show, onSave, onHide, validate, modalTitle, loading, dialogClassName, width, ...restProps }: CreateEditModalProps<T, K>) => React.JSX.Element;
|
|
41
|
-
export declare const DisabledFormField: ({ value }: any) => React.JSX.Element;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import React, { ReactNode } from 'react';
|
|
2
|
-
import { FormFields, IncludeData, InitialState, OnSave, Validate, ModalTitle, Width } from './CreateEditModal';
|
|
3
|
-
import { FormValue } from './FormFields';
|
|
4
|
-
import { ButtonProps } from '../buttons/IconButtons';
|
|
5
|
-
export type ShowCreateModal = (show?: boolean) => void;
|
|
6
|
-
export type ShowEditModal<T, K> = (state: {
|
|
7
|
-
[key in keyof T]: FormValue;
|
|
8
|
-
} & K) => void;
|
|
9
|
-
export type ShowCreateModalButton = ButtonProps;
|
|
10
|
-
export declare const ShowCreateModalButton: ({ onClick, ...props }: ButtonProps) => React.JSX.Element;
|
|
11
|
-
export interface ShowEditModalButtonProps<T, K> extends ButtonProps {
|
|
12
|
-
state: {
|
|
13
|
-
[key in keyof T]: FormValue;
|
|
14
|
-
} & K;
|
|
15
|
-
}
|
|
16
|
-
export declare const ShowEditModalButton: ({ state, onClick, ...props }: ShowEditModalButtonProps<T, K>) => React.JSX.Element;
|
|
17
|
-
type CreateEditModalContextType<T, K> = {
|
|
18
|
-
showCreateModal: ShowCreateModal;
|
|
19
|
-
showEditModal: ShowEditModal<T, K>;
|
|
20
|
-
};
|
|
21
|
-
type T = any;
|
|
22
|
-
type K = any;
|
|
23
|
-
export declare const CreateEditModalContext: React.Context<CreateEditModalContextType<any, any>>;
|
|
24
|
-
export declare const useCreateEditModal: () => CreateEditModalContextType<any, any>;
|
|
25
|
-
export type CreateEditModalProviderProps<T extends FormFields, K extends IncludeData<T>> = {
|
|
26
|
-
initialState: InitialState<T> | K;
|
|
27
|
-
includeData?: K;
|
|
28
|
-
formFields: T;
|
|
29
|
-
onSave?: OnSave<T, K>;
|
|
30
|
-
onCreate?: OnSave<T, K>;
|
|
31
|
-
onUpdate?: OnSave<T, K>;
|
|
32
|
-
validate?: Validate;
|
|
33
|
-
createModalTitle?: ModalTitle;
|
|
34
|
-
editModalTitle?: ModalTitle;
|
|
35
|
-
loading?: boolean;
|
|
36
|
-
dialogClassName?: string;
|
|
37
|
-
width?: Width;
|
|
38
|
-
children: ReactNode;
|
|
39
|
-
};
|
|
40
|
-
export declare const CreateEditModalProvider: React.FC<CreateEditModalProviderProps<T, K>>;
|
|
41
|
-
export {};
|
package/dist/login/Login.d.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import React, { ReactElement } from 'react';
|
|
2
|
-
import { ThunkAction, ThunkDispatch } from 'redux-thunk';
|
|
3
|
-
import axios, { AxiosInstance } from 'axios';
|
|
4
|
-
export declare const LOGIN_SET_TOKEN = "LOGIN_SET_TOKEN";
|
|
5
|
-
export declare const LOGIN_SET_CURRENT_USER = "LOGIN_SET_CURRENT_USER";
|
|
6
|
-
export declare const LOGIN_UNSET_CURRENT_USER = "LOGIN_UNSET_CURRENT_USER";
|
|
7
|
-
export type LoginActions = {
|
|
8
|
-
type: 'LOGIN_SET_TOKEN';
|
|
9
|
-
payload: string;
|
|
10
|
-
} | {
|
|
11
|
-
type: 'LOGIN_SET_CURRENT_USER';
|
|
12
|
-
payload: any;
|
|
13
|
-
} | {
|
|
14
|
-
type: 'LOGIN_UNSET_CURRENT_USER';
|
|
15
|
-
};
|
|
16
|
-
export type AuthState = {
|
|
17
|
-
isAuthenticated: boolean;
|
|
18
|
-
user: any | null;
|
|
19
|
-
token: string;
|
|
20
|
-
};
|
|
21
|
-
type Action = {
|
|
22
|
-
type: string;
|
|
23
|
-
[key: string]: any;
|
|
24
|
-
};
|
|
25
|
-
export type LoginFactoryProps = {
|
|
26
|
-
authenticatedComponent: (props: any) => ReactElement;
|
|
27
|
-
passwordResetUrl: string;
|
|
28
|
-
axios: typeof axios | AxiosInstance;
|
|
29
|
-
onError: (error: any) => void;
|
|
30
|
-
onLogout?: () => void;
|
|
31
|
-
loginUrl: string;
|
|
32
|
-
getUserUrl: string;
|
|
33
|
-
logoutUrl: string;
|
|
34
|
-
localStoragePrefix: string;
|
|
35
|
-
};
|
|
36
|
-
export type LoginProps = {
|
|
37
|
-
label?: string | ReactElement;
|
|
38
|
-
};
|
|
39
|
-
export declare const loginFactory: ({ authenticatedComponent, passwordResetUrl, axios, onError, onLogout, loginUrl, getUserUrl, logoutUrl, localStoragePrefix, }: LoginFactoryProps) => {
|
|
40
|
-
Login: ({ label }: LoginProps) => React.JSX.Element;
|
|
41
|
-
useLogin: () => {
|
|
42
|
-
login: (userData: any, callback?: () => void) => any;
|
|
43
|
-
getCurrentUser: (args_0?: {
|
|
44
|
-
callback?: (userData: any) => void;
|
|
45
|
-
}) => any;
|
|
46
|
-
setCurrentUser: (user: any) => any;
|
|
47
|
-
setToken: (token: string) => any;
|
|
48
|
-
unsetCurrentUser: () => any;
|
|
49
|
-
logout: () => any;
|
|
50
|
-
};
|
|
51
|
-
login: (userData: any, callback?: () => void) => ThunkAction<Promise<void>, any, undefined, LoginActions>;
|
|
52
|
-
getCurrentUser: ({ callback }?: {
|
|
53
|
-
callback?: (userData: any) => void;
|
|
54
|
-
}) => (dispatch: ThunkDispatch<any, undefined, any>) => Promise<void>;
|
|
55
|
-
setCurrentUser: (user: any) => (dispatch: ThunkDispatch<any, undefined, any>) => void;
|
|
56
|
-
setToken: (token: string) => (dispatch: ThunkDispatch<any, undefined, any>) => void;
|
|
57
|
-
unsetCurrentUser: () => (dispatch: ThunkDispatch<any, undefined, any>) => void;
|
|
58
|
-
logout: () => (dispatch: ThunkDispatch<any, undefined, any>) => Promise<void>;
|
|
59
|
-
authReducer: {
|
|
60
|
-
auth: (state: AuthState, action: Action) => {
|
|
61
|
-
isAuthenticated: boolean;
|
|
62
|
-
token: any;
|
|
63
|
-
user: any | null;
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
useAuth: () => any;
|
|
67
|
-
storeState: (state: any, action: Action) => void;
|
|
68
|
-
retrieveState: () => any;
|
|
69
|
-
};
|
|
70
|
-
export {};
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @jest-environment jsdom
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import React from 'react';
|
|
6
|
-
import { render, fireEvent } from '@testing-library/react';
|
|
7
|
-
import '@testing-library/jest-dom/extend-expect';
|
|
8
|
-
import { FormInput, FormCheckbox, FormSelect, FormDropdown, FormBadgesSelection } from './FormFields';
|
|
9
|
-
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
jest.clearAllMocks();
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
const mockFields = {
|
|
15
|
-
initialState: {},
|
|
16
|
-
initialValue: 'myval',
|
|
17
|
-
state: {},
|
|
18
|
-
setState: (obj: any) => {},
|
|
19
|
-
keyName: 'test123',
|
|
20
|
-
pristine: true,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
test('FormInput component handles input correctly', () => {
|
|
24
|
-
const mockOnChange = jest.fn();
|
|
25
|
-
const { getByLabelText } = render(
|
|
26
|
-
<FormInput
|
|
27
|
-
{...mockFields}
|
|
28
|
-
label={<>test</>}
|
|
29
|
-
onChange={mockOnChange}
|
|
30
|
-
/>
|
|
31
|
-
);
|
|
32
|
-
const input = getByLabelText('test') as HTMLInputElement;
|
|
33
|
-
|
|
34
|
-
fireEvent.change(input, { target: { value: 'new value' } });
|
|
35
|
-
expect(mockOnChange).toBeCalledWith('new value');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('FormCheckbox component handles input correctly', () => {
|
|
39
|
-
const mockOnChange = jest.fn();
|
|
40
|
-
const { getByRole } = render(
|
|
41
|
-
<FormCheckbox
|
|
42
|
-
{...mockFields}
|
|
43
|
-
label={<>test</>}
|
|
44
|
-
onChange={mockOnChange}
|
|
45
|
-
/>
|
|
46
|
-
);
|
|
47
|
-
const checkbox = getByRole('checkbox') as HTMLInputElement;
|
|
48
|
-
|
|
49
|
-
fireEvent.click(checkbox);
|
|
50
|
-
expect(mockOnChange).toBeCalledWith(true);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('FormSelect component handles input correctly', () => {
|
|
54
|
-
const mockOnChange = jest.fn();
|
|
55
|
-
const list = [
|
|
56
|
-
{
|
|
57
|
-
id: '1',
|
|
58
|
-
name: 'item1',
|
|
59
|
-
children: 'Item 1',
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
id: '2',
|
|
63
|
-
name: 'item2',
|
|
64
|
-
children: 'Item 2',
|
|
65
|
-
},
|
|
66
|
-
];
|
|
67
|
-
const { getByText, getByRole } = render(
|
|
68
|
-
<FormSelect
|
|
69
|
-
{...mockFields}
|
|
70
|
-
// @ts-ignore
|
|
71
|
-
list={list}
|
|
72
|
-
label={<>test</>}
|
|
73
|
-
onChange={mockOnChange}
|
|
74
|
-
/>
|
|
75
|
-
);
|
|
76
|
-
const select = getByRole('listbox') as HTMLSelectElement;
|
|
77
|
-
|
|
78
|
-
fireEvent.change(select, { target: { value: '2' } });
|
|
79
|
-
|
|
80
|
-
// Asserting the onChange callback was not called by the onChange event of the select
|
|
81
|
-
expect(mockOnChange).not.toBeCalled();
|
|
82
|
-
const option = getByText('Item 2') as HTMLOptionElement;
|
|
83
|
-
|
|
84
|
-
// Asserting the onChange callback is called by the onClick event of the option
|
|
85
|
-
fireEvent.click(option);//, { target: { value: '2' } });
|
|
86
|
-
expect(mockOnChange).toBeCalledWith('2');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// test('FormDropdown component handles input correctly', () => {
|
|
90
|
-
// const mockOnChange = jest.fn();
|
|
91
|
-
// const list = [{ id: '1', name: 'item1' }, { id: '2', name: 'item2' }];
|
|
92
|
-
// const { getByText } = render(<FormDropdown list={list} onChange={mockOnChange} />);
|
|
93
|
-
// const item = getByText('item1') as HTMLSelectElement;
|
|
94
|
-
|
|
95
|
-
// fireEvent.click(item);
|
|
96
|
-
// expect(mockOnChange).toBeCalledWith('1');
|
|
97
|
-
// });
|
|
98
|
-
|
|
99
|
-
// test('FormBadgesSelection component handles input correctly', () => {
|
|
100
|
-
// const mockOnChange = jest.fn();
|
|
101
|
-
// const list = [{ id: '1', name: 'item1' }, { id: '2', name: 'item2' }];
|
|
102
|
-
// const { getByText } = render(<FormBadgesSelection list={list} onChange={mockOnChange} />);
|
|
103
|
-
// const item = getByText('item1') as HTMLSelectElement;
|
|
104
|
-
|
|
105
|
-
// fireEvent.click(item);
|
|
106
|
-
// expect(mockOnChange).toBeCalledWith('1');
|
|
107
|
-
// });
|