dce-reactkit 2.0.9 → 2.0.12

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 (48) hide show
  1. package/lib/components/AppWrapper.d.ts +16 -1
  2. package/lib/components/AppWrapper.js +157 -13
  3. package/lib/components/AppWrapper.js.map +1 -1
  4. package/lib/components/Modal.d.ts +2 -0
  5. package/lib/components/Modal.js +9 -3
  6. package/lib/components/Modal.js.map +1 -1
  7. package/lib/components/TabBox.d.ts +11 -0
  8. package/lib/components/TabBox.js +42 -0
  9. package/lib/components/TabBox.js.map +1 -0
  10. package/lib/helpers/alert.d.ts +2 -0
  11. package/lib/helpers/alert.js +6 -0
  12. package/lib/helpers/alert.js.map +1 -0
  13. package/lib/helpers/confirm.d.ts +2 -0
  14. package/lib/helpers/confirm.js +6 -0
  15. package/lib/helpers/confirm.js.map +1 -0
  16. package/lib/helpers/showFatalError.d.ts +1 -1
  17. package/lib/helpers/showFatalError.js +2 -1
  18. package/lib/helpers/showFatalError.js.map +1 -1
  19. package/package.json +1 -1
  20. package/src/components/AppWrapper.tsx +191 -11
  21. package/src/components/Modal.tsx +16 -2
  22. package/src/components/TabBox.tsx +136 -0
  23. package/src/helpers/alert.tsx +5 -0
  24. package/src/helpers/confirm.tsx +5 -0
  25. package/src/helpers/showFatalError.tsx +3 -1
  26. package/lib/components/AppWrapper.tsx +0 -181
  27. package/lib/components/ErrorBox.tsx +0 -124
  28. package/lib/components/LoadingSpinner.tsx +0 -105
  29. package/lib/components/Modal.tsx +0 -447
  30. package/lib/errors/ErrorWithCode.tsx +0 -15
  31. package/lib/helpers/abbreviate.tsx +0 -23
  32. package/lib/helpers/avg.tsx +0 -22
  33. package/lib/helpers/ceilToNumDecimals.tsx +0 -13
  34. package/lib/helpers/floorToNumDecimals.tsx +0 -13
  35. package/lib/helpers/forceNumIntoBounds.tsx +0 -19
  36. package/lib/helpers/handleError.ts +0 -65
  37. package/lib/helpers/handleSuccess.ts +0 -18
  38. package/lib/helpers/padDecimalZeros.tsx +0 -32
  39. package/lib/helpers/padZerosLeft.tsx +0 -21
  40. package/lib/helpers/parseRequest.ts +0 -299
  41. package/lib/helpers/roundToNumDecimals.tsx +0 -13
  42. package/lib/helpers/showFatalError.tsx +0 -3
  43. package/lib/helpers/sum.tsx +0 -16
  44. package/lib/helpers/visitServerEndpoint.tsx +0 -110
  45. package/lib/helpers/waitMs.tsx +0 -12
  46. package/lib/types/ParamType.ts +0 -18
  47. package/lib/types/ReactKitErrorCode.tsx +0 -16
  48. package/lib/types/Variant.tsx +0 -16
@@ -16,6 +16,9 @@ import { setSessionExpiryHandler } from '../helpers/visitServerEndpoint';
16
16
  // Import shared types
17
17
  import ReactKitErrorCode from '../types/ReactKitErrorCode';
18
18
 
19
+ // Import shared components
20
+ import Modal from './Modal';
21
+
19
22
  // Import custom errors
20
23
  import ErrorWithCode from '../errors/ErrorWithCode';
21
24
 
@@ -36,6 +39,84 @@ type Props = {
36
39
  /* Static Helpers */
37
40
  /*------------------------------------------------------------------------*/
38
41
 
42
+ /*----------------------------------------*/
43
+ /* Alert */
44
+ /*----------------------------------------*/
45
+
46
+ // Stored copies of setters
47
+ let setAlertInfo: (info: { title: string, text: string }) => void;
48
+ let onAlertClosed: () => void;
49
+
50
+ /**
51
+ * Show an alert modal with an "Okay" button
52
+ * @author Gabe Abrams
53
+ * @param title the title text to display at the top of the alert
54
+ * @param text the text to display in the alert
55
+ */
56
+ export const _alert = async (title: string, text: string) => {
57
+ // Fallback if alert not available
58
+ if (!setAlertInfo) {
59
+ return window.alert(`${title}\n\n${text}`);
60
+ }
61
+
62
+ // Return promise that resolves when alert is closed
63
+ return new Promise((resolve) => {
64
+ // Setup handler
65
+ onAlertClosed = () => {
66
+ resolve(null);
67
+ };
68
+
69
+ // Show the alert
70
+ setAlertInfo({
71
+ title,
72
+ text,
73
+ });
74
+ });
75
+ };
76
+
77
+ /*----------------------------------------*/
78
+ /* Confirm */
79
+ /*----------------------------------------*/
80
+
81
+ // Stored copies of setters
82
+ let setConfirmInfo: (info: { title: string, text: string }) => void;
83
+ let onConfirmClosed: (confirmed: boolean) => void;
84
+
85
+ /**
86
+ * Show a confirmation modal with an "Okay" and a "Cancel" button
87
+ * @author Gabe Abrams
88
+ * @param title the title text to display at the top of the alert
89
+ * @param text the text to display in the alert
90
+ * @returns true if the user confirmed
91
+ */
92
+ export const _confirm = async (
93
+ title: string,
94
+ text: string,
95
+ ): Promise<boolean> => {
96
+ // Fallback if confirm is not available
97
+ if (!setConfirmInfo) {
98
+ return window.confirm(`${title}\n\n${text}`);
99
+ }
100
+
101
+ // Return promise that resolves with result of confirmation
102
+ return new Promise((resolve) => {
103
+ // Setup handler
104
+ onConfirmClosed = (confirmed: boolean) => {
105
+ resolve(confirmed)
106
+ };
107
+
108
+ // Show the confirm
109
+ setConfirmInfo({
110
+ title,
111
+ text,
112
+ });
113
+ });
114
+ };
115
+
116
+ /*----------------------------------------*/
117
+ /* Fatal Error */
118
+ /*----------------------------------------*/
119
+
39
120
  // Stored copies of setters
40
121
  let setFatalErrorMessage: (message: string) => void;
41
122
  let setFatalErrorCode: (code: string) => void;
@@ -47,7 +128,7 @@ let setFatalErrorTitle: (title: string) => void;
47
128
  * @param error the error to show
48
129
  * @param [errorTitle] title of the error box
49
130
  */
50
- export const showFatalError = (
131
+ export const _showFatalError = (
51
132
  error: any,
52
133
  errorTitle: string = 'An Error Occurred',
53
134
  ) => {
@@ -65,7 +146,10 @@ export const showFatalError = (
65
146
 
66
147
  // Handle case where app hasn't loaded
67
148
  if (!setFatalErrorMessage || !setFatalErrorCode) {
68
- return alert(`An error has occurred: ${message} (code: ${code}). Please contact support.`);
149
+ return _alert(
150
+ errorTitle,
151
+ `${message} (code: ${code}). Please contact support.`,
152
+ );
69
153
  }
70
154
 
71
155
  // Use setters
@@ -94,15 +178,47 @@ const AppWrapper = (props: Props): React.ReactElement => {
94
178
  /* -------------- State ------------- */
95
179
 
96
180
  // Fatal error
97
- const [fatalErrorMessage, setFatalErrorMessageInner] = useState(null);
181
+ const [
182
+ fatalErrorMessage,
183
+ setFatalErrorMessageInner,
184
+ ] = useState<string | undefined>();
98
185
  setFatalErrorMessage = setFatalErrorMessageInner;
99
- const [fatalErrorCode, setFatalErrorCodeInner] = useState(null);
186
+ const [
187
+ fatalErrorCode,
188
+ setFatalErrorCodeInner,
189
+ ] = useState<string | undefined>();
100
190
  setFatalErrorCode = setFatalErrorCodeInner;
101
- const [fatalErrorTitle, setFatalErrorTitleInner] = useState(null);
191
+ const [
192
+ fatalErrorTitle,
193
+ setFatalErrorTitleInner,
194
+ ] = useState<string | undefined>();
102
195
  setFatalErrorTitle = setFatalErrorTitleInner;
103
196
 
197
+ // Alert
198
+ const [
199
+ alertInfo,
200
+ setAlertInfoInner,
201
+ ] = useState<{
202
+ title: string,
203
+ text: string
204
+ }>();
205
+ setAlertInfo = setAlertInfoInner;
206
+
207
+ // Confirm
208
+ const [
209
+ confirmInfo,
210
+ setConfirmInfoInner,
211
+ ] = useState<{
212
+ title: string,
213
+ text: string
214
+ }>();
215
+ setConfirmInfo = setConfirmInfoInner;
216
+
104
217
  // Session expired
105
- const [sessionHasExpired, setSessionHasExpired] = useState(false);
218
+ const [
219
+ sessionHasExpired,
220
+ setSessionHasExpired,
221
+ ] = useState<boolean>(false);
106
222
 
107
223
  /*------------------------------------------------------------------------*/
108
224
  /* Lifecycle Functions */
@@ -128,10 +244,60 @@ const AppWrapper = (props: Props): React.ReactElement => {
128
244
  /*------------------------------------------------------------------------*/
129
245
 
130
246
  /*----------------------------------------*/
131
- /* Main UI */
247
+ /* Modal */
248
+ /*----------------------------------------*/
249
+
250
+ // Modal that may be defined
251
+ let modal: React.ReactNode;
252
+
253
+ /* -------------- Alert ------------- */
254
+
255
+ if (alertInfo) {
256
+ modal = (
257
+ <Modal
258
+ title={alertInfo.title}
259
+ type={Modal.ModalType.Okay}
260
+ onClose={() => {
261
+ // Alert closed
262
+ if (onAlertClosed) {
263
+ onAlertClosed();
264
+ }
265
+ }}
266
+ onTopOfOtherModals
267
+ >
268
+ {alertInfo.text}
269
+ </Modal>
270
+ );
271
+ }
272
+
273
+ /* ------------- Confirm ------------ */
274
+
275
+ if (confirmInfo) {
276
+ modal = (
277
+ <Modal
278
+ title={confirmInfo.title}
279
+ type={Modal.ModalType.OkayCancel}
280
+ onClose={(buttonType) => {
281
+ if (onConfirmClosed) {
282
+ onConfirmClosed(buttonType === Modal.ButtonType.Okay);
283
+ }
284
+ }}
285
+ dontAllowBackdropExit
286
+ >
287
+
288
+ </Modal>
289
+ );
290
+ }
291
+
292
+ /*----------------------------------------*/
293
+ /* Views */
132
294
  /*----------------------------------------*/
133
295
 
134
- // Show error
296
+ // Body that will be filled with the current view
297
+ let body: React.ReactNode;
298
+
299
+ /* ----------- Fatal Error ---------- */
300
+
135
301
  if (fatalErrorMessage || fatalErrorCode || sessionHasExpired) {
136
302
  // Re-encapsulate in an error
137
303
  const error = (
@@ -147,7 +313,7 @@ const AppWrapper = (props: Props): React.ReactElement => {
147
313
  );
148
314
 
149
315
  // Build error screen
150
- return (
316
+ body = (
151
317
  <div
152
318
  style={{
153
319
  display: 'block',
@@ -173,10 +339,24 @@ const AppWrapper = (props: Props): React.ReactElement => {
173
339
  );
174
340
  }
175
341
 
176
- // Show the app itself
342
+ /* --------------- App -------------- */
343
+
344
+ if (!body) {
345
+ body = (
346
+ <>
347
+ {children}
348
+ </>
349
+ );
350
+ }
351
+
352
+ /*----------------------------------------*/
353
+ /* Main UI */
354
+ /*----------------------------------------*/
355
+
177
356
  return (
178
357
  <>
179
- {children}
358
+ {modal}
359
+ {body}
180
360
  </>
181
361
  );
182
362
  };
@@ -209,6 +209,8 @@ type Props = {
209
209
  children?: React.ReactNode,
210
210
  // Handler to call when modal is closed (if excluded, not closable)
211
211
  onClose?: (type: ButtonType) => void,
212
+ // If true, don't allow the user to click the backdrop to exit
213
+ dontAllowBackdropExit?: boolean,
212
214
  // Custom label for "okay" button
213
215
  okayLabel?: string,
214
216
  // Custom variant for "okay" button
@@ -249,6 +251,8 @@ type Props = {
249
251
  confirmLabel?: string,
250
252
  // Custom variant for "confirm" button
251
253
  confirmVariant?: Variant,
254
+ // True if modal should be on top of other modals
255
+ onTopOfOtherModals?: boolean,
252
256
  };
253
257
 
254
258
  /*------------------------------------------------------------------------*/
@@ -276,6 +280,8 @@ const Modal: (
276
280
  title,
277
281
  children,
278
282
  onClose,
283
+ dontAllowBackdropExit,
284
+ onTopOfOtherModals,
279
285
  } = props;
280
286
 
281
287
  /* -------------- State ------------- */
@@ -404,9 +410,17 @@ const Modal: (
404
410
  show={visible}
405
411
  size={size !== ModalSize.Medium ? size : undefined}
406
412
  onHide={() => {
407
- handleClose(ButtonType.Cancel);
413
+ if (!dontAllowBackdropExit) {
414
+ handleClose(ButtonType.Cancel);
415
+ }
416
+ }}
417
+ style={{
418
+ zIndex: (
419
+ onTopOfOtherModals
420
+ ? 6000000000
421
+ : 5000000000
422
+ ),
408
423
  }}
409
- style={{ zIndex: 5000000000 }}
410
424
  backdropClassName="Modal-backdrop"
411
425
  centered
412
426
  >
@@ -0,0 +1,136 @@
1
+ /**
2
+ * A box with a tab on the top that holds buttons and other content
3
+ * @author Gabe Abrams
4
+ */
5
+
6
+ // Import React
7
+ import React from 'react';
8
+
9
+ /*------------------------------------------------------------------------*/
10
+ /* Types */
11
+ /*------------------------------------------------------------------------*/
12
+
13
+ type Props = {
14
+ // Title of the box
15
+ title: React.ReactNode,
16
+ // Children/contents inside the box
17
+ children: React.ReactNode,
18
+ };
19
+
20
+ /*------------------------------------------------------------------------*/
21
+ /* Style */
22
+ /*------------------------------------------------------------------------*/
23
+
24
+ const style = `
25
+ /* Tab Box */
26
+ .TabBox-box {
27
+ /* Light Border */
28
+ border: 2px solid #dedede;
29
+
30
+ /* Rounded Corners (except top-left) */
31
+ border-bottom-right-radius: 5px;
32
+ border-bottom-left-radius: 5px;
33
+ border-top-right-radius: 5px;
34
+
35
+ /* Very Light Gray Border */
36
+ background: #fdfdfd;
37
+
38
+ /* Align Contents on Left */
39
+ text-align: left;
40
+ }
41
+
42
+ /* Container for Title */
43
+ .TabBox-title-container {
44
+ /* Place on Left */
45
+ position: relative;
46
+ left: 0;
47
+ text-align: left;
48
+ }
49
+
50
+ /* Tab-style Title */
51
+ .TabBox-title {
52
+ /* Place so it Barely Overlaps the Box Border */
53
+ display: inline-block;
54
+ position: relative;
55
+ top: 2px; /* Gives Illusion that Border Doesn't Exist Below Tab */
56
+
57
+ /* Title-sized Font */
58
+ font-size: 25px;
59
+
60
+ /* Add Border on Top and Sides */
61
+ border-top: 2px solid #dedede;
62
+ border-left: 2px solid #dedede;
63
+ border-right: 2px solid #dedede;
64
+
65
+ /* Round the Top Corners */
66
+ border-top-left-radius: 5px;
67
+ border-top-right-radius: 5px;
68
+
69
+ /* Add Text Padding */
70
+ padding-left: 12px;
71
+ padding-right: 12px;
72
+
73
+ /* Match Background Color of Box */
74
+ background: #fdfdfd;
75
+ }
76
+
77
+ /* Make the TabBox's Children Appear Above Title if Overlap Occurs */
78
+ .TabBox-children {
79
+ position: relative;
80
+ z-index: 1;
81
+ }
82
+ `;
83
+
84
+ /*------------------------------------------------------------------------*/
85
+ /* Component */
86
+ /*------------------------------------------------------------------------*/
87
+
88
+ const TabBox: React.FC<Props> = (props) => {
89
+ /*------------------------------------------------------------------------*/
90
+ /* Setup */
91
+ /*------------------------------------------------------------------------*/
92
+
93
+ /* -------------- Props ------------- */
94
+
95
+ const {
96
+ title,
97
+ children,
98
+ } = props;
99
+
100
+ /*------------------------------------------------------------------------*/
101
+ /* Render */
102
+ /*------------------------------------------------------------------------*/
103
+
104
+ /*----------------------------------------*/
105
+ /* Main UI */
106
+ /*----------------------------------------*/
107
+
108
+ // Full UI
109
+ return (
110
+ <div>
111
+ {/* Style */}
112
+ <style>{style}</style>
113
+
114
+ {/* Title */}
115
+ <div className="TabBox-title-container">
116
+ <div className="TabBox-title">
117
+ {title}
118
+ </div>
119
+ </div>
120
+
121
+ {/* Contents */}
122
+ <div className="TabBox-box p-2">
123
+ <div className="TabBox-children">
124
+ {children}
125
+ </div>
126
+ </div>
127
+ </div>
128
+ );
129
+ };
130
+
131
+ /*------------------------------------------------------------------------*/
132
+ /* Wrap Up */
133
+ /*------------------------------------------------------------------------*/
134
+
135
+ // Export component
136
+ export default TabBox;
@@ -0,0 +1,5 @@
1
+ import { _alert } from '../components/AppWrapper';
2
+
3
+ const alert = _alert;
4
+
5
+ export default alert;
@@ -0,0 +1,5 @@
1
+ import { _confirm } from '../components/AppWrapper';
2
+
3
+ const confirm = _confirm;
4
+
5
+ export default confirm;
@@ -1,3 +1,5 @@
1
- import { showFatalError } from '../components/AppWrapper';
1
+ import { _showFatalError } from '../components/AppWrapper';
2
+
3
+ const showFatalError = _showFatalError;
2
4
 
3
5
  export default showFatalError;
@@ -1,181 +0,0 @@
1
- /**
2
- * A wrapper for the entire React app that adds global functionality like
3
- * handling for fatal error messages
4
- * @author Gabe Abrams
5
- */
6
-
7
- // Import React
8
- import React, { useState, useEffect } from 'react';
9
-
10
- // Import shared components
11
- import ErrorBox from './ErrorBox';
12
-
13
- // Import helpers
14
- import { setSessionExpiryHandler } from '../helpers/visitServerEndpoint';
15
-
16
- // Import shared types
17
- import ReactKitErrorCode from '../types/ReactKitErrorCode';
18
-
19
- // Import custom errors
20
- import ErrorWithCode from '../errors/ErrorWithCode';
21
-
22
- /*------------------------------------------------------------------------*/
23
- /* Props */
24
- /*------------------------------------------------------------------------*/
25
-
26
- type Props = {
27
- // The entire app
28
- children: React.ReactNode,
29
- // True if this app is a dark-themed app
30
- dark?: boolean,
31
- // Custom session expired message
32
- sessionExpiredMessage?: string,
33
- };
34
-
35
- /*------------------------------------------------------------------------*/
36
- /* Static Helpers */
37
- /*------------------------------------------------------------------------*/
38
-
39
- // Stored copies of setters
40
- let setFatalErrorMessage: (message: string) => void;
41
- let setFatalErrorCode: (code: string) => void;
42
-
43
- /**
44
- * Show a fatal error message
45
- * @author Gabe Abrams
46
- * @param error the error to show
47
- */
48
- export const showFatalError = (error: any) => {
49
- // Determine message and code
50
- const message: string = (
51
- typeof error === 'string'
52
- ? error.trim()
53
- : String(error.message ?? 'An unknown error occurred.')
54
- );
55
- const code: string = (
56
- typeof error === 'string'
57
- ? ReactKitErrorCode.NoCode
58
- : String(error.code ?? ReactKitErrorCode.NoCode)
59
- );
60
-
61
- // Handle case where app hasn't loaded
62
- if (!setFatalErrorMessage || !setFatalErrorCode) {
63
- return alert(`An error has occurred: ${message} (code: ${code}). Please contact support.`);
64
- }
65
-
66
- // Use setters
67
- setFatalErrorMessage(message);
68
- setFatalErrorCode(code);
69
- };
70
-
71
- /*------------------------------------------------------------------------*/
72
- /* Component */
73
- /*------------------------------------------------------------------------*/
74
-
75
- const AppWrapper = (props: Props): React.ReactElement => {
76
- /*------------------------------------------------------------------------*/
77
- /* Setup */
78
- /*------------------------------------------------------------------------*/
79
-
80
- /* -------------- Props ------------- */
81
-
82
- const {
83
- children,
84
- dark,
85
- sessionExpiredMessage = 'Your session has expired. Please go back to Canvas and start over.',
86
- } = props;
87
-
88
- /* -------------- State ------------- */
89
-
90
- // Fatal error
91
- const [fatalErrorMessage, setFatalErrorMessageInner] = useState(null);
92
- setFatalErrorMessage = setFatalErrorMessageInner;
93
- const [fatalErrorCode, setFatalErrorCodeInner] = useState(null);
94
- setFatalErrorCode = setFatalErrorCodeInner;
95
-
96
- // Session expired
97
- const [sessionHasExpired, setSessionHasExpired] = useState(false);
98
-
99
- /*------------------------------------------------------------------------*/
100
- /* Lifecycle Functions */
101
- /*------------------------------------------------------------------------*/
102
-
103
- /**
104
- * Mount
105
- * @author Gabe Abrams
106
- */
107
- useEffect(
108
- () => {
109
- // Add session expired handler
110
- setSessionExpiryHandler(() => {
111
- // Session expired!
112
- setSessionHasExpired(true);
113
- });
114
- },
115
- [],
116
- );
117
-
118
- /*------------------------------------------------------------------------*/
119
- /* Render */
120
- /*------------------------------------------------------------------------*/
121
-
122
- /*----------------------------------------*/
123
- /* Main UI */
124
- /*----------------------------------------*/
125
-
126
- // Show error
127
- if (fatalErrorMessage || fatalErrorCode || sessionHasExpired) {
128
- // Re-encapsulate in an error
129
- const error = (
130
- sessionHasExpired
131
- ? new ErrorWithCode(
132
- fatalErrorMessage,
133
- fatalErrorCode,
134
- )
135
- : new ErrorWithCode(
136
- sessionExpiredMessage,
137
- ReactKitErrorCode.SessionExpired,
138
- )
139
- );
140
-
141
- // Build error screen
142
- return (
143
- <div
144
- style={{
145
- display: 'block',
146
- width: '100vw',
147
- minHeight: '100vh',
148
- paddingTop: '10rem',
149
- backgroundColor: (
150
- dark
151
- ? '#222'
152
- : '#fff'
153
- ),
154
- }}
155
- >
156
- <ErrorBox
157
- title={(
158
- sessionHasExpired
159
- ? 'Session Expired'
160
- : undefined
161
- )}
162
- error={error}
163
- />
164
- </div>
165
- );
166
- }
167
-
168
- // Show the app itself
169
- return (
170
- <>
171
- {children}
172
- </>
173
- );
174
- };
175
-
176
- /*------------------------------------------------------------------------*/
177
- /* Wrap Up */
178
- /*------------------------------------------------------------------------*/
179
-
180
- // Export component
181
- export default AppWrapper;