@etsoo/react 1.3.53 → 1.3.57

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.
@@ -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,30 @@ 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
+ }
39
+ console.log(targetFields, changedFields, matchedFields);
27
40
  // Ready
28
41
  React.useEffect(() => {
29
42
  // Callback
30
- update(state.authorized);
31
- }, [state.authorized]);
43
+ update(state.authorized, matchedFields);
44
+ }, [state.authorized, matchedFields]);
32
45
  // return
33
46
  return React.createElement(React.Fragment);
34
47
  }
@@ -198,15 +211,10 @@ export class ReactApp extends CoreApp {
198
211
  * @param keep Keep in local storage or not
199
212
  */
200
213
  userLogin(user, refreshToken, keep) {
201
- // Changed
202
- const dataChanged = !this.authorized ||
203
- this.userData == null ||
204
- !Utils.objectEqual(this.userData, user, ['seconds', 'token']);
205
214
  // Super call, set token
206
215
  super.userLogin(user, refreshToken, keep);
207
216
  // Dispatch action
208
- // Only when unauthorized or with changes except 'token' and 'seconds'
209
- if (this.userStateDispatch != null && dataChanged)
217
+ if (this.userStateDispatch != null)
210
218
  this.userStateDispatch({
211
219
  type: UserActionType.Login,
212
220
  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 ref = React.useRef({});
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
- ? async (authorized) => {
38
- ref.current.loading = true;
39
- await onUpdateAll(authorized);
40
- ref.current.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
- ref.current.loading = false;
56
- ref.current.firstLoaded = false;
57
- };
58
- }, []);
59
- React.useEffect(() => {
60
- if (ref.current.loading) {
61
- ref.current.loading = false;
62
- return;
63
- }
64
- // onUpdateAll support to load after page loaded
65
- if (onUpdateAll != null && ref.current.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,
@@ -52,4 +52,8 @@ export interface CommonPageProps extends Omit<ContainerProps, 'id'> {
52
52
  * Scroll container
53
53
  */
54
54
  scrollContainer?: HTMLElement | object;
55
+ /**
56
+ * State last changed fields
57
+ */
58
+ targetFields?: string[];
55
59
  }
@@ -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
  /**
@@ -53,4 +53,5 @@ export declare class UserState<D extends IUser> {
53
53
  * Constructor
54
54
  */
55
55
  constructor();
56
+ private getChangedFields;
56
57
  }
@@ -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
- return { ...action.user, authorized: true };
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.53",
3
+ "version": "1.3.57",
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.77",
53
+ "@etsoo/appscript": "^1.1.79",
54
54
  "@etsoo/notificationbase": "^1.0.94",
55
- "@etsoo/shared": "^1.0.76",
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.1",
92
+ "ts-jest": "^27.1.2",
93
93
  "typescript": "^4.5.4"
94
94
  }
95
95
  }
@@ -7,7 +7,7 @@ import {
7
7
  IUserData
8
8
  } from '@etsoo/appscript';
9
9
  import { NotificationRenderProps } from '@etsoo/notificationbase';
10
- import { DataTypes, Utils } from '@etsoo/shared';
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,26 @@ 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
+
68
+ console.log(targetFields, changedFields, matchedFields);
69
+
55
70
  // Ready
56
71
  React.useEffect(() => {
57
72
  // Callback
58
- update(state.authorized);
59
- }, [state.authorized]);
73
+ update(state.authorized, matchedFields);
74
+ }, [state.authorized, matchedFields]);
60
75
 
61
76
  // return
62
77
  return React.createElement(React.Fragment);
@@ -343,18 +358,11 @@ export class ReactApp<
343
358
  refreshToken: string,
344
359
  keep?: boolean
345
360
  ): void {
346
- // Changed
347
- const dataChanged =
348
- !this.authorized ||
349
- this.userData == null ||
350
- !Utils.objectEqual(this.userData, user, ['seconds', 'token']);
351
-
352
361
  // Super call, set token
353
362
  super.userLogin(user, refreshToken, keep);
354
363
 
355
364
  // Dispatch action
356
- // Only when unauthorized or with changes except 'token' and 'seconds'
357
- if (this.userStateDispatch != null && dataChanged)
365
+ if (this.userStateDispatch != null)
358
366
  this.userStateDispatch({
359
367
  type: UserActionType.Login,
360
368
  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 ref = React.useRef<{
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
- ? async (authorized?: boolean) => {
70
- ref.current.loading = true;
71
- await onUpdateAll(authorized);
72
- ref.current.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
- ref.current.loading = false;
87
- ref.current.firstLoaded = false;
88
- };
89
- }, []);
90
-
91
- React.useEffect(() => {
92
- if (ref.current.loading) {
93
- ref.current.loading = false;
94
- return;
95
- }
96
-
97
- // onUpdateAll support to load after page loaded
98
- if (onUpdateAll != null && ref.current.firstLoaded) {
99
- onUpdateAll();
100
- }
101
- });
102
-
103
76
  // Return the UI
104
77
  return (
105
78
  <React.Fragment>
106
- {update && <ReactAppStateDetector update={update} />}
79
+ {update && (
80
+ <ReactAppStateDetector
81
+ targetFields={targetFields}
82
+ update={update}
83
+ />
84
+ )}
107
85
  <Container
108
86
  disableGutters={disableGutters}
109
87
  maxWidth={maxWidth}
@@ -62,4 +62,9 @@ export interface CommonPageProps extends Omit<ContainerProps, 'id'> {
62
62
  * Scroll container
63
63
  */
64
64
  scrollContainer?: HTMLElement | object;
65
+
66
+ /**
67
+ * State last changed fields
68
+ */
69
+ targetFields?: string[];
65
70
  }
@@ -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
 
@@ -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
- return { ...action.user!, authorized: true } as D;
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
  }