@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.
Files changed (63) hide show
  1. package/change-log.md +330 -312
  2. package/dist/components/buttons/ConfirmButton.d.ts +2 -2
  3. package/dist/components/buttons/DeleteConfirmButton.d.ts +2 -2
  4. package/dist/components/buttons/IconButtons.d.ts +40 -41
  5. package/dist/components/errors/Errors.d.ts +1 -2
  6. package/dist/components/forms/FormField.d.ts +22 -0
  7. package/dist/components/forms/FormFields.d.ts +1 -56
  8. package/dist/components/forms/FormModal.d.ts +7 -34
  9. package/dist/components/forms/FormModalProvider.d.ts +25 -15
  10. package/dist/components/forms/FormProvider.d.ts +66 -0
  11. package/dist/components/forms/fields/FormBadgesSelection.d.ts +26 -0
  12. package/dist/components/forms/fields/FormCheckbox.d.ts +7 -0
  13. package/dist/components/forms/fields/FormDropdown.d.ts +19 -0
  14. package/dist/components/forms/fields/FormInput.d.ts +17 -0
  15. package/dist/components/forms/fields/FormSelect.d.ts +12 -0
  16. package/dist/components/forms/fields/index.d.ts +5 -0
  17. package/dist/components/indicators/CheckIndicator.d.ts +1 -2
  18. package/dist/components/indicators/LoadingIndicator.d.ts +4 -4
  19. package/dist/components/login/LoginPage.d.ts +1 -1
  20. package/dist/components/tables/DataTable.d.ts +2 -2
  21. package/dist/components/tables/DragAndDropList.d.ts +2 -2
  22. package/dist/components/tables/SearchBox.d.ts +2 -2
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.js +2 -2
  25. package/dist/index.js.LICENSE.txt +0 -4
  26. package/dist/localization/LocalizationContext.d.ts +1 -1
  27. package/dist/utils/hooks.d.ts +1 -1
  28. package/dist/utils/timeAndDate.d.ts +5 -2
  29. package/dist/utils/utils.d.ts +3 -3
  30. package/package.json +10 -11
  31. package/src/__tests__/buttons.test.tsx +545 -0
  32. package/src/__tests__/errors.test.tsx +339 -0
  33. package/src/__tests__/forms.test.tsx +3021 -0
  34. package/src/__tests__/hooks.test.tsx +413 -0
  35. package/src/__tests__/indicators.test.tsx +284 -0
  36. package/src/__tests__/localization.test.tsx +462 -0
  37. package/src/__tests__/login.test.tsx +417 -0
  38. package/src/__tests__/setupTests.ts +328 -0
  39. package/src/__tests__/tables.test.tsx +609 -0
  40. package/src/__tests__/timeAndDate.test.tsx +308 -0
  41. package/src/__tests__/utils.test.tsx +422 -0
  42. package/src/components/forms/FormField.tsx +92 -0
  43. package/src/components/forms/FormFields.tsx +3 -423
  44. package/src/components/forms/FormModal.tsx +168 -243
  45. package/src/components/forms/FormModalProvider.tsx +164 -85
  46. package/src/components/forms/FormProvider.tsx +218 -0
  47. package/src/components/forms/fields/FormBadgesSelection.tsx +108 -0
  48. package/src/components/forms/fields/FormCheckbox.tsx +76 -0
  49. package/src/components/forms/fields/FormDropdown.tsx +123 -0
  50. package/src/components/forms/fields/FormInput.tsx +114 -0
  51. package/src/components/forms/fields/FormSelect.tsx +47 -0
  52. package/src/components/forms/fields/index.ts +6 -0
  53. package/src/index.ts +32 -29
  54. package/src/localization/LocalizationContext.tsx +156 -131
  55. package/src/localization/localization.ts +131 -131
  56. package/src/utils/hooks.ts +108 -94
  57. package/src/utils/timeAndDate.ts +33 -4
  58. package/src/utils/utils.ts +74 -66
  59. package/dist/components/forms/CreateEditModal.d.ts +0 -41
  60. package/dist/components/forms/CreateEditModalProvider.d.ts +0 -41
  61. package/dist/components/forms/FormFields.test.d.ts +0 -4
  62. package/dist/login/Login.d.ts +0 -70
  63. package/src/components/forms/FormFields.test.tsx +0 -107
@@ -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, effect]);
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>) => void] => {
30
- const [state, setState] = useState(initialState);
31
- const [callback, setCallback] = useState<() => void | undefined>();
32
- useEffect(() => {
33
- if (typeof callback === 'function') callback();
34
- }, [callback]);
35
-
36
- const setSubState = (obj: Partial<T>, callback?: () => void) => {
37
- setState({ ...state, ...obj });
38
- if (callback) setCallback(callback);
39
- }
40
- return [state, setSubState];
41
- }
42
-
43
- // https://devtrium.com/posts/set-interval-react
44
- export const useInterval = (func: () => void, value: number) => useEffect(() => {
45
- if (typeof func !== 'function') {
46
- throw('First argument of useInterval should be a function');
47
- } else if(
48
- typeof value !== 'number'
49
- || !isFinite(value)
50
- || value <= 0
51
- ) {
52
- throw('Second argument of useInterval should be a positive number');
53
- }
54
- const interval = setInterval(func, value);
55
-
56
- return () => clearInterval(interval);
57
- }, []);
58
-
59
- export const useLocalStorage = <T,>(key: string, initialValue: T): [T, (value: T) => void] => {
60
- const initialLocalStorageValue = localStorage.getItem(key);
61
-
62
- if (initialLocalStorageValue === null) {
63
- localStorage.setItem(key, JSON.stringify(initialValue));
64
- }
65
-
66
- const [state, setState] = useState<T>(
67
- initialLocalStorageValue
68
- ? JSON.parse(initialLocalStorageValue) as T
69
- : initialValue
70
- );
71
-
72
- useEffect(() => {
73
- const handleStorageChange = (event: StorageEvent) => {
74
- if (event.key === key && event.newValue) {
75
- setState(JSON.parse(event.newValue) as T);
76
- }
77
- };
78
-
79
- // Manually dispatch an event to update components in the same document
80
- window.addEventListener('storage', handleStorageChange);
81
- return () => window.removeEventListener('storage', handleStorageChange);
82
- }, [key]);
83
-
84
- const setLocalStorage = (value: T) => {
85
- setState(value);
86
- localStorage.setItem(key, JSON.stringify(value));
87
- window.dispatchEvent(new StorageEvent('storage', {
88
- key,
89
- newValue: JSON.stringify(value),
90
- oldValue: localStorage.getItem(key),
91
- }));
92
- };
93
-
94
- return [state, setLocalStorage];
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
  };
@@ -1,4 +1,33 @@
1
- import moment from 'moment';
2
-
3
- export const getTimestamp = () => Math.round(new Date().getTime()/1000);
4
- export const getToday = () => moment().utc().startOf('day');
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
+ };
@@ -1,66 +1,74 @@
1
- import axios, { AxiosInstance } from 'axios';
2
-
3
- export const isEmpty = (value: unknown) =>
4
- value === undefined
5
- || value === null
6
- || value === false
7
- || (typeof value === 'object' && Object.keys(value).length === 0)
8
- || (typeof value === 'string' && value.trim().length === 0);
9
-
10
-
11
- export const snakeToCamelCase = (str: string) => str.replace(
12
- /([-_][a-z])/g,
13
- (group) => group
14
- .replace('-', '')
15
- .replace('_', '')
16
- );
17
-
18
- export const camelToSnakeCase = (str: string) => (str
19
- .split(/(?=[A-Z])/)
20
- .map(x => x.toUpperCase())
21
- .join('_')
22
- );
23
-
24
- export const pluralToSingle = (str: string) => {
25
- if (str.slice(-1) !== 's') {
26
- // This string is not plural: keep it unaltered
27
- return str;
28
- } else if (str.slice(-3) === 'ies') {
29
- // Handle special case of categories
30
- return `${str.slice(0, -3)}y`;
31
- } else if (str.slice(-3) === 'IES') {
32
- // Same but in upper case
33
- return `${str.slice(0, -3)}Y`;
34
- } else {
35
- // Standard plural
36
- return str.slice(0, -1);
37
- }
38
- }
39
-
40
- export const arrayToObject = <T extends any[]>(array: T, byKey: string) => Object.fromEntries(array.map(obj => [obj[byKey], obj]));
41
-
42
- export const roundFixed = (str: string | number, decimals?: number) => parseFloat(`${str}`).toFixed(decimals || 0);
43
- export const round = (str: string | number, decimals?: number) => parseFloat(parseFloat(`${str}`).toFixed(decimals || 0));
44
-
45
- export type DownloadFileOptions = {
46
- axios: AxiosInstance;
47
- }
48
- export const downloadFile = (url: string, filename: string, options: DownloadFileOptions) => (
49
- // https://gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743
50
-
51
- (options.axios || axios.create())({
52
- url,
53
- method: 'GET',
54
- responseType: 'blob',
55
- }).then((response) => {
56
- const url = window.URL.createObjectURL(new Blob([response.data]));
57
- const link = document.createElement('a');
58
- link.href = url;
59
- link.setAttribute(
60
- 'download',
61
- filename,
62
- );
63
- document.body.appendChild(link);
64
- link.click();
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 {};
@@ -1,4 +0,0 @@
1
- /**
2
- * @jest-environment jsdom
3
- */
4
- import '@testing-library/jest-dom/extend-expect';
@@ -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
- // });