@torq-north/react-tools 1.0.0 → 1.1.0

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Torq Tools
1
+ # Torq North Tools
2
2
 
3
- A collection of react components, hooks and other utilities used in various Crew 2 projects
3
+ A collection of react components, hooks and other utilities used in various projects
4
4
 
5
5
  ## Getting it running
6
6
 
@@ -8,6 +8,32 @@ Upon pulling down the repo, in order to get the component browser running, all y
8
8
 
9
9
  ![image](https://user-images.githubusercontent.com/68865874/229501155-90c89bfb-e29b-4664-9eab-bd6313b53c14.png)
10
10
 
11
+ ## Session expiry redirects
12
+
13
+ The API helpers (`sendGet`, `sendPost`, etc.) can automatically detect when a user's session has expired and redirect them to the login page. This is triggered when any API call receives a 401 response, or when the server issues a redirect to `/auth/login`, which is the typical behaviour of a Symfony OAuth firewall that redirects rather than returning 401 directly.
14
+
15
+ This behaviour is opt-in. Call `enableAuthRedirect` once at app startup with the login URL to activate it:
16
+
17
+ ```typescript
18
+ import { enableAuthRedirect } from "@torq-north/react-tools";
19
+
20
+ enableAuthRedirect("/auth/login");
21
+ ```
22
+
23
+ If `enableAuthRedirect` is never called, session expiry responses are left for the call site to handle as normal errors.
24
+
25
+ ### Dev environments
26
+
27
+ In local development the frontend and backend often run on different ports. If the backend is on a different port than the Vite dev server, navigating to `/auth/login` will hit Vite instead of the backend and the login page won't render correctly. Pass the full backend URL for dev:
28
+
29
+ ```typescript
30
+ enableAuthRedirect(
31
+ import.meta.env.DEV ? "http://localhost:8103/auth/login" : "/auth/login"
32
+ );
33
+ ```
34
+
35
+ Replace `8103` with whichever port your backend is exposed on locally. In production the relative URL is used and no special configuration is needed.
36
+
11
37
  ## Adding your own component
12
38
 
13
39
  1. Copy/paste in component from IRC project
package/dist/index.cjs CHANGED
@@ -146,8 +146,12 @@ var sendGet = function (url, params) { return __awaiter(void 0, void 0, void 0,
146
146
  switch (_a.label) {
147
147
  case 0:
148
148
  params &&
149
- Object.keys(params).forEach(function (key) { return params[key] === undefined && delete params[key]; });
150
- fetchUrl = params ? "".concat(url, "?").concat(new URLSearchParams(params).toString()) : url;
149
+ Object.keys(params).forEach(function (key) {
150
+ return params[key] === undefined && delete params[key];
151
+ });
152
+ fetchUrl = params
153
+ ? "".concat(url, "?").concat(new URLSearchParams(params).toString())
154
+ : url;
151
155
  return [4 /*yield*/, fetch(fetchUrl)];
152
156
  case 1:
153
157
  response = _a.sent();
@@ -248,11 +252,29 @@ function isJson(response) {
248
252
  }
249
253
  return contentType.indexOf("application/json") >= 0;
250
254
  }
255
+ var authLoginUrl = "/auth/login";
256
+ var authRedirectEnabled = false;
257
+ function enableAuthRedirect(loginUrl) {
258
+ if (loginUrl === void 0) { loginUrl = "/auth/login"; }
259
+ authLoginUrl = loginUrl;
260
+ authRedirectEnabled = true;
261
+ }
262
+ function isSessionExpired(response) {
263
+ return (response.status === 401 ||
264
+ (response.redirected && response.url.includes("/auth/login")));
265
+ }
251
266
  function process$1(response) {
252
267
  return __awaiter(this, void 0, void 0, function () {
253
268
  return __generator(this, function (_a) {
254
269
  switch (_a.label) {
255
- case 0: return [4 /*yield*/, checkResponse(response)];
270
+ case 0:
271
+ if (authRedirectEnabled && isSessionExpired(response)) {
272
+ window.location.href = authLoginUrl;
273
+ // Return a never-resolving promise to suspend execution while the browser navigates away,
274
+ // preventing any error handling or UI updates from firing before the page unloads.
275
+ return [2 /*return*/, new Promise(function () { })];
276
+ }
277
+ return [4 /*yield*/, checkResponse(response)];
256
278
  case 1:
257
279
  _a.sent();
258
280
  if (isJson(response)) {
@@ -5205,6 +5227,7 @@ exports.TabSet = TabSet;
5205
5227
  exports.TextFormField = TextFormField;
5206
5228
  exports.asInteger = asInteger;
5207
5229
  exports.asPhoneNumber = asPhoneNumber;
5230
+ exports.enableAuthRedirect = enableAuthRedirect;
5208
5231
  exports.isEmail = isEmail;
5209
5232
  exports.isPostalCode = isPostalCode;
5210
5233
  exports.sendDelete = sendDelete;