@etsoo/react 1.4.57 → 1.4.61

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.
@@ -8,6 +8,10 @@ import { IStateProps } from '../states/IState';
8
8
  import { IPageData, PageAction, PageState } from '../states/PageState';
9
9
  import { UserAction, UserState } from '../states/UserState';
10
10
  import { InputDialogProps } from './InputDialogProps';
11
+ /**
12
+ * Global application
13
+ */
14
+ export declare let globalApp: IReactApp<IAppSettings, any, IPageData>;
11
15
  /**
12
16
  * React app state detector
13
17
  * Case 1: undefined, when refresh the whole page
@@ -7,8 +7,10 @@ import { CultureState } from '../states/CultureState';
7
7
  import { PageActionType, PageState } from '../states/PageState';
8
8
  import { UserActionType, UserState } from '../states/UserState';
9
9
  import { Labels } from './Labels';
10
- // Global application
11
- let globalApp;
10
+ /**
11
+ * Global application
12
+ */
13
+ export let globalApp;
12
14
  /**
13
15
  * React app state detector
14
16
  * Case 1: undefined, when refresh the whole page
@@ -234,11 +234,12 @@ export class ServiceApp extends ReactApp {
234
234
  // Service user login
235
235
  this.servicePassphrase =
236
236
  (_a = this.decrypt(serviceUser.serviceDeviceId, this.settings.serviceId.toString())) !== null && _a !== void 0 ? _a : '';
237
- // Keep = true, means service could hold the refresh token for long access
238
- super.userLogin(user, refreshToken, true);
239
237
  // Service user
240
238
  this.serviceUser = serviceUser;
241
239
  // Service API token
242
240
  this.serviceApi.authorize(this.settings.authScheme, serviceUser.token);
241
+ // Keep = true, means service could hold the refresh token for long access
242
+ // Trigger Context change and serviceUser is ready then
243
+ super.userLogin(user, refreshToken, true);
243
244
  }
244
245
  }
@@ -1,12 +1,40 @@
1
- /// <reference types="react" />
1
+ import { GridProps } from '@mui/material';
2
+ import React from 'react';
2
3
  import { CommonPageProps } from './CommonPageProps';
4
+ /**
5
+ * View page display field
6
+ */
7
+ export interface ViewPageField<T extends {}> extends GridProps {
8
+ /**
9
+ * Data field
10
+ */
11
+ data: keyof T | ((item: T) => React.ReactNode);
12
+ /**
13
+ * Label field
14
+ */
15
+ label: string | (() => React.ReactNode);
16
+ }
17
+ declare type ViewPageFieldType<T> = (string & keyof T) | ViewPageField<T>;
3
18
  /**
4
19
  * View page props
5
20
  */
6
- export interface ViewPageProps extends CommonPageProps {
21
+ export interface ViewPageProps<T extends {}> extends CommonPageProps {
22
+ /**
23
+ * Fields to display
24
+ */
25
+ fields: ViewPageFieldType<T>[];
26
+ /**
27
+ * Load data
28
+ */
29
+ loadData: () => PromiseLike<T | undefined>;
30
+ /**
31
+ * Support refresh
32
+ */
33
+ supportRefresh?: boolean;
7
34
  }
8
35
  /**
9
36
  * View page
10
37
  * @param props Props
11
38
  */
12
- export declare function ViewPage(props: ViewPageProps): JSX.Element;
39
+ export declare function ViewPage<T extends {}>(props: ViewPageProps<T>): JSX.Element;
40
+ export {};
@@ -1,11 +1,69 @@
1
+ import { Grid, LinearProgress, Typography } from '@mui/material';
1
2
  import React from 'react';
3
+ import { globalApp } from '../../app/ReactApp';
4
+ import { MUGlobal } from '../MUGlobal';
2
5
  import { CommonPage } from './CommonPage';
6
+ function formatItemData(fieldData) {
7
+ if (fieldData instanceof Date)
8
+ return globalApp.formatDate(fieldData, 'd');
9
+ return new String(fieldData);
10
+ }
11
+ function getItemField(field, data) {
12
+ var _a, _b;
13
+ // Item data and label
14
+ let itemData, itemLabel, gridProps;
15
+ if (typeof field === 'object') {
16
+ // Destruct
17
+ const { data: fieldData, label: fieldLabel, ...rest } = field;
18
+ gridProps = rest;
19
+ // Field data
20
+ if (typeof fieldData === 'function')
21
+ itemData = fieldData(data);
22
+ else
23
+ itemData = formatItemData(formatItemData);
24
+ // Field label
25
+ itemLabel =
26
+ typeof fieldLabel === 'function'
27
+ ? fieldLabel()
28
+ : (_a = globalApp.get(fieldLabel)) !== null && _a !== void 0 ? _a : fieldLabel;
29
+ }
30
+ else {
31
+ itemData = formatItemData(data[field]);
32
+ itemLabel = (_b = globalApp.get(field)) !== null && _b !== void 0 ? _b : field;
33
+ gridProps = { xs: 12, sm: 6, md: 4, lg: 3 };
34
+ }
35
+ return [itemData, itemLabel, gridProps];
36
+ }
3
37
  /**
4
38
  * View page
5
39
  * @param props Props
6
40
  */
7
41
  export function ViewPage(props) {
8
42
  // Destruct
9
- const { ...rest } = props;
10
- return React.createElement(CommonPage, { ...rest, scrollContainer: global });
43
+ const { children, fields, loadData, paddings = MUGlobal.pagePaddings, supportRefresh = true, ...rest } = props;
44
+ // Data
45
+ const [data, setData] = React.useState();
46
+ // Load data
47
+ const onRefresh = async () => {
48
+ const result = await loadData();
49
+ if (result == null)
50
+ return;
51
+ setData(result);
52
+ };
53
+ return (React.createElement(CommonPage, { paddings: paddings, onRefresh: supportRefresh ? onRefresh : undefined, onUpdate: supportRefresh ? undefined : onRefresh, ...rest, scrollContainer: global }, data == null ? (React.createElement(LinearProgress, null)) : (React.createElement(React.Fragment, null,
54
+ React.createElement(Grid, { container: true, justifyContent: "left", spacing: paddings, sx: {
55
+ '.MuiTypography-subtitle2': { fontWeight: 'bold' }
56
+ } }, fields.map((field, index) => {
57
+ // Get data
58
+ const [itemData, itemLabel, gridProps] = getItemField(field, data);
59
+ if (itemData == null)
60
+ return undefined;
61
+ // Layout
62
+ return (React.createElement(Grid, { item: true, ...gridProps, key: index },
63
+ React.createElement(Typography, { variant: "caption", component: "div" },
64
+ itemLabel,
65
+ ":"),
66
+ React.createElement(Typography, { variant: "subtitle2" }, itemData)));
67
+ })),
68
+ children))));
11
69
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.4.57",
3
+ "version": "1.4.61",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -77,7 +77,7 @@
77
77
  },
78
78
  "devDependencies": {
79
79
  "@babel/cli": "^7.16.8",
80
- "@babel/core": "^7.16.10",
80
+ "@babel/core": "^7.16.12",
81
81
  "@babel/plugin-transform-runtime": "^7.16.10",
82
82
  "@babel/preset-env": "^7.16.11",
83
83
  "@babel/runtime-corejs3": "^7.16.8",
@@ -34,8 +34,10 @@ import {
34
34
  import { InputDialogProps } from './InputDialogProps';
35
35
  import { Labels } from './Labels';
36
36
 
37
- // Global application
38
- let globalApp: IReactApp<IAppSettings, any, IPageData>;
37
+ /**
38
+ * Global application
39
+ */
40
+ export let globalApp: IReactApp<IAppSettings, any, IPageData>;
39
41
 
40
42
  /**
41
43
  * React app state detector
@@ -333,13 +333,14 @@ export class ServiceApp<
333
333
  this.settings.serviceId.toString()
334
334
  ) ?? '';
335
335
 
336
- // Keep = true, means service could hold the refresh token for long access
337
- super.userLogin(user, refreshToken, true);
338
-
339
336
  // Service user
340
337
  this.serviceUser = serviceUser;
341
338
 
342
339
  // Service API token
343
340
  this.serviceApi.authorize(this.settings.authScheme, serviceUser.token);
341
+
342
+ // Keep = true, means service could hold the refresh token for long access
343
+ // Trigger Context change and serviceUser is ready then
344
+ super.userLogin(user, refreshToken, true);
344
345
  }
345
346
  }
@@ -1,19 +1,155 @@
1
+ import { Grid, GridProps, LinearProgress, Typography } from '@mui/material';
1
2
  import React from 'react';
3
+ import { globalApp } from '../../app/ReactApp';
4
+ import { MUGlobal } from '../MUGlobal';
2
5
  import { CommonPage } from './CommonPage';
3
6
  import { CommonPageProps } from './CommonPageProps';
4
7
 
8
+ /**
9
+ * View page display field
10
+ */
11
+ export interface ViewPageField<T extends {}> extends GridProps {
12
+ /**
13
+ * Data field
14
+ */
15
+ data: keyof T | ((item: T) => React.ReactNode);
16
+
17
+ /**
18
+ * Label field
19
+ */
20
+ label: string | (() => React.ReactNode);
21
+ }
22
+
23
+ type ViewPageFieldType<T> = (string & keyof T) | ViewPageField<T>;
24
+
5
25
  /**
6
26
  * View page props
7
27
  */
8
- export interface ViewPageProps extends CommonPageProps {}
28
+ export interface ViewPageProps<T extends {}> extends CommonPageProps {
29
+ /**
30
+ * Fields to display
31
+ */
32
+ fields: ViewPageFieldType<T>[];
33
+
34
+ /**
35
+ * Load data
36
+ */
37
+ loadData: () => PromiseLike<T | undefined>;
38
+
39
+ /**
40
+ * Support refresh
41
+ */
42
+ supportRefresh?: boolean;
43
+ }
44
+
45
+ function formatItemData(fieldData: unknown) {
46
+ if (fieldData instanceof Date) return globalApp.formatDate(fieldData, 'd');
47
+ return new String(fieldData);
48
+ }
49
+
50
+ function getItemField<T>(
51
+ field: ViewPageFieldType<T>,
52
+ data: T
53
+ ): [React.ReactNode, React.ReactNode, GridProps] {
54
+ // Item data and label
55
+ let itemData: React.ReactNode,
56
+ itemLabel: React.ReactNode,
57
+ gridProps: GridProps;
58
+
59
+ if (typeof field === 'object') {
60
+ // Destruct
61
+ const { data: fieldData, label: fieldLabel, ...rest } = field;
62
+ gridProps = rest;
63
+
64
+ // Field data
65
+ if (typeof fieldData === 'function') itemData = fieldData(data);
66
+ else itemData = formatItemData(formatItemData);
67
+
68
+ // Field label
69
+ itemLabel =
70
+ typeof fieldLabel === 'function'
71
+ ? fieldLabel()
72
+ : globalApp.get<string>(fieldLabel) ?? fieldLabel;
73
+ } else {
74
+ itemData = formatItemData(data[field]);
75
+ itemLabel = globalApp.get<string>(field) ?? field;
76
+ gridProps = { xs: 12, sm: 6, md: 4, lg: 3 };
77
+ }
78
+
79
+ return [itemData, itemLabel, gridProps];
80
+ }
9
81
 
10
82
  /**
11
83
  * View page
12
84
  * @param props Props
13
85
  */
14
- export function ViewPage(props: ViewPageProps) {
86
+ export function ViewPage<T extends {}>(props: ViewPageProps<T>) {
15
87
  // Destruct
16
- const { ...rest } = props;
88
+ const {
89
+ children,
90
+ fields,
91
+ loadData,
92
+ paddings = MUGlobal.pagePaddings,
93
+ supportRefresh = true,
94
+ ...rest
95
+ } = props;
96
+
97
+ // Data
98
+ const [data, setData] = React.useState<T>();
99
+
100
+ // Load data
101
+ const onRefresh = async () => {
102
+ const result = await loadData();
103
+ if (result == null) return;
104
+ setData(result);
105
+ };
106
+
107
+ return (
108
+ <CommonPage
109
+ paddings={paddings}
110
+ onRefresh={supportRefresh ? onRefresh : undefined}
111
+ onUpdate={supportRefresh ? undefined : onRefresh}
112
+ {...rest}
113
+ scrollContainer={global}
114
+ >
115
+ {data == null ? (
116
+ <LinearProgress />
117
+ ) : (
118
+ <React.Fragment>
119
+ <Grid
120
+ container
121
+ justifyContent="left"
122
+ spacing={paddings}
123
+ sx={{
124
+ '.MuiTypography-subtitle2': { fontWeight: 'bold' }
125
+ }}
126
+ >
127
+ {fields.map((field, index) => {
128
+ // Get data
129
+ const [itemData, itemLabel, gridProps] =
130
+ getItemField(field, data);
131
+
132
+ if (itemData == null) return undefined;
17
133
 
18
- return <CommonPage {...rest} scrollContainer={global}></CommonPage>;
134
+ // Layout
135
+ return (
136
+ <Grid item {...gridProps} key={index}>
137
+ <Typography
138
+ variant="caption"
139
+ component="div"
140
+ >
141
+ {itemLabel}:
142
+ </Typography>
143
+ <Typography variant="subtitle2">
144
+ {itemData}
145
+ </Typography>
146
+ </Grid>
147
+ );
148
+ })}
149
+ </Grid>
150
+ {children}
151
+ </React.Fragment>
152
+ )}
153
+ </CommonPage>
154
+ );
19
155
  }