dce-reactkit 3.1.14 → 3.1.15

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.
@@ -6,14 +6,16 @@ import ParamType from '../types/ParamType';
6
6
  * @param opts.paramTypes map containing the types for each parameter that is
7
7
  * included in the request (map: param name => type)
8
8
  * @param opts.handler function that processes the request
9
- * @param [opts.allowNotLoggedIn] if true, allow the user to not be logged
10
- * in (the user will be allowed to not have launched via LTI)
11
9
  * @returns express route handler that takes the following arguments:
12
- * params (map: param name => value), handleSuccess (function for handling
13
- * successful requests), handleError (function for handling failed requests),
14
- * req (express request object), redirect (a function that takes a url and
15
- * redirects the user to the url), and send (a function that sends a string
16
- * and optional http status code). Params also has userId, userFirstName,
10
+ * params (map: param name => value),
11
+ * req (express request object),
12
+ * next (express next function),
13
+ * send (a function that sends a string to the client),
14
+ * redirect (takes a url and redirects the user to that url),
15
+ * renderErrorPage (shows a static error page to the user),
16
+ * and returns the value to send to the client as a JSON API response, or
17
+ * calls next() or redirect(...) or send(...) or renderErrorPage(...).
18
+ * Note: params also has userId, userFirstName,
17
19
  * userLastName, isLearner, isTTM, isAdmin, and any other variables that
18
20
  * are directly added to the session
19
21
  */
@@ -29,7 +31,13 @@ declare const genRouteHandler: (opts: {
29
31
  next: () => void;
30
32
  redirect: (pathOrURL: string) => void;
31
33
  send: (text: string, status?: number | undefined) => void;
34
+ renderErrorPage: (opts?: {
35
+ title?: string | undefined;
36
+ description?: string | undefined;
37
+ code?: string | undefined;
38
+ pageTitle?: string | undefined;
39
+ status?: number | undefined;
40
+ } | undefined) => void;
32
41
  }) => any;
33
- allowNotLoggedIn?: boolean | undefined;
34
42
  }) => (req: any, res: any, next: () => void) => Promise<undefined>;
35
43
  export default genRouteHandler;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Generate a static error page
3
+ * @author Gabe Abrams
4
+ * @param opts object containing all arguments
5
+ * @param [opts.title=An Error Occurred] title of the error box
6
+ * @param [opts.description=An unknown server error occurred. Please contact support.]
7
+ * a human-readable description of the error
8
+ * @param [opts.code=ReactKitErrorCode.NoCode] error code to show
9
+ * @param [opts.pageTitle=opts.title] title of the page/tab if it differs from
10
+ * the title of the error
11
+ * @returns html of the page
12
+ */
13
+ declare const genErrorPage: (opts?: {
14
+ title?: string;
15
+ description?: string;
16
+ code?: string;
17
+ pageTitle?: string;
18
+ }) => string;
19
+ export default genErrorPage;
package/dist/index.d.ts CHANGED
@@ -509,14 +509,16 @@ declare enum ParamType {
509
509
  * @param opts.paramTypes map containing the types for each parameter that is
510
510
  * included in the request (map: param name => type)
511
511
  * @param opts.handler function that processes the request
512
- * @param [opts.allowNotLoggedIn] if true, allow the user to not be logged
513
- * in (the user will be allowed to not have launched via LTI)
514
512
  * @returns express route handler that takes the following arguments:
515
- * params (map: param name => value), handleSuccess (function for handling
516
- * successful requests), handleError (function for handling failed requests),
517
- * req (express request object), redirect (a function that takes a url and
518
- * redirects the user to the url), and send (a function that sends a string
519
- * and optional http status code). Params also has userId, userFirstName,
513
+ * params (map: param name => value),
514
+ * req (express request object),
515
+ * next (express next function),
516
+ * send (a function that sends a string to the client),
517
+ * redirect (takes a url and redirects the user to that url),
518
+ * renderErrorPage (shows a static error page to the user),
519
+ * and returns the value to send to the client as a JSON API response, or
520
+ * calls next() or redirect(...) or send(...) or renderErrorPage(...).
521
+ * Note: params also has userId, userFirstName,
520
522
  * userLastName, isLearner, isTTM, isAdmin, and any other variables that
521
523
  * are directly added to the session
522
524
  */
@@ -532,8 +534,14 @@ declare const genRouteHandler: (opts: {
532
534
  next: () => void;
533
535
  redirect: (pathOrURL: string) => void;
534
536
  send: (text: string, status?: number | undefined) => void;
537
+ renderErrorPage: (opts?: {
538
+ title?: string | undefined;
539
+ description?: string | undefined;
540
+ code?: string | undefined;
541
+ pageTitle?: string | undefined;
542
+ status?: number | undefined;
543
+ } | undefined) => void;
535
544
  }) => any;
536
- allowNotLoggedIn?: boolean | undefined;
537
545
  }) => (req: any, res: any, next: () => void) => Promise<undefined>;
538
546
 
539
547
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dce-reactkit",
3
- "version": "3.1.14",
3
+ "version": "3.1.15",
4
4
  "description": "Shared components for Harvard DCE apps",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -8,6 +8,15 @@ import ParamType from '../types/ParamType';
8
8
  // Import helpers
9
9
  import handleError from './handleError';
10
10
  import handleSuccess from './handleSuccess';
11
+ import genErrorPage from '../html/genErrorPage';
12
+
13
+ /*------------------------------------------------------------------------*/
14
+ /* Helpers */
15
+ /*------------------------------------------------------------------------*/
16
+
17
+ /*------------------------------------------------------------------------*/
18
+ /* Main */
19
+ /*------------------------------------------------------------------------*/
11
20
 
12
21
  /**
13
22
  * Generate an express API route handler
@@ -17,11 +26,15 @@ import handleSuccess from './handleSuccess';
17
26
  * included in the request (map: param name => type)
18
27
  * @param opts.handler function that processes the request
19
28
  * @returns express route handler that takes the following arguments:
20
- * params (map: param name => value), handleSuccess (function for handling
21
- * successful requests), handleError (function for handling failed requests),
22
- * req (express request object), redirect (a function that takes a url and
23
- * redirects the user to the url), and send (a function that sends a string
24
- * and optional http status code). Params also has userId, userFirstName,
29
+ * params (map: param name => value),
30
+ * req (express request object),
31
+ * next (express next function),
32
+ * send (a function that sends a string to the client),
33
+ * redirect (takes a url and redirects the user to that url),
34
+ * renderErrorPage (shows a static error page to the user),
35
+ * and returns the value to send to the client as a JSON API response, or
36
+ * calls next() or redirect(...) or send(...) or renderErrorPage(...).
37
+ * Note: params also has userId, userFirstName,
25
38
  * userLastName, isLearner, isTTM, isAdmin, and any other variables that
26
39
  * are directly added to the session
27
40
  */
@@ -39,6 +52,15 @@ const genRouteHandler = (
39
52
  next: () => void,
40
53
  redirect: (pathOrURL: string) => void,
41
54
  send: (text: string, status?: number) => void,
55
+ renderErrorPage: (
56
+ opts?: {
57
+ title?: string,
58
+ description?: string,
59
+ code?: string,
60
+ pageTitle?: string,
61
+ status?: number,
62
+ },
63
+ ) => void,
42
64
  },
43
65
  ) => any,
44
66
  },
@@ -402,6 +424,31 @@ const genRouteHandler = (
402
424
  res.status(status).send(text);
403
425
  };
404
426
 
427
+ /**
428
+ * Render an error page
429
+ * @author Gabe Abrams
430
+ * @param opts object containing all arguments
431
+ * @param [opts.title=An Error Occurred] title of the error box
432
+ * @param [opts.description=An unknown server error occurred. Please contact support.]
433
+ * a human-readable description of the error
434
+ * @param [opts.code=ReactKitErrorCode.NoCode] error code to show
435
+ * @param [opts.pageTitle=opts.title] title of the page/tab if it differs from
436
+ * the title of the error
437
+ * @param [opts.status=500] http status code
438
+ */
439
+ const renderErrorPage = (
440
+ opts: {
441
+ title?: string,
442
+ description?: string,
443
+ code?: string,
444
+ pageTitle?: string,
445
+ status?: number,
446
+ } = {},
447
+ ) => {
448
+ const html = genErrorPage(opts);
449
+ send(html, opts.status ?? 500);
450
+ };
451
+
405
452
  // Call the handler
406
453
  try {
407
454
  const results = await opts.handler({
@@ -413,6 +460,7 @@ const genRouteHandler = (
413
460
  next();
414
461
  },
415
462
  redirect,
463
+ renderErrorPage,
416
464
  });
417
465
 
418
466
  // Send results to client (only if next wasn't called)
@@ -0,0 +1,141 @@
1
+ // Import shared types
2
+ import ReactKitErrorCode from '../types/ReactKitErrorCode';
3
+
4
+ /**
5
+ * Generate a static error page
6
+ * @author Gabe Abrams
7
+ * @param opts object containing all arguments
8
+ * @param [opts.title=An Error Occurred] title of the error box
9
+ * @param [opts.description=An unknown server error occurred. Please contact support.]
10
+ * a human-readable description of the error
11
+ * @param [opts.code=ReactKitErrorCode.NoCode] error code to show
12
+ * @param [opts.pageTitle=opts.title] title of the page/tab if it differs from
13
+ * the title of the error
14
+ * @returns html of the page
15
+ */
16
+ const genErrorPage = (
17
+ opts: {
18
+ title?: string,
19
+ description?: string,
20
+ code?: string,
21
+ pageTitle?: string,
22
+ } = {},
23
+ ): string => {
24
+ const title = (opts.title ?? 'An Error Occurred');
25
+ const pageTitle = (opts.pageTitle ?? title);
26
+ const description = (
27
+ opts.description
28
+ ?? 'An unknown server error occurred. Please contact support.'
29
+ );
30
+ const code = (opts.code ?? ReactKitErrorCode.NoCode);
31
+
32
+ return `
33
+ <head>
34
+ <!-- Metadata -->
35
+ <meta
36
+ name="viewport"
37
+ content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0"
38
+ >
39
+
40
+ <!-- Title -->
41
+ <title>${pageTitle}</title>
42
+
43
+ <!-- Bootstrap -->
44
+ <link
45
+ rel="stylesheet"
46
+ href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.1/css/bootstrap.min.css"
47
+ integrity="sha512-siwe/oXMhSjGCwLn+scraPOWrJxHlUgMBMZXdPe2Tnk3I0x3ESCoLz7WZ5NTH6SZrywMY+PB1cjyqJ5jAluCOg=="
48
+ crossorigin="anonymous"
49
+ referrerpolicy="no-referrer"
50
+ />
51
+ <script
52
+ src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.1/js/bootstrap.min.js"
53
+ integrity="sha512-vyRAVI0IEm6LI/fVSv/Wq/d0KUfrg3hJq2Qz5FlfER69sf3ZHlOrsLriNm49FxnpUGmhx+TaJKwJ+ByTLKT+Yg=="
54
+ crossorigin="anonymous"
55
+ referrerpolicy="no-referrer"
56
+ ></script>
57
+
58
+ <!-- FontAwesome -->
59
+ <link
60
+ rel="stylesheet"
61
+ href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
62
+ integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
63
+ crossorigin="anonymous"
64
+ referrerpolicy="no-referrer"
65
+ />
66
+
67
+ <!-- Style -->
68
+ <style>
69
+ .DCEReactKit-pop-in {
70
+ animation-name: DCEReactKit-pop-in;
71
+ animation-duration: 0.5s;
72
+ animation-iteration-count: 1;
73
+ animation-timing-function: ease-out;
74
+ animation-fill-mode: both;
75
+
76
+ transform-origin: center;
77
+ }
78
+
79
+ @keyframes DCEReactKit-pop-in {
80
+ 0% {
81
+ opacity: 0;
82
+ transform: scale(0.9);
83
+ }
84
+ 100% {
85
+ opacity: 1;
86
+ transform: scale(1);
87
+ }
88
+ }
89
+
90
+ .DCEReactKit-slide-in {
91
+ animation-name: DCEReactKit-slide-in;
92
+ animation-duration: 1s;
93
+ animation-iteration-count: 1;
94
+ animation-timing-function: ease-out;
95
+ animation-fill-mode: both;
96
+ animation-delay: 0.2s;
97
+ }
98
+
99
+ @keyframes DCEReactKit-slide-in {
100
+ 0% {
101
+ opacity: 0;
102
+ transform: translate(0, 0.3em);
103
+ }
104
+ 100% {
105
+ opacity: 1;
106
+ transform: translate(0, 0);
107
+ }
108
+ }
109
+ </style>
110
+ </head>
111
+
112
+ <!-- Body -->
113
+ <body class="bg-dark text-center pt-3 ps-3 pe-3">
114
+ <!-- Alert -->
115
+ <div
116
+ class="DCEReactKit-pop-in alert alert-warning d-inline-block"
117
+ style="width: 50em; max-width: 100%"
118
+ >
119
+ <!-- Title -->
120
+ <h2>
121
+ <i class="me-1 fa-solid fa-triangle-exclamation"></i>
122
+ ${title}
123
+ </h2>
124
+ <!-- Description -->
125
+ <div>
126
+ ${description}
127
+ </div>
128
+ </div>
129
+
130
+ <!-- Error Code -->
131
+ <div class="DCEReactKit-slide-in text-light">
132
+ <strong>
133
+ Error Code:
134
+ </strong>
135
+ ${code}
136
+ </div>
137
+ </body>
138
+ `;
139
+ };
140
+
141
+ export default genErrorPage;