@etsoo/materialui 1.0.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 (250) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.json +38 -0
  3. package/.gitattributes +2 -0
  4. package/.github/workflows/main.yml +48 -0
  5. package/.prettierignore +5 -0
  6. package/.prettierrc +6 -0
  7. package/LICENSE +21 -0
  8. package/README.md +16 -0
  9. package/__tests__/ComboBox.tsx +30 -0
  10. package/__tests__/MUGlobalTests.tsx +58 -0
  11. package/__tests__/NotifierMUTests.tsx +217 -0
  12. package/__tests__/SelectEx.tsx +26 -0
  13. package/__tests__/tsconfig.json +19 -0
  14. package/babel.config.json +11 -0
  15. package/lib/AuditDisplay.d.ts +33 -0
  16. package/lib/AuditDisplay.js +52 -0
  17. package/lib/AutocompleteExtendedProps.d.ts +64 -0
  18. package/lib/AutocompleteExtendedProps.js +1 -0
  19. package/lib/BackButton.d.ts +13 -0
  20. package/lib/BackButton.js +33 -0
  21. package/lib/BridgeCloseButton.d.ts +23 -0
  22. package/lib/BridgeCloseButton.js +32 -0
  23. package/lib/ButtonLink.d.ts +17 -0
  24. package/lib/ButtonLink.js +19 -0
  25. package/lib/ComboBox.d.ts +38 -0
  26. package/lib/ComboBox.js +108 -0
  27. package/lib/CountdownButton.d.ts +23 -0
  28. package/lib/CountdownButton.js +81 -0
  29. package/lib/CustomFabProps.d.ts +27 -0
  30. package/lib/CustomFabProps.js +1 -0
  31. package/lib/DataGridEx.d.ts +94 -0
  32. package/lib/DataGridEx.js +329 -0
  33. package/lib/DataGridRenderers.d.ts +22 -0
  34. package/lib/DataGridRenderers.js +99 -0
  35. package/lib/DialogButton.d.ts +54 -0
  36. package/lib/DialogButton.js +45 -0
  37. package/lib/DnDList.d.ts +87 -0
  38. package/lib/DnDList.js +153 -0
  39. package/lib/DraggablePaperComponent.d.ts +8 -0
  40. package/lib/DraggablePaperComponent.js +12 -0
  41. package/lib/EmailInput.d.ts +11 -0
  42. package/lib/EmailInput.js +15 -0
  43. package/lib/FabBox.d.ts +21 -0
  44. package/lib/FabBox.js +31 -0
  45. package/lib/FlexBox.d.ts +14 -0
  46. package/lib/FlexBox.js +18 -0
  47. package/lib/GridDataFormat.d.ts +10 -0
  48. package/lib/GridDataFormat.js +43 -0
  49. package/lib/IconButtonLink.d.ts +17 -0
  50. package/lib/IconButtonLink.js +16 -0
  51. package/lib/InputField.d.ts +21 -0
  52. package/lib/InputField.js +39 -0
  53. package/lib/ItemList.d.ts +56 -0
  54. package/lib/ItemList.js +69 -0
  55. package/lib/ListItemRightIcon.d.ts +4 -0
  56. package/lib/ListItemRightIcon.js +8 -0
  57. package/lib/ListMoreDisplay.d.ts +35 -0
  58. package/lib/ListMoreDisplay.js +99 -0
  59. package/lib/LoadingButton.d.ts +16 -0
  60. package/lib/LoadingButton.js +41 -0
  61. package/lib/MUGlobal.d.ts +102 -0
  62. package/lib/MUGlobal.js +184 -0
  63. package/lib/MaskInput.d.ts +34 -0
  64. package/lib/MaskInput.js +43 -0
  65. package/lib/MobileListItemRenderer.d.ts +17 -0
  66. package/lib/MobileListItemRenderer.js +35 -0
  67. package/lib/MoreFab.d.ts +45 -0
  68. package/lib/MoreFab.js +95 -0
  69. package/lib/NotifierMU.d.ts +47 -0
  70. package/lib/NotifierMU.js +387 -0
  71. package/lib/NotifierPromptProps.d.ts +22 -0
  72. package/lib/NotifierPromptProps.js +1 -0
  73. package/lib/OptionGroup.d.ts +58 -0
  74. package/lib/OptionGroup.js +81 -0
  75. package/lib/PList.d.ts +15 -0
  76. package/lib/PList.js +12 -0
  77. package/lib/ProgressCount.d.ts +44 -0
  78. package/lib/ProgressCount.js +79 -0
  79. package/lib/PullToRefreshUI.d.ts +9 -0
  80. package/lib/PullToRefreshUI.js +18 -0
  81. package/lib/RLink.d.ts +14 -0
  82. package/lib/RLink.js +37 -0
  83. package/lib/ResponsibleContainer.d.ts +87 -0
  84. package/lib/ResponsibleContainer.js +156 -0
  85. package/lib/ScrollTopFab.d.ts +7 -0
  86. package/lib/ScrollTopFab.js +25 -0
  87. package/lib/ScrollerListEx.d.ts +81 -0
  88. package/lib/ScrollerListEx.js +167 -0
  89. package/lib/SearchBar.d.ts +29 -0
  90. package/lib/SearchBar.js +260 -0
  91. package/lib/SearchField.d.ts +21 -0
  92. package/lib/SearchField.js +39 -0
  93. package/lib/SearchOptionGroup.d.ts +9 -0
  94. package/lib/SearchOptionGroup.js +14 -0
  95. package/lib/SelectBool.d.ts +13 -0
  96. package/lib/SelectBool.js +22 -0
  97. package/lib/SelectEx.d.ts +50 -0
  98. package/lib/SelectEx.js +156 -0
  99. package/lib/ShowDataComparison.d.ts +20 -0
  100. package/lib/ShowDataComparison.js +58 -0
  101. package/lib/Switch.d.ts +29 -0
  102. package/lib/Switch.js +34 -0
  103. package/lib/SwitchAnt.d.ts +25 -0
  104. package/lib/SwitchAnt.js +40 -0
  105. package/lib/TabBox.d.ts +54 -0
  106. package/lib/TabBox.js +31 -0
  107. package/lib/TableEx.d.ts +65 -0
  108. package/lib/TableEx.js +270 -0
  109. package/lib/TextFieldEx.d.ts +101 -0
  110. package/lib/TextFieldEx.js +126 -0
  111. package/lib/Tiplist.d.ts +18 -0
  112. package/lib/Tiplist.js +157 -0
  113. package/lib/TooltipClick.d.ts +15 -0
  114. package/lib/TooltipClick.js +40 -0
  115. package/lib/UserAvatar.d.ts +24 -0
  116. package/lib/UserAvatar.js +25 -0
  117. package/lib/UserAvatarEditor.d.ts +53 -0
  118. package/lib/UserAvatarEditor.js +129 -0
  119. package/lib/app/CommonApp.d.ts +38 -0
  120. package/lib/app/CommonApp.js +149 -0
  121. package/lib/app/IServiceAppSettings.d.ts +11 -0
  122. package/lib/app/IServiceAppSettings.js +1 -0
  123. package/lib/app/IServicePage.d.ts +6 -0
  124. package/lib/app/IServicePage.js +1 -0
  125. package/lib/app/IServiceUser.d.ts +14 -0
  126. package/lib/app/IServiceUser.js +1 -0
  127. package/lib/app/ISmartERPUser.d.ts +14 -0
  128. package/lib/app/ISmartERPUser.js +1 -0
  129. package/lib/app/Labels.d.ts +65 -0
  130. package/lib/app/Labels.js +62 -0
  131. package/lib/app/ReactApp.d.ts +195 -0
  132. package/lib/app/ReactApp.js +296 -0
  133. package/lib/app/ServiceApp.d.ts +78 -0
  134. package/lib/app/ServiceApp.js +244 -0
  135. package/lib/index.d.ts +74 -0
  136. package/lib/index.js +74 -0
  137. package/lib/pages/CommonPage.d.ts +11 -0
  138. package/lib/pages/CommonPage.js +60 -0
  139. package/lib/pages/CommonPageProps.d.ts +59 -0
  140. package/lib/pages/CommonPageProps.js +1 -0
  141. package/lib/pages/DataGridPage.d.ts +9 -0
  142. package/lib/pages/DataGridPage.js +79 -0
  143. package/lib/pages/DataGridPageProps.d.ts +17 -0
  144. package/lib/pages/DataGridPageProps.js +1 -0
  145. package/lib/pages/EditPage.d.ts +33 -0
  146. package/lib/pages/EditPage.js +29 -0
  147. package/lib/pages/FixedListPage.d.ts +15 -0
  148. package/lib/pages/FixedListPage.js +70 -0
  149. package/lib/pages/ListPage.d.ts +9 -0
  150. package/lib/pages/ListPage.js +50 -0
  151. package/lib/pages/ListPageProps.d.ts +7 -0
  152. package/lib/pages/ListPageProps.js +1 -0
  153. package/lib/pages/ResponsivePage.d.ts +9 -0
  154. package/lib/pages/ResponsivePage.js +45 -0
  155. package/lib/pages/ResponsivePageProps.d.ts +39 -0
  156. package/lib/pages/ResponsivePageProps.js +1 -0
  157. package/lib/pages/SearchPageProps.d.ts +30 -0
  158. package/lib/pages/SearchPageProps.js +1 -0
  159. package/lib/pages/TablePage.d.ts +9 -0
  160. package/lib/pages/TablePage.js +69 -0
  161. package/lib/pages/TablePageProps.d.ts +7 -0
  162. package/lib/pages/TablePageProps.js +1 -0
  163. package/lib/pages/ViewPage.d.ts +66 -0
  164. package/lib/pages/ViewPage.js +105 -0
  165. package/lib/texts/DateText.d.ts +34 -0
  166. package/lib/texts/DateText.js +25 -0
  167. package/lib/texts/MoneyText.d.ts +21 -0
  168. package/lib/texts/MoneyText.js +14 -0
  169. package/lib/texts/NumberText.d.ts +25 -0
  170. package/lib/texts/NumberText.js +14 -0
  171. package/package.json +97 -0
  172. package/src/AuditDisplay.tsx +114 -0
  173. package/src/AutocompleteExtendedProps.ts +83 -0
  174. package/src/BackButton.tsx +55 -0
  175. package/src/BridgeCloseButton.tsx +69 -0
  176. package/src/ButtonLink.tsx +32 -0
  177. package/src/ComboBox.tsx +251 -0
  178. package/src/CountdownButton.tsx +119 -0
  179. package/src/CustomFabProps.ts +32 -0
  180. package/src/DataGridEx.tsx +713 -0
  181. package/src/DataGridRenderers.tsx +140 -0
  182. package/src/DialogButton.tsx +163 -0
  183. package/src/DnDList.tsx +344 -0
  184. package/src/DraggablePaperComponent.tsx +19 -0
  185. package/src/EmailInput.tsx +24 -0
  186. package/src/FabBox.tsx +51 -0
  187. package/src/FlexBox.tsx +20 -0
  188. package/src/GridDataFormat.tsx +77 -0
  189. package/src/IconButtonLink.tsx +29 -0
  190. package/src/InputField.tsx +82 -0
  191. package/src/ItemList.tsx +204 -0
  192. package/src/ListItemRightIcon.tsx +9 -0
  193. package/src/ListMoreDisplay.tsx +205 -0
  194. package/src/LoadingButton.tsx +75 -0
  195. package/src/MUGlobal.ts +220 -0
  196. package/src/MaskInput.tsx +107 -0
  197. package/src/MobileListItemRenderer.tsx +79 -0
  198. package/src/MoreFab.tsx +211 -0
  199. package/src/NotifierMU.tsx +654 -0
  200. package/src/NotifierPromptProps.ts +24 -0
  201. package/src/OptionGroup.tsx +223 -0
  202. package/src/PList.tsx +27 -0
  203. package/src/ProgressCount.tsx +166 -0
  204. package/src/PullToRefreshUI.tsx +21 -0
  205. package/src/RLink.tsx +64 -0
  206. package/src/ResponsibleContainer.tsx +394 -0
  207. package/src/ScrollTopFab.tsx +34 -0
  208. package/src/ScrollerListEx.tsx +387 -0
  209. package/src/SearchBar.tsx +396 -0
  210. package/src/SearchField.tsx +82 -0
  211. package/src/SearchOptionGroup.tsx +31 -0
  212. package/src/SelectBool.tsx +33 -0
  213. package/src/SelectEx.tsx +290 -0
  214. package/src/ShowDataComparison.tsx +106 -0
  215. package/src/Switch.tsx +94 -0
  216. package/src/SwitchAnt.tsx +95 -0
  217. package/src/TabBox.tsx +118 -0
  218. package/src/TableEx.tsx +558 -0
  219. package/src/TextFieldEx.tsx +249 -0
  220. package/src/Tiplist.tsx +303 -0
  221. package/src/TooltipClick.tsx +84 -0
  222. package/src/UserAvatar.tsx +64 -0
  223. package/src/UserAvatarEditor.tsx +287 -0
  224. package/src/app/CommonApp.ts +223 -0
  225. package/src/app/IServiceAppSettings.ts +13 -0
  226. package/src/app/IServicePage.ts +6 -0
  227. package/src/app/IServiceUser.ts +17 -0
  228. package/src/app/ISmartERPUser.ts +16 -0
  229. package/src/app/Labels.ts +77 -0
  230. package/src/app/ReactApp.ts +504 -0
  231. package/src/app/ServiceApp.ts +352 -0
  232. package/src/index.ts +77 -0
  233. package/src/pages/CommonPage.tsx +128 -0
  234. package/src/pages/CommonPageProps.ts +70 -0
  235. package/src/pages/DataGridPage.tsx +140 -0
  236. package/src/pages/DataGridPageProps.ts +24 -0
  237. package/src/pages/EditPage.tsx +114 -0
  238. package/src/pages/FixedListPage.tsx +141 -0
  239. package/src/pages/ListPage.tsx +90 -0
  240. package/src/pages/ListPageProps.ts +12 -0
  241. package/src/pages/ResponsivePage.tsx +68 -0
  242. package/src/pages/ResponsivePageProps.ts +57 -0
  243. package/src/pages/SearchPageProps.ts +39 -0
  244. package/src/pages/TablePage.tsx +126 -0
  245. package/src/pages/TablePageProps.ts +12 -0
  246. package/src/pages/ViewPage.tsx +282 -0
  247. package/src/texts/DateText.tsx +74 -0
  248. package/src/texts/MoneyText.tsx +49 -0
  249. package/src/texts/NumberText.tsx +40 -0
  250. package/tsconfig.json +19 -0
@@ -0,0 +1,287 @@
1
+ import { Button, ButtonGroup, Slider, Stack } from '@mui/material';
2
+ import React from 'react';
3
+ import AvatarEditor from 'react-avatar-editor';
4
+ import RotateLeftIcon from '@mui/icons-material/RotateLeft';
5
+ import RotateRightIcon from '@mui/icons-material/RotateRight';
6
+ import ClearAllIcon from '@mui/icons-material/ClearAll';
7
+ import ComputerIcon from '@mui/icons-material/Computer';
8
+ import DoneIcon from '@mui/icons-material/Done';
9
+ import pica from 'pica';
10
+ import { Labels } from './app/Labels';
11
+
12
+ /**
13
+ * User avatar editor to Blob helper
14
+ */
15
+ export interface UserAvatarEditorToBlob {
16
+ (
17
+ canvas: HTMLCanvasElement,
18
+ mimeType?: string,
19
+ quality?: number
20
+ ): Promise<Blob>;
21
+ }
22
+
23
+ /**
24
+ * User avatar editor on done handler
25
+ */
26
+ export interface UserAvatarEditorOnDoneHandler {
27
+ (canvas: HTMLCanvasElement, toBlob: UserAvatarEditorToBlob): void;
28
+ }
29
+
30
+ /**
31
+ * User avatar editor props
32
+ */
33
+ export interface UserAvatarEditorProps {
34
+ /**
35
+ * Cropping border size
36
+ */
37
+ border?: number;
38
+
39
+ /**
40
+ * Image source
41
+ */
42
+ image?: string | File;
43
+
44
+ /**
45
+ * Max width to save
46
+ */
47
+ maxWidth?: number;
48
+
49
+ /**
50
+ * On done handler
51
+ */
52
+ onDone: UserAvatarEditorOnDoneHandler;
53
+
54
+ /**
55
+ * Return scaled result?
56
+ */
57
+ scaledResult?: boolean;
58
+
59
+ /**
60
+ * Width of the editor
61
+ */
62
+ width?: number;
63
+
64
+ /**
65
+ * Height of the editor
66
+ */
67
+ height?: number;
68
+ }
69
+
70
+ interface EditorState {
71
+ scale: number;
72
+ rotate: number;
73
+ }
74
+
75
+ const defaultState: EditorState = {
76
+ scale: 1,
77
+ rotate: 0
78
+ };
79
+
80
+ /**
81
+ * User avatar editor
82
+ * https://github.com/mosch/react-avatar-editor
83
+ * @param props Props
84
+ * @returns Component
85
+ */
86
+ export function UserAvatarEditor(props: UserAvatarEditorProps) {
87
+ // Destruct
88
+ const {
89
+ border = 30,
90
+ image,
91
+ maxWidth,
92
+ onDone,
93
+ scaledResult = false,
94
+ width = 200,
95
+ height = 200
96
+ } = props;
97
+
98
+ // Container width
99
+ const containerWidth = width + 2 * border + 44 + 4;
100
+
101
+ // Calculated max width
102
+ const maxWidthCalculated =
103
+ maxWidth == null || maxWidth < 200 ? 3 * width : maxWidth;
104
+
105
+ // Labels
106
+ const labels = Labels.UserAvatarEditor;
107
+
108
+ // Ref
109
+ const ref = React.createRef<AvatarEditor>();
110
+
111
+ // Button ref
112
+ const buttonRef = React.createRef<HTMLButtonElement>();
113
+
114
+ // Preview image state
115
+ const [previewImage, setPreviewImage] = React.useState(image);
116
+
117
+ // Is ready state
118
+ const [ready, setReady] = React.useState(false);
119
+
120
+ // Editor states
121
+ const [editorState, setEditorState] = React.useState(defaultState);
122
+
123
+ // Handle zoom
124
+ const handleZoom = (
125
+ _event: Event,
126
+ value: number | number[],
127
+ _activeThumb: number
128
+ ) => {
129
+ const scale = typeof value === 'number' ? value : value[0];
130
+ const newState = { ...editorState, scale };
131
+ setEditorState(newState);
132
+ };
133
+
134
+ // Handle image load
135
+ const handleLoad = () => {
136
+ setReady(true);
137
+ };
138
+
139
+ // Handle file change
140
+ const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
141
+ const files = event.target.files;
142
+ if (files == null || files.length == 0) return;
143
+
144
+ // Reset all settings
145
+ handleReset();
146
+
147
+ // Set new preview image
148
+ setPreviewImage(files[0]);
149
+
150
+ // Set ready state
151
+ setReady(false);
152
+
153
+ // Make the submit button visible
154
+ buttonRef.current?.scrollIntoView(false);
155
+ };
156
+
157
+ // Handle reset
158
+ const handleReset = () => {
159
+ setEditorState({ ...defaultState });
160
+ };
161
+
162
+ // Handle rotate
163
+ const handleRotate = (r: number) => {
164
+ let rotate = editorState.rotate + r;
165
+ if (rotate >= 360 || rotate <= -360) rotate = 0;
166
+
167
+ const newState = { ...editorState, rotate };
168
+ setEditorState(newState);
169
+ };
170
+
171
+ // Handle done
172
+ const handleDone = () => {
173
+ // Data
174
+ var data = scaledResult
175
+ ? ref.current?.getImageScaledToCanvas()
176
+ : ref.current?.getImage();
177
+ if (data == null) return;
178
+
179
+ // pica
180
+ const picaInstance = pica();
181
+
182
+ // toBlob helper
183
+ // Convenience method, similar to canvas.toBlob(), but with promise interface & polyfill for old browsers.
184
+ const toBlob = (
185
+ canvas: HTMLCanvasElement,
186
+ mimeType: string = 'image/jpeg',
187
+ quality: number = 1
188
+ ) => {
189
+ return picaInstance.toBlob(canvas, mimeType, quality);
190
+ };
191
+
192
+ if (data.width > maxWidthCalculated) {
193
+ // Target height
194
+ const heightCalculated = (height * maxWidthCalculated) / width;
195
+
196
+ // Target
197
+ const to = document.createElement('canvas');
198
+ to.width = maxWidthCalculated;
199
+ to.height = heightCalculated;
200
+
201
+ // Large photo, resize it
202
+ // https://github.com/nodeca/pica
203
+ picaInstance
204
+ .resize(data, to, {
205
+ unsharpAmount: 160,
206
+ unsharpRadius: 0.6,
207
+ unsharpThreshold: 1
208
+ })
209
+ .then((result) => onDone(result, toBlob));
210
+ } else {
211
+ onDone(data, toBlob);
212
+ }
213
+ };
214
+
215
+ return (
216
+ <Stack direction="column" spacing={0.5} width={containerWidth}>
217
+ <Button
218
+ variant="outlined"
219
+ size="medium"
220
+ component="label"
221
+ startIcon={<ComputerIcon />}
222
+ fullWidth
223
+ >
224
+ {labels.upload}
225
+ <input
226
+ id="fileInput"
227
+ type="file"
228
+ accept="image/png, image/jpeg"
229
+ multiple={false}
230
+ hidden
231
+ onChange={handleFileChange}
232
+ />
233
+ </Button>
234
+ <Stack direction="row" spacing={0.5}>
235
+ <AvatarEditor
236
+ ref={ref}
237
+ border={border}
238
+ width={width}
239
+ height={height}
240
+ onLoadSuccess={handleLoad}
241
+ image={previewImage ?? ''}
242
+ scale={editorState.scale}
243
+ rotate={editorState.rotate}
244
+ />
245
+ <ButtonGroup
246
+ size="small"
247
+ orientation="vertical"
248
+ disabled={!ready}
249
+ >
250
+ <Button
251
+ onClick={() => handleRotate(90)}
252
+ title={labels.rotateRight}
253
+ >
254
+ <RotateRightIcon />
255
+ </Button>
256
+ <Button
257
+ onClick={() => handleRotate(-90)}
258
+ title={labels.rotateLeft}
259
+ >
260
+ <RotateLeftIcon />
261
+ </Button>
262
+ <Button onClick={handleReset} title={labels.reset}>
263
+ <ClearAllIcon />
264
+ </Button>
265
+ </ButtonGroup>
266
+ </Stack>
267
+ <Slider
268
+ title={labels.zoom}
269
+ disabled={!ready}
270
+ min={1}
271
+ max={5}
272
+ step={0.01}
273
+ value={editorState.scale}
274
+ onChange={handleZoom}
275
+ />
276
+ <Button
277
+ ref={buttonRef}
278
+ variant="contained"
279
+ startIcon={<DoneIcon />}
280
+ disabled={!ready}
281
+ onClick={handleDone}
282
+ >
283
+ {labels.done}
284
+ </Button>
285
+ </Stack>
286
+ );
287
+ }
@@ -0,0 +1,223 @@
1
+ import {
2
+ IActionResult,
3
+ IApiPayload,
4
+ IAppSettings,
5
+ IUser,
6
+ RefreshTokenProps,
7
+ RefreshTokenResult
8
+ } from '@etsoo/appscript';
9
+ import { CoreConstants, IPageData, RefreshTokenRQ } from '@etsoo/react';
10
+ import { ReactApp } from './ReactApp';
11
+
12
+ /**
13
+ * Common independent application
14
+ * 通用独立程序
15
+ */
16
+ export abstract class CommonApp<
17
+ U extends IUser = IUser,
18
+ P extends IPageData = IPageData,
19
+ S extends IAppSettings = IAppSettings
20
+ > extends ReactApp<S, U, P> {
21
+ /**
22
+ * Override persistedFields
23
+ */
24
+ protected override get persistedFields() {
25
+ return [...super.persistedFields, CoreConstants.FieldUserIdSaved];
26
+ }
27
+
28
+ /**
29
+ * Init call update fields in local storage
30
+ * @returns Fields
31
+ */
32
+ protected override initCallEncryptedUpdateFields(): string[] {
33
+ const fields = super.initCallEncryptedUpdateFields();
34
+ fields.push(CoreConstants.FieldUserIdSaved);
35
+ return fields;
36
+ }
37
+
38
+ /**
39
+ * Do user login
40
+ * @param data User data
41
+ * @param refreshToken Refresh token
42
+ * @param keep Keep login
43
+ * @returns Success data
44
+ */
45
+ protected doUserLogin(
46
+ data: U,
47
+ refreshToken: string,
48
+ keep: boolean
49
+ ): string | undefined {
50
+ this.userLogin(data, refreshToken, keep);
51
+ return undefined;
52
+ }
53
+
54
+ /**
55
+ * Refresh token
56
+ * @param props Props
57
+ */
58
+ override async refreshToken<D extends object = RefreshTokenRQ>(
59
+ props?: RefreshTokenProps<D>
60
+ ) {
61
+ // Destruct
62
+ const {
63
+ callback,
64
+ data,
65
+ relogin = false,
66
+ showLoading = false
67
+ } = props ?? {};
68
+
69
+ // Token
70
+ const token = this.getCacheToken();
71
+ if (token == null || token === '') {
72
+ if (callback) callback(false);
73
+ return false;
74
+ }
75
+
76
+ // Reqest data
77
+ const rq: RefreshTokenRQ = {
78
+ deviceId: this.deviceId,
79
+ timezone: this.getTimeZone(),
80
+ ...data
81
+ };
82
+
83
+ // Login result type
84
+ type LoginResult = IActionResult<U>;
85
+
86
+ // Payload
87
+ const payload: IApiPayload<LoginResult, any> = {
88
+ // No loading bar needed to avoid screen flicks
89
+ showLoading,
90
+ config: { headers: { [CoreConstants.TokenHeaderRefresh]: token } },
91
+ onError: (error) => {
92
+ if (callback) callback(error);
93
+
94
+ // Prevent further processing
95
+ return false;
96
+ }
97
+ };
98
+
99
+ // Success callback
100
+ const success = (
101
+ result: LoginResult,
102
+ failCallback?: (
103
+ result: RefreshTokenResult,
104
+ serviceToken?: string
105
+ ) => void
106
+ ) => {
107
+ // Token
108
+ const refreshToken = this.getResponseToken(payload.response);
109
+ if (refreshToken == null || result.data == null) {
110
+ if (failCallback) failCallback(this.get('noData')!);
111
+ return false;
112
+ }
113
+
114
+ // Keep
115
+ const keep = this.storage.getData(
116
+ CoreConstants.FieldLoginKeep,
117
+ false
118
+ );
119
+
120
+ // User login
121
+ var successData = this.doUserLogin(result.data, refreshToken, keep);
122
+
123
+ // Callback
124
+ if (failCallback) failCallback(true, successData);
125
+
126
+ return true;
127
+ };
128
+
129
+ // Call API
130
+ const result = await this.api.put<LoginResult>(
131
+ 'Auth/RefreshToken',
132
+ rq,
133
+ payload
134
+ );
135
+
136
+ if (result == null) return false;
137
+
138
+ if (!result.ok) {
139
+ if (result.type === 'TokenExpired' && relogin) {
140
+ // Try login
141
+ // Dialog to receive password
142
+ var labels = this.getLabels('reloginTip', 'login');
143
+ this.notifier.prompt(
144
+ labels.reloginTip,
145
+ async (pwd) => {
146
+ if (pwd == null) {
147
+ this.toLoginPage();
148
+ return;
149
+ }
150
+
151
+ // Set password for the action
152
+ rq.pwd = this.encrypt(this.hash(pwd));
153
+
154
+ // Submit again
155
+ const result = await this.api.put<LoginResult>(
156
+ 'Auth/RefreshToken',
157
+ rq,
158
+ payload
159
+ );
160
+
161
+ if (result == null) return;
162
+
163
+ if (result.ok) {
164
+ success(
165
+ result,
166
+ (loginResult: RefreshTokenResult) => {
167
+ if (loginResult === true) {
168
+ if (callback) callback(true);
169
+ return;
170
+ }
171
+
172
+ const message =
173
+ this.formatRefreshTokenResult(
174
+ loginResult
175
+ );
176
+ if (message) this.notifier.alert(message);
177
+ }
178
+ );
179
+ return;
180
+ }
181
+
182
+ // Popup message
183
+ this.alertResult(result);
184
+ return false;
185
+ },
186
+ labels.login,
187
+ { type: 'password' }
188
+ );
189
+
190
+ // Fake truth to avoid reloading
191
+ return true;
192
+ }
193
+
194
+ if (callback) callback(result);
195
+ return false;
196
+ }
197
+
198
+ return success(result, callback);
199
+ }
200
+
201
+ /**
202
+ * Try login
203
+ * @param data Additional data
204
+ * @param showLoading Show loading bar or not
205
+ * @returns Result
206
+ */
207
+ override async tryLogin<D extends object = RefreshTokenRQ>(
208
+ data?: D,
209
+ showLoading?: boolean
210
+ ) {
211
+ // Reset user state
212
+ const result = await super.tryLogin(data);
213
+ if (!result) return false;
214
+
215
+ // Refresh token
216
+ return await this.refreshToken({
217
+ callback: (result) => this.doRefreshTokenResult(result),
218
+ data,
219
+ showLoading,
220
+ relogin: true
221
+ });
222
+ }
223
+ }
@@ -0,0 +1,13 @@
1
+ import { IAppSettings } from '@etsoo/appscript';
2
+ import { DataTypes } from '@etsoo/shared';
3
+
4
+ /**
5
+ * Service app settings interface
6
+ */
7
+ export interface IServiceAppSettings<S extends DataTypes.IdType = number>
8
+ extends IAppSettings {
9
+ /**
10
+ * Service id
11
+ */
12
+ readonly serviceId: S;
13
+ }
@@ -0,0 +1,6 @@
1
+ import { IPageData } from '@etsoo/react';
2
+
3
+ /**
4
+ * Service page data interface
5
+ */
6
+ export interface IServicePageData extends IPageData {}
@@ -0,0 +1,17 @@
1
+ import { IActionResult, IUser } from '@etsoo/appscript';
2
+
3
+ /**
4
+ * Service user interface
5
+ */
6
+ export interface IServiceUser extends IUser {
7
+ /**
8
+ * Service device id
9
+ */
10
+ serviceDeviceId: string;
11
+ }
12
+
13
+ /**
14
+ * Service user login result
15
+ */
16
+ export type ServiceLoginResult<U extends IServiceUser = IServiceUser> =
17
+ IActionResult<U>;
@@ -0,0 +1,16 @@
1
+ import { IActionResult, IUser } from '@etsoo/appscript';
2
+
3
+ /**
4
+ * SmartERP user interface
5
+ */
6
+ export interface ISmartERPUser extends IUser {
7
+ /**
8
+ * Service refresh token
9
+ */
10
+ readonly serviceToken?: string;
11
+ }
12
+
13
+ /**
14
+ * SmartERP user login result
15
+ */
16
+ export type SmartERPLoginResult = IActionResult<ISmartERPUser>;
@@ -0,0 +1,77 @@
1
+ import { DataTypes, Utils } from '@etsoo/shared';
2
+
3
+ /**
4
+ * Labels
5
+ */
6
+ export namespace Labels {
7
+ /**
8
+ * Common page labels
9
+ */
10
+ export const CommonPage = {
11
+ add: 'Add',
12
+ back: 'Back',
13
+ delete: 'Delete',
14
+ more: 'More',
15
+ pullToRefresh: 'Pull down to refresh',
16
+ refresh: 'Refresh',
17
+ refreshing: 'Refreshing',
18
+ releaseToRefresh: 'Release to refresh',
19
+ reset: 'Reset',
20
+ save: 'Save',
21
+ scrollTop: 'Scroll to top',
22
+ submit: 'Submit'
23
+ };
24
+
25
+ /**
26
+ * Notification MU labels
27
+ */
28
+ export const NotificationMU = {
29
+ alertTitle: 'Warning',
30
+ alertOK: 'OK',
31
+ confirmTitle: 'Confirm',
32
+ confirmYes: 'OK',
33
+ confirmNo: 'Cancel',
34
+ promptTitle: 'Input',
35
+ promptCancel: 'Cancel',
36
+ promptOK: 'OK',
37
+ loading: 'Loading',
38
+ success: 'Success',
39
+ warning: 'Warning',
40
+ info: 'Information'
41
+ };
42
+
43
+ /**
44
+ * UserAvatarEditor labels
45
+ */
46
+ export const UserAvatarEditor = {
47
+ done: 'Done',
48
+ reset: 'Reset',
49
+ rotateLeft: 'Rotate left 90°',
50
+ rotateRight: 'Rotate right 90°',
51
+ upload: 'Upload',
52
+ zoom: 'Zoom'
53
+ };
54
+
55
+ /**
56
+ * setLabelReference key reference
57
+ */
58
+ export interface setLabelsReference {
59
+ commonPage?: DataTypes.StringDictionary;
60
+ notificationMU?: DataTypes.StringDictionary;
61
+ userAvatarEditor?: DataTypes.StringDictionary;
62
+ }
63
+
64
+ /**
65
+ * Set components' labels
66
+ * @param labels Labels
67
+ * @param reference Key reference
68
+ */
69
+ export const setLabels = (
70
+ labels: DataTypes.StringRecord,
71
+ reference: setLabelsReference = {}
72
+ ) => {
73
+ Utils.setLabels(CommonPage, labels, reference.commonPage);
74
+ Utils.setLabels(NotificationMU, labels, reference.notificationMU);
75
+ Utils.setLabels(UserAvatarEditor, labels, reference.userAvatarEditor);
76
+ };
77
+ }