@etsoo/react 1.3.52 → 1.3.56
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/lib/app/ReactApp.js +17 -10
- package/lib/mu/pages/CommonPage.js +3 -24
- package/lib/mu/pages/CommonPageProps.d.ts +4 -0
- package/lib/states/IState.d.ts +8 -1
- package/lib/states/UserState.d.ts +1 -0
- package/lib/states/UserState.js +18 -1
- package/package.json +4 -4
- package/src/app/ReactApp.ts +18 -12
- package/src/mu/pages/CommonPage.tsx +8 -30
- package/src/mu/pages/CommonPageProps.ts +5 -0
- package/src/states/IState.ts +9 -1
- package/src/states/UserState.ts +23 -1
package/lib/app/ReactApp.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { CoreApp, createClient } from '@etsoo/appscript';
|
|
2
|
-
import { Utils } from '@etsoo/shared';
|
|
3
2
|
import React from 'react';
|
|
4
3
|
import { NotifierMU } from '../mu/NotifierMU';
|
|
5
4
|
import { ProgressCount } from '../mu/ProgressCount';
|
|
@@ -19,16 +18,29 @@ let globalApp;
|
|
|
19
18
|
*/
|
|
20
19
|
export function ReactAppStateDetector(props) {
|
|
21
20
|
// Destruct
|
|
22
|
-
const { update } = props;
|
|
21
|
+
const { targetFields, update } = props;
|
|
23
22
|
// Context
|
|
24
23
|
const { state } = globalApp == null
|
|
25
24
|
? { state: {} }
|
|
26
25
|
: React.useContext(globalApp.userState.context);
|
|
26
|
+
// Match fields
|
|
27
|
+
const changedFields = state.lastChangedFields;
|
|
28
|
+
let matchedFields;
|
|
29
|
+
if (targetFields == null || changedFields == null) {
|
|
30
|
+
matchedFields = changedFields;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
matchedFields = [];
|
|
34
|
+
targetFields.forEach((targetField) => {
|
|
35
|
+
if (changedFields.includes(targetField))
|
|
36
|
+
matchedFields === null || matchedFields === void 0 ? void 0 : matchedFields.push(targetField);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
27
39
|
// Ready
|
|
28
40
|
React.useEffect(() => {
|
|
29
41
|
// Callback
|
|
30
|
-
update(state.authorized);
|
|
31
|
-
}, [state.authorized]);
|
|
42
|
+
update(state.authorized, matchedFields);
|
|
43
|
+
}, [state.authorized, matchedFields]);
|
|
32
44
|
// return
|
|
33
45
|
return React.createElement(React.Fragment);
|
|
34
46
|
}
|
|
@@ -198,15 +210,10 @@ export class ReactApp extends CoreApp {
|
|
|
198
210
|
* @param keep Keep in local storage or not
|
|
199
211
|
*/
|
|
200
212
|
userLogin(user, refreshToken, keep) {
|
|
201
|
-
// Changed
|
|
202
|
-
const dataChanged = !this.authorized ||
|
|
203
|
-
this.userData == null ||
|
|
204
|
-
!Utils.objectEqual(this.userData, user, ['seconds', 'token']);
|
|
205
213
|
// Super call, set token
|
|
206
214
|
super.userLogin(user, refreshToken, keep);
|
|
207
215
|
// Dispatch action
|
|
208
|
-
|
|
209
|
-
if (this.userStateDispatch != null && dataChanged)
|
|
216
|
+
if (this.userStateDispatch != null)
|
|
210
217
|
this.userStateDispatch({
|
|
211
218
|
type: UserActionType.Login,
|
|
212
219
|
user
|
|
@@ -22,23 +22,18 @@ export const CommonPageScrollContainer = global;
|
|
|
22
22
|
*/
|
|
23
23
|
export function CommonPage(props) {
|
|
24
24
|
// Destruct
|
|
25
|
-
const { children, disableGutters = true, fabButtons, fabColumnDirection, fabPaddingAdjust = 1.5, fabSize = 'small', maxWidth = false, moreActions, onRefresh, onUpdate, onUpdateAll, paddings = MUGlobal.pagePaddings, scrollContainer, pullContainer, sx = {}, ...rest } = props;
|
|
25
|
+
const { children, disableGutters = true, fabButtons, fabColumnDirection, fabPaddingAdjust = 1.5, fabSize = 'small', maxWidth = false, moreActions, onRefresh, onUpdate, onUpdateAll, paddings = MUGlobal.pagePaddings, scrollContainer, targetFields, pullContainer, sx = {}, ...rest } = props;
|
|
26
26
|
// Merge style
|
|
27
27
|
Object.assign(sx, {
|
|
28
28
|
padding: paddings
|
|
29
29
|
});
|
|
30
|
-
const [state] = React.useState({});
|
|
31
30
|
// Fab padding
|
|
32
31
|
const fabPadding = MUGlobal.increase(MUGlobal.pagePaddings, fabPaddingAdjust);
|
|
33
32
|
// Labels
|
|
34
33
|
const labels = Labels.CommonPage;
|
|
35
34
|
// Update
|
|
36
35
|
const update = onUpdateAll
|
|
37
|
-
?
|
|
38
|
-
state.loading = true;
|
|
39
|
-
await onUpdateAll(authorized);
|
|
40
|
-
state.firstLoaded = true;
|
|
41
|
-
}
|
|
36
|
+
? onUpdateAll
|
|
42
37
|
: onUpdate
|
|
43
38
|
? (authorized) => {
|
|
44
39
|
if (authorized == null || authorized)
|
|
@@ -50,25 +45,9 @@ export function CommonPage(props) {
|
|
|
50
45
|
onRefresh();
|
|
51
46
|
}
|
|
52
47
|
: undefined;
|
|
53
|
-
React.useEffect(() => {
|
|
54
|
-
return () => {
|
|
55
|
-
state.loading = false;
|
|
56
|
-
state.firstLoaded = false;
|
|
57
|
-
};
|
|
58
|
-
}, []);
|
|
59
|
-
React.useEffect(() => {
|
|
60
|
-
if (state.loading) {
|
|
61
|
-
state.loading = false;
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
// onUpdateAll support to load after page loaded
|
|
65
|
-
if (onUpdateAll != null && state.firstLoaded) {
|
|
66
|
-
onUpdateAll();
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
48
|
// Return the UI
|
|
70
49
|
return (React.createElement(React.Fragment, null,
|
|
71
|
-
update && React.createElement(ReactAppStateDetector, { update: update }),
|
|
50
|
+
update && (React.createElement(ReactAppStateDetector, { targetFields: targetFields, update: update })),
|
|
72
51
|
React.createElement(Container, { disableGutters: disableGutters, maxWidth: maxWidth, sx: sx, id: "page-container", ...rest },
|
|
73
52
|
React.createElement(FabBox, { sx: {
|
|
74
53
|
zIndex: 1,
|
package/lib/states/IState.d.ts
CHANGED
|
@@ -17,12 +17,19 @@ export interface IUpdate<S extends IState, A extends IAction> {
|
|
|
17
17
|
* State update interface
|
|
18
18
|
*/
|
|
19
19
|
export interface IStateUpdate {
|
|
20
|
-
(authorized?: boolean): PromiseLike<void> | void;
|
|
20
|
+
(authorized?: boolean, matchedFields?: string[]): PromiseLike<void> | void;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* State update props
|
|
24
24
|
*/
|
|
25
25
|
export interface IStateProps {
|
|
26
|
+
/**
|
|
27
|
+
* State last changed fields
|
|
28
|
+
*/
|
|
29
|
+
targetFields?: string[];
|
|
30
|
+
/**
|
|
31
|
+
* State update callback
|
|
32
|
+
*/
|
|
26
33
|
update: IStateUpdate;
|
|
27
34
|
}
|
|
28
35
|
/**
|
package/lib/states/UserState.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Utils } from '@etsoo/shared';
|
|
1
2
|
import { State } from './State';
|
|
2
3
|
/**
|
|
3
4
|
* User action type
|
|
@@ -26,10 +27,18 @@ export class UserState {
|
|
|
26
27
|
// User reducer
|
|
27
28
|
switch (action.type) {
|
|
28
29
|
case UserActionType.Login:
|
|
29
|
-
|
|
30
|
+
const lastChangedFields = state.authorized && action.user
|
|
31
|
+
? this.getChangedFields(action.user, state)
|
|
32
|
+
: [];
|
|
33
|
+
return {
|
|
34
|
+
...action.user,
|
|
35
|
+
authorized: true,
|
|
36
|
+
lastChangedFields
|
|
37
|
+
};
|
|
30
38
|
case UserActionType.Logout:
|
|
31
39
|
return {
|
|
32
40
|
...state,
|
|
41
|
+
lastChangedFields: undefined,
|
|
33
42
|
token: undefined,
|
|
34
43
|
authorized: false // Flag as unauthorized
|
|
35
44
|
};
|
|
@@ -37,6 +46,7 @@ export class UserState {
|
|
|
37
46
|
if (action.update) {
|
|
38
47
|
var newState = { ...state };
|
|
39
48
|
action.update(newState);
|
|
49
|
+
newState.lastChangedFields = this.getChangedFields(newState, state);
|
|
40
50
|
return newState;
|
|
41
51
|
}
|
|
42
52
|
return state;
|
|
@@ -46,6 +56,7 @@ export class UserState {
|
|
|
46
56
|
return state;
|
|
47
57
|
return {
|
|
48
58
|
...state,
|
|
59
|
+
lastChangedFields: undefined,
|
|
49
60
|
authorized: false // Flag as unauthorized
|
|
50
61
|
};
|
|
51
62
|
default:
|
|
@@ -55,4 +66,10 @@ export class UserState {
|
|
|
55
66
|
this.context = context;
|
|
56
67
|
this.provider = provider;
|
|
57
68
|
}
|
|
69
|
+
getChangedFields(input, init) {
|
|
70
|
+
return Utils.objectUpdated(input, init, [
|
|
71
|
+
'seconds',
|
|
72
|
+
'lastChangedFields'
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
58
75
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/react",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.56",
|
|
4
4
|
"description": "TypeScript ReactJs framework",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"@emotion/react": "^11.7.1",
|
|
51
51
|
"@emotion/style": "^0.8.0",
|
|
52
52
|
"@emotion/styled": "^11.6.0",
|
|
53
|
-
"@etsoo/appscript": "^1.1.
|
|
53
|
+
"@etsoo/appscript": "^1.1.79",
|
|
54
54
|
"@etsoo/notificationbase": "^1.0.94",
|
|
55
|
-
"@etsoo/shared": "^1.0.
|
|
55
|
+
"@etsoo/shared": "^1.0.78",
|
|
56
56
|
"@mui/icons-material": "^5.2.4",
|
|
57
57
|
"@mui/material": "^5.2.4",
|
|
58
58
|
"@reach/router": "^1.3.4",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"eslint-plugin-react": "^7.27.1",
|
|
90
90
|
"jest": "^27.4.5",
|
|
91
91
|
"react-test-renderer": "^17.0.2",
|
|
92
|
-
"ts-jest": "^27.1.
|
|
92
|
+
"ts-jest": "^27.1.2",
|
|
93
93
|
"typescript": "^4.5.4"
|
|
94
94
|
}
|
|
95
95
|
}
|
package/src/app/ReactApp.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
IUserData
|
|
8
8
|
} from '@etsoo/appscript';
|
|
9
9
|
import { NotificationRenderProps } from '@etsoo/notificationbase';
|
|
10
|
-
import { DataTypes
|
|
10
|
+
import { DataTypes } from '@etsoo/shared';
|
|
11
11
|
import React from 'react';
|
|
12
12
|
import { NotifierMU } from '../mu/NotifierMU';
|
|
13
13
|
import { ProgressCount } from '../mu/ProgressCount';
|
|
@@ -42,7 +42,7 @@ let globalApp: IReactApp<IAppSettings, any, IPageData>;
|
|
|
42
42
|
*/
|
|
43
43
|
export function ReactAppStateDetector(props: IStateProps) {
|
|
44
44
|
// Destruct
|
|
45
|
-
const { update } = props;
|
|
45
|
+
const { targetFields, update } = props;
|
|
46
46
|
|
|
47
47
|
// Context
|
|
48
48
|
const { state } =
|
|
@@ -52,11 +52,24 @@ export function ReactAppStateDetector(props: IStateProps) {
|
|
|
52
52
|
(globalApp.userState as UserState<IUser>).context
|
|
53
53
|
);
|
|
54
54
|
|
|
55
|
+
// Match fields
|
|
56
|
+
const changedFields = state.lastChangedFields;
|
|
57
|
+
let matchedFields: string[] | undefined;
|
|
58
|
+
if (targetFields == null || changedFields == null) {
|
|
59
|
+
matchedFields = changedFields;
|
|
60
|
+
} else {
|
|
61
|
+
matchedFields = [];
|
|
62
|
+
targetFields.forEach((targetField) => {
|
|
63
|
+
if (changedFields.includes(targetField))
|
|
64
|
+
matchedFields?.push(targetField);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
// Ready
|
|
56
69
|
React.useEffect(() => {
|
|
57
70
|
// Callback
|
|
58
|
-
update(state.authorized);
|
|
59
|
-
}, [state.authorized]);
|
|
71
|
+
update(state.authorized, matchedFields);
|
|
72
|
+
}, [state.authorized, matchedFields]);
|
|
60
73
|
|
|
61
74
|
// return
|
|
62
75
|
return React.createElement(React.Fragment);
|
|
@@ -343,18 +356,11 @@ export class ReactApp<
|
|
|
343
356
|
refreshToken: string,
|
|
344
357
|
keep?: boolean
|
|
345
358
|
): void {
|
|
346
|
-
// Changed
|
|
347
|
-
const dataChanged =
|
|
348
|
-
!this.authorized ||
|
|
349
|
-
this.userData == null ||
|
|
350
|
-
!Utils.objectEqual(this.userData, user, ['seconds', 'token']);
|
|
351
|
-
|
|
352
359
|
// Super call, set token
|
|
353
360
|
super.userLogin(user, refreshToken, keep);
|
|
354
361
|
|
|
355
362
|
// Dispatch action
|
|
356
|
-
|
|
357
|
-
if (this.userStateDispatch != null && dataChanged)
|
|
363
|
+
if (this.userStateDispatch != null)
|
|
358
364
|
this.userStateDispatch({
|
|
359
365
|
type: UserActionType.Login,
|
|
360
366
|
user
|
|
@@ -40,6 +40,7 @@ export function CommonPage(props: CommonPageProps) {
|
|
|
40
40
|
onUpdateAll,
|
|
41
41
|
paddings = MUGlobal.pagePaddings,
|
|
42
42
|
scrollContainer,
|
|
43
|
+
targetFields,
|
|
43
44
|
pullContainer,
|
|
44
45
|
sx = {},
|
|
45
46
|
...rest
|
|
@@ -50,11 +51,6 @@ export function CommonPage(props: CommonPageProps) {
|
|
|
50
51
|
padding: paddings
|
|
51
52
|
});
|
|
52
53
|
|
|
53
|
-
const [state] = React.useState<{
|
|
54
|
-
firstLoaded?: boolean;
|
|
55
|
-
loading?: boolean;
|
|
56
|
-
}>({});
|
|
57
|
-
|
|
58
54
|
// Fab padding
|
|
59
55
|
const fabPadding = MUGlobal.increase(
|
|
60
56
|
MUGlobal.pagePaddings,
|
|
@@ -66,11 +62,7 @@ export function CommonPage(props: CommonPageProps) {
|
|
|
66
62
|
|
|
67
63
|
// Update
|
|
68
64
|
const update = onUpdateAll
|
|
69
|
-
?
|
|
70
|
-
state.loading = true;
|
|
71
|
-
await onUpdateAll(authorized);
|
|
72
|
-
state.firstLoaded = true;
|
|
73
|
-
}
|
|
65
|
+
? onUpdateAll
|
|
74
66
|
: onUpdate
|
|
75
67
|
? (authorized?: boolean) => {
|
|
76
68
|
if (authorized == null || authorized) onUpdate();
|
|
@@ -81,29 +73,15 @@ export function CommonPage(props: CommonPageProps) {
|
|
|
81
73
|
}
|
|
82
74
|
: undefined;
|
|
83
75
|
|
|
84
|
-
React.useEffect(() => {
|
|
85
|
-
return () => {
|
|
86
|
-
state.loading = false;
|
|
87
|
-
state.firstLoaded = false;
|
|
88
|
-
};
|
|
89
|
-
}, []);
|
|
90
|
-
|
|
91
|
-
React.useEffect(() => {
|
|
92
|
-
if (state.loading) {
|
|
93
|
-
state.loading = false;
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// onUpdateAll support to load after page loaded
|
|
98
|
-
if (onUpdateAll != null && state.firstLoaded) {
|
|
99
|
-
onUpdateAll();
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
|
|
103
76
|
// Return the UI
|
|
104
77
|
return (
|
|
105
78
|
<React.Fragment>
|
|
106
|
-
{update &&
|
|
79
|
+
{update && (
|
|
80
|
+
<ReactAppStateDetector
|
|
81
|
+
targetFields={targetFields}
|
|
82
|
+
update={update}
|
|
83
|
+
/>
|
|
84
|
+
)}
|
|
107
85
|
<Container
|
|
108
86
|
disableGutters={disableGutters}
|
|
109
87
|
maxWidth={maxWidth}
|
package/src/states/IState.ts
CHANGED
|
@@ -20,13 +20,21 @@ export interface IUpdate<S extends IState, A extends IAction> {
|
|
|
20
20
|
* State update interface
|
|
21
21
|
*/
|
|
22
22
|
export interface IStateUpdate {
|
|
23
|
-
(authorized?: boolean): PromiseLike<void> | void;
|
|
23
|
+
(authorized?: boolean, matchedFields?: string[]): PromiseLike<void> | void;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* State update props
|
|
28
28
|
*/
|
|
29
29
|
export interface IStateProps {
|
|
30
|
+
/**
|
|
31
|
+
* State last changed fields
|
|
32
|
+
*/
|
|
33
|
+
targetFields?: string[];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* State update callback
|
|
37
|
+
*/
|
|
30
38
|
update: IStateUpdate;
|
|
31
39
|
}
|
|
32
40
|
|
package/src/states/UserState.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IAction, IUser, IUserData } from '@etsoo/appscript';
|
|
2
|
+
import { Utils } from '@etsoo/shared';
|
|
2
3
|
import { IProviderProps, IUpdate } from './IState';
|
|
3
4
|
import { State } from './State';
|
|
4
5
|
|
|
@@ -73,10 +74,19 @@ export class UserState<D extends IUser> {
|
|
|
73
74
|
// User reducer
|
|
74
75
|
switch (action.type) {
|
|
75
76
|
case UserActionType.Login:
|
|
76
|
-
|
|
77
|
+
const lastChangedFields =
|
|
78
|
+
state.authorized && action.user
|
|
79
|
+
? this.getChangedFields(action.user, state)
|
|
80
|
+
: [];
|
|
81
|
+
return {
|
|
82
|
+
...action.user!,
|
|
83
|
+
authorized: true,
|
|
84
|
+
lastChangedFields
|
|
85
|
+
} as D;
|
|
77
86
|
case UserActionType.Logout:
|
|
78
87
|
return {
|
|
79
88
|
...state, // Keep other user data
|
|
89
|
+
lastChangedFields: undefined,
|
|
80
90
|
token: undefined, // Remove token
|
|
81
91
|
authorized: false // Flag as unauthorized
|
|
82
92
|
};
|
|
@@ -84,6 +94,10 @@ export class UserState<D extends IUser> {
|
|
|
84
94
|
if (action.update) {
|
|
85
95
|
var newState = { ...state };
|
|
86
96
|
action.update(newState);
|
|
97
|
+
newState.lastChangedFields = this.getChangedFields(
|
|
98
|
+
newState,
|
|
99
|
+
state
|
|
100
|
+
);
|
|
87
101
|
return newState;
|
|
88
102
|
}
|
|
89
103
|
return state;
|
|
@@ -93,6 +107,7 @@ export class UserState<D extends IUser> {
|
|
|
93
107
|
|
|
94
108
|
return {
|
|
95
109
|
...state, // Keep other user data and token for refresh
|
|
110
|
+
lastChangedFields: undefined,
|
|
96
111
|
authorized: false // Flag as unauthorized
|
|
97
112
|
};
|
|
98
113
|
default:
|
|
@@ -106,4 +121,11 @@ export class UserState<D extends IUser> {
|
|
|
106
121
|
this.context = context;
|
|
107
122
|
this.provider = provider;
|
|
108
123
|
}
|
|
124
|
+
|
|
125
|
+
private getChangedFields(input: {}, init: {}) {
|
|
126
|
+
return Utils.objectUpdated(input, init, [
|
|
127
|
+
'seconds',
|
|
128
|
+
'lastChangedFields'
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
109
131
|
}
|