@etsoo/react 1.4.56 → 1.4.60

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
  }
@@ -63,7 +63,9 @@ export function MobileListItemRenderer({ data, itemHeight, margins }, renderer)
63
63
  } })) : (actions), title: title, titleTypographyProps: { variant: 'body2' }, subheader: subheader, subheaderTypographyProps: { variant: 'caption' } }),
64
64
  React.createElement(CardContent, { sx: {
65
65
  paddingTop: 0,
66
- paddingBottom: cardActions == null ? margins : 0
66
+ paddingBottom: cardActions == null
67
+ ? Reflect.get(margins, 'marginBottom')
68
+ : 0
67
69
  } }, children),
68
70
  cardActions));
69
71
  }
@@ -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,73 @@
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
+ if (field.label == null && typeof field.data === 'string')
18
+ field.label = field.data;
19
+ const { data: fieldData, label: fieldLabel, ...rest } = field;
20
+ gridProps = rest;
21
+ // Field data
22
+ if (typeof fieldData === 'function')
23
+ itemData = fieldData(data);
24
+ else
25
+ itemData = formatItemData(formatItemData);
26
+ // Field label
27
+ itemLabel =
28
+ typeof fieldLabel === 'function'
29
+ ? fieldLabel()
30
+ : fieldLabel == null
31
+ ? 'No Label'
32
+ : (_a = globalApp.get(fieldLabel)) !== null && _a !== void 0 ? _a : fieldLabel;
33
+ }
34
+ else {
35
+ itemData = formatItemData(data[field]);
36
+ itemLabel = (_b = globalApp.get(field)) !== null && _b !== void 0 ? _b : field;
37
+ gridProps = { xs: 12, sm: 6, md: 4, lg: 3 };
38
+ }
39
+ return [itemData, itemLabel, gridProps];
40
+ }
3
41
  /**
4
42
  * View page
5
43
  * @param props Props
6
44
  */
7
45
  export function ViewPage(props) {
8
46
  // Destruct
9
- const { ...rest } = props;
10
- return React.createElement(CommonPage, { ...rest, scrollContainer: global });
47
+ const { children, fields, loadData, paddings = MUGlobal.pagePaddings, supportRefresh = true, ...rest } = props;
48
+ // Data
49
+ const [data, setData] = React.useState();
50
+ // Load data
51
+ const onRefresh = async () => {
52
+ const result = await loadData();
53
+ if (result == null)
54
+ return;
55
+ setData(result);
56
+ };
57
+ 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,
58
+ React.createElement(Grid, { container: true, justifyContent: "left", spacing: paddings, sx: {
59
+ '.MuiTypography-subtitle2': { fontWeight: 'bold' }
60
+ } }, fields.map((field, index) => {
61
+ // Get data
62
+ const [itemData, itemLabel, gridProps] = getItemField(field, data);
63
+ if (itemData == null)
64
+ return undefined;
65
+ // Layout
66
+ return (React.createElement(Grid, { item: true, ...gridProps, key: index },
67
+ React.createElement(Typography, { variant: "caption", component: "div" },
68
+ itemLabel,
69
+ ":"),
70
+ React.createElement(Typography, { variant: "subtitle2" }, itemData)));
71
+ })),
72
+ children))));
11
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.4.56",
3
+ "version": "1.4.60",
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
  }
@@ -104,7 +104,10 @@ export function MobileListItemRenderer<T>(
104
104
  <CardContent
105
105
  sx={{
106
106
  paddingTop: 0,
107
- paddingBottom: cardActions == null ? margins : 0
107
+ paddingBottom:
108
+ cardActions == null
109
+ ? Reflect.get(margins, 'marginBottom')
110
+ : 0
108
111
  }}
109
112
  >
110
113
  {children}
@@ -1,19 +1,159 @@
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
+ if (field.label == null && typeof field.data === 'string')
62
+ field.label = field.data;
63
+ const { data: fieldData, label: fieldLabel, ...rest } = field;
64
+ gridProps = rest;
65
+
66
+ // Field data
67
+ if (typeof fieldData === 'function') itemData = fieldData(data);
68
+ else itemData = formatItemData(formatItemData);
69
+
70
+ // Field label
71
+ itemLabel =
72
+ typeof fieldLabel === 'function'
73
+ ? fieldLabel()
74
+ : fieldLabel == null
75
+ ? 'No Label'
76
+ : globalApp.get<string>(fieldLabel) ?? fieldLabel;
77
+ } else {
78
+ itemData = formatItemData(data[field]);
79
+ itemLabel = globalApp.get<string>(field) ?? field;
80
+ gridProps = { xs: 12, sm: 6, md: 4, lg: 3 };
81
+ }
82
+
83
+ return [itemData, itemLabel, gridProps];
84
+ }
9
85
 
10
86
  /**
11
87
  * View page
12
88
  * @param props Props
13
89
  */
14
- export function ViewPage(props: ViewPageProps) {
90
+ export function ViewPage<T extends {}>(props: ViewPageProps<T>) {
15
91
  // Destruct
16
- const { ...rest } = props;
92
+ const {
93
+ children,
94
+ fields,
95
+ loadData,
96
+ paddings = MUGlobal.pagePaddings,
97
+ supportRefresh = true,
98
+ ...rest
99
+ } = props;
100
+
101
+ // Data
102
+ const [data, setData] = React.useState<T>();
103
+
104
+ // Load data
105
+ const onRefresh = async () => {
106
+ const result = await loadData();
107
+ if (result == null) return;
108
+ setData(result);
109
+ };
110
+
111
+ return (
112
+ <CommonPage
113
+ paddings={paddings}
114
+ onRefresh={supportRefresh ? onRefresh : undefined}
115
+ onUpdate={supportRefresh ? undefined : onRefresh}
116
+ {...rest}
117
+ scrollContainer={global}
118
+ >
119
+ {data == null ? (
120
+ <LinearProgress />
121
+ ) : (
122
+ <React.Fragment>
123
+ <Grid
124
+ container
125
+ justifyContent="left"
126
+ spacing={paddings}
127
+ sx={{
128
+ '.MuiTypography-subtitle2': { fontWeight: 'bold' }
129
+ }}
130
+ >
131
+ {fields.map((field, index) => {
132
+ // Get data
133
+ const [itemData, itemLabel, gridProps] =
134
+ getItemField(field, data);
135
+
136
+ if (itemData == null) return undefined;
17
137
 
18
- return <CommonPage {...rest} scrollContainer={global}></CommonPage>;
138
+ // Layout
139
+ return (
140
+ <Grid item {...gridProps} key={index}>
141
+ <Typography
142
+ variant="caption"
143
+ component="div"
144
+ >
145
+ {itemLabel}:
146
+ </Typography>
147
+ <Typography variant="subtitle2">
148
+ {itemData}
149
+ </Typography>
150
+ </Grid>
151
+ );
152
+ })}
153
+ </Grid>
154
+ {children}
155
+ </React.Fragment>
156
+ )}
157
+ </CommonPage>
158
+ );
19
159
  }