@nu-art/ts-focused-object-frontend 0.401.8 → 0.500.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.
@@ -1,4 +1,4 @@
1
- import { ComponentSync } from '@nu-art/thunderstorm-frontend/index';
1
+ import { ComponentSync } from '@nu-art/thunder-widgets';
2
2
  import { FocusData_Map, FocusedEntity } from '@nu-art/ts-focused-object-shared';
3
3
  import { UniqueId } from '@nu-art/ts-common';
4
4
  import { OnFocusedDataReceived } from '../modules/ModuleFE_FocusedObject.js';
@@ -1,11 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ComponentSync, LL_H_C, Show } from '@nu-art/thunderstorm-frontend/index';
2
+ import { ComponentSync, LL_H_C, Show } from '@nu-art/thunder-widgets';
3
3
  import { compare, filterDuplicates } from '@nu-art/ts-common';
4
- import { ModuleFE_FocusedObject } from '../modules/ModuleFE_FocusedObject.js';
4
+ import { dispatch_onFocusedDataReceived, ModuleFE_FocusedObject } from '../modules/ModuleFE_FocusedObject.js';
5
5
  import { Component_AccountThumbnail, ModuleFE_Account } from '@nu-art/user-account-frontend/index';
6
6
  import './Component_FocusedEntityRef.scss';
7
7
  export class Component_FocusedEntityRef extends ComponentSync {
8
- // ######################## Lifecycle ########################
9
8
  __onFocusedDataReceived(map) {
10
9
  this.reDeriveState();
11
10
  }
@@ -28,11 +27,12 @@ export class Component_FocusedEntityRef extends ComponentSync {
28
27
  * no matter how the component is rendered or recycled.
29
28
  */
30
29
  componentWillUnmount() {
30
+ dispatch_onFocusedDataReceived.removeListener(this);
31
31
  if (this.state.focusedEntities)
32
32
  ModuleFE_FocusedObject.unfocus(this.state.focusedEntities);
33
33
  }
34
34
  componentDidMount() {
35
- //If mounted with focus entities, focus on them
35
+ dispatch_onFocusedDataReceived.addListener(this);
36
36
  if (this.state.focusedEntities)
37
37
  ModuleFE_FocusedObject.focus(this.state.focusedEntities);
38
38
  }
@@ -47,7 +47,6 @@ export class Component_FocusedEntityRef extends ComponentSync {
47
47
  ModuleFE_FocusedObject.focus(prevState.focusedEntities);
48
48
  }
49
49
  }
50
- // ######################## Render ########################
51
50
  render() {
52
51
  return _jsx(LL_H_C, { className: 'component--focused-object', children: this.state.accountIds.map(id => {
53
52
  const account = ModuleFE_Account.cache.unique(id);
@@ -1,14 +1,17 @@
1
1
  import { Module, UniqueId } from '@nu-art/ts-common';
2
- import { ApiDefCaller } from '@nu-art/thunderstorm-shared';
3
- import { ThunderDispatcher } from '@nu-art/thunderstorm-frontend/index';
4
- import { ApiStruct_FocusedObject, FocusData_Map, FocusedEntity } from '@nu-art/ts-focused-object-shared';
2
+ import { API_FocusedObject, FocusData_Map, FocusedEntity } from '@nu-art/ts-focused-object-shared';
5
3
  import { OnLoginStatusUpdated } from '@nu-art/user-account-frontend/index';
6
4
  export interface OnFocusedDataReceived {
7
5
  __onFocusedDataReceived: (map: FocusData_Map) => void;
8
6
  }
9
- export declare const dispatch_onFocusedDataReceived: ThunderDispatcher<OnFocusedDataReceived, "__onFocusedDataReceived", [map: FocusData_Map], void>;
7
+ declare class FocusedDataDispatcher {
8
+ private readonly listeners;
9
+ addListener(l: OnFocusedDataReceived): void;
10
+ removeListener(l: OnFocusedDataReceived): void;
11
+ dispatchAll(map: FocusData_Map): void;
12
+ }
13
+ export declare const dispatch_onFocusedDataReceived: FocusedDataDispatcher;
10
14
  export declare class ModuleFE_FocusedObject_Class extends Module implements OnLoginStatusUpdated {
11
- readonly _v1: ApiDefCaller<ApiStruct_FocusedObject>['_v1'];
12
15
  private focusFirebaseListener;
13
16
  private focusDataMap;
14
17
  private currentlyFocused;
@@ -19,6 +22,7 @@ export declare class ModuleFE_FocusedObject_Class extends Module implements OnLo
19
22
  __onLoginStatusUpdated(): void;
20
23
  constructor();
21
24
  init(): void;
25
+ update(body: API_FocusedObject['update']['Body']): Promise<API_FocusedObject['update']['Response']>;
22
26
  private initFirebaseListening;
23
27
  private initWindowFocusListeners;
24
28
  private initWindowCloseListeners;
@@ -55,3 +59,4 @@ export declare class ModuleFE_FocusedObject_Class extends Module implements OnLo
55
59
  private translateCurrentlyFocusedToFocusedEntities;
56
60
  }
57
61
  export declare const ModuleFE_FocusedObject: ModuleFE_FocusedObject_Class;
62
+ export {};
@@ -1,161 +1,205 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
1
35
  import { _keys, debounce, filterDuplicates, Module, removeItemFromArray, Second } from '@nu-art/ts-common';
2
- import { apiWithBody, ThunderDispatcher } from '@nu-art/thunderstorm-frontend/index';
36
+ import { ApiCaller } from '@nu-art/http-client';
3
37
  import { ModuleFE_FirebaseListener } from '@nu-art/firebase-frontend/ModuleFE_FirebaseListener/ModuleFE_FirebaseListener';
4
38
  import { ApiDef_FocusedObject, } from '@nu-art/ts-focused-object-shared';
5
39
  import { LoggedStatus, ModuleFE_Account } from '@nu-art/user-account-frontend/index';
6
40
  import { DefaultTTL_FocusedObject, getRelationalPath } from '@nu-art/ts-focused-object-shared/consts';
7
- export const dispatch_onFocusedDataReceived = new ThunderDispatcher('__onFocusedDataReceived');
8
- export class ModuleFE_FocusedObject_Class extends Module {
9
- _v1;
10
- focusFirebaseListener;
11
- focusDataMap;
12
- currentlyFocused = {};
13
- apiDebounce;
14
- windowIsFocused = true;
15
- unfocusTimeout;
16
- keepAliveTimeout;
17
- __onLoginStatusUpdated() {
18
- const status = ModuleFE_Account.getLoggedStatus();
19
- if (status === LoggedStatus.LOGGED_OUT)
20
- this.onUserLoggedOut();
21
- }
22
- constructor() {
23
- super();
24
- this.focusDataMap = {};
25
- this._v1 = {
26
- // updateFocusData: apiWithBody(ApiDef_FocusedObject._v1.updateFocusData),
27
- // setFocusStatusByTabId: apiWithBody(ApiDef_FocusedObject._v1.setFocusStatusByTabId),
28
- // releaseObject: apiWithBody(ApiDef_FocusedObject._v1.releaseObject),
29
- // releaseByTabId: apiWithBody(ApiDef_FocusedObject._v1.releaseByTabId),
30
- update: apiWithBody(ApiDef_FocusedObject._v1.update),
31
- };
32
- this.apiDebounce = debounce(this.updateRTDB, 2 * Second, 10 * Second);
33
- }
34
- init() {
35
- this.initFirebaseListening();
36
- this.initWindowFocusListeners();
37
- this.initWindowCloseListeners();
41
+ class FocusedDataDispatcher {
42
+ listeners = new Set();
43
+ addListener(l) {
44
+ this.listeners.add(l);
38
45
  }
39
- // ######################## Init listeners ########################
40
- initFirebaseListening = () => {
41
- this.focusFirebaseListener = ModuleFE_FirebaseListener.createListener(getRelationalPath());
42
- this.focusFirebaseListener.startListening(this.onRTDBChange);
43
- };
44
- initWindowFocusListeners() {
45
- window.addEventListener('focus', this.onWindowFocus);
46
- window.addEventListener('blur', this.onWindowBlur);
46
+ removeListener(l) {
47
+ this.listeners.delete(l);
47
48
  }
48
- initWindowCloseListeners() {
49
- window.addEventListener('beforeunload', async (event) => {
50
- this._v1.update({ focusedEntities: [] }).execute();
51
- // navigator.sendBeacon('/log', JSON.stringify({ type:'application/json' }));
52
- });
49
+ dispatchAll(map) {
50
+ this.listeners.forEach(l => l.__onFocusedDataReceived(map));
53
51
  }
54
- // ######################## Listener Callbacks ########################
55
- onRTDBChange = (snapshot) => {
56
- this.focusDataMap = snapshot.val() ?? {};
57
- this.logDebug('Received firebase focus data', this.focusDataMap);
58
- // Update all the FocusedEntityRef components
59
- dispatch_onFocusedDataReceived.dispatchAll(this.focusDataMap);
60
- };
61
- /**
62
- * Callback for when the current window is focused.
63
- * we change the class property "windowIsFocused" to true so when the time comes to
64
- * send a keepalive to BE, the request will be sent if the window is focused.
65
- * Will also trigger keepalive timer if the time is not already set
66
- */
67
- onWindowFocus = () => {
68
- this.windowIsFocused = true;
69
- //If the keep alive counter still exists, no need to trigger any extra further logic
70
- if (this.keepAliveTimeout)
71
- return;
72
- this.apiDebounce();
73
- };
74
- /**
75
- * Callback for when the current window is un-focused.
76
- * we change the class property "windowIsFocused" to false so when the time comes to
77
- * send a keepalive to BE, the request will not be sent if the window is not focused
78
- */
79
- onWindowBlur = () => {
80
- this.windowIsFocused = false;
81
- };
82
- onUserLoggedOut = () => {
83
- this.currentlyFocused = {};
84
- };
85
- // ######################## Timer Interactions ########################
86
- triggerKeepAlive = () => {
87
- this.clearKeepAlive();
88
- //No need to set keepalive timeout if currentlyFocused has no data
89
- if (!_keys(this.currentlyFocused).length)
90
- return;
91
- this.keepAliveTimeout = setTimeout(() => {
92
- //No need to keepalive if window is not focused
93
- if (!this.windowIsFocused)
94
- return this.clearKeepAlive();
52
+ }
53
+ export const dispatch_onFocusedDataReceived = new FocusedDataDispatcher();
54
+ let ModuleFE_FocusedObject_Class = (() => {
55
+ let _classSuper = Module;
56
+ let _instanceExtraInitializers = [];
57
+ let _update_decorators;
58
+ return class ModuleFE_FocusedObject_Class extends _classSuper {
59
+ static {
60
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
61
+ _update_decorators = [ApiCaller(ApiDef_FocusedObject.update)];
62
+ __esDecorate(this, null, _update_decorators, { kind: "method", name: "update", static: false, private: false, access: { has: obj => "update" in obj, get: obj => obj.update }, metadata: _metadata }, null, _instanceExtraInitializers);
63
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
64
+ }
65
+ focusFirebaseListener = __runInitializers(this, _instanceExtraInitializers);
66
+ focusDataMap;
67
+ currentlyFocused = {};
68
+ apiDebounce;
69
+ windowIsFocused = true;
70
+ unfocusTimeout;
71
+ keepAliveTimeout;
72
+ __onLoginStatusUpdated() {
73
+ const status = ModuleFE_Account.getLoggedStatus();
74
+ if (status === LoggedStatus.LOGGED_OUT)
75
+ this.onUserLoggedOut();
76
+ }
77
+ constructor() {
78
+ super();
79
+ this.focusDataMap = {};
80
+ this.apiDebounce = debounce(this.updateRTDB, 2 * Second, 10 * Second);
81
+ }
82
+ init() {
83
+ this.initFirebaseListening();
84
+ this.initWindowFocusListeners();
85
+ this.initWindowCloseListeners();
86
+ }
87
+ async update(body) {
88
+ return undefined;
89
+ }
90
+ initFirebaseListening = () => {
91
+ this.focusFirebaseListener = ModuleFE_FirebaseListener.createListener(getRelationalPath());
92
+ this.focusFirebaseListener.startListening(this.onRTDBChange);
93
+ };
94
+ initWindowFocusListeners() {
95
+ window.addEventListener('focus', this.onWindowFocus);
96
+ window.addEventListener('blur', this.onWindowBlur);
97
+ }
98
+ initWindowCloseListeners() {
99
+ window.addEventListener('beforeunload', () => {
100
+ void this.update({ focusedEntities: [] });
101
+ });
102
+ }
103
+ onRTDBChange = (snapshot) => {
104
+ this.focusDataMap = snapshot.val() ?? {};
105
+ this.logDebug('Received firebase focus data', this.focusDataMap);
106
+ // Update all the FocusedEntityRef components
107
+ dispatch_onFocusedDataReceived.dispatchAll(this.focusDataMap);
108
+ };
109
+ /**
110
+ * Callback for when the current window is focused.
111
+ * we change the class property "windowIsFocused" to true so when the time comes to
112
+ * send a keepalive to BE, the request will be sent if the window is focused.
113
+ * Will also trigger keepalive timer if the time is not already set
114
+ */
115
+ onWindowFocus = () => {
116
+ this.windowIsFocused = true;
117
+ //If the keep alive counter still exists, no need to trigger any extra further logic
118
+ if (this.keepAliveTimeout)
119
+ return;
95
120
  this.apiDebounce();
96
- }, DefaultTTL_FocusedObject - 20 * Second);
97
- };
98
- triggerUnfocus = () => {
99
- this.clearUnfocus();
100
- this.unfocusTimeout = setTimeout(() => this.apiDebounce(), 20 * Second);
101
- };
102
- clearKeepAlive = () => {
103
- clearTimeout(this.keepAliveTimeout);
104
- delete this.keepAliveTimeout;
105
- };
106
- clearUnfocus = () => {
107
- clearTimeout(this.unfocusTimeout);
108
- delete this.unfocusTimeout;
109
- };
110
- // ######################## API Logic ########################
111
- updateRTDB = () => {
112
- //Call API
113
- const focusedEntities = this.translateCurrentlyFocusedToFocusedEntities();
114
- this._v1.update({ focusedEntities })
115
- .executeSync()
116
- .then()
117
- .catch(e => {
118
- this.logError('Update focused object failed', e);
119
- })
120
- .finally(() => {
121
- this.clearUnfocus();
122
- this.triggerKeepAlive();
123
- });
124
- };
125
- // ######################## Logic ########################
126
- focus = (entities) => {
127
- entities.forEach(entity => {
128
- if (!this.currentlyFocused[entity.dbKey])
129
- this.currentlyFocused[entity.dbKey] = [];
130
- this.currentlyFocused[entity.dbKey] = filterDuplicates([...this.currentlyFocused[entity.dbKey], entity.itemId]);
131
- });
132
- this.apiDebounce();
133
- };
134
- unfocus = (entities) => {
135
- entities.forEach(entity => {
136
- if (!this.currentlyFocused[entity.dbKey])
121
+ };
122
+ /**
123
+ * Callback for when the current window is un-focused.
124
+ * we change the class property "windowIsFocused" to false so when the time comes to
125
+ * send a keepalive to BE, the request will not be sent if the window is not focused
126
+ */
127
+ onWindowBlur = () => {
128
+ this.windowIsFocused = false;
129
+ };
130
+ onUserLoggedOut = () => {
131
+ this.currentlyFocused = {};
132
+ };
133
+ triggerKeepAlive = () => {
134
+ this.clearKeepAlive();
135
+ //No need to set keepalive timeout if currentlyFocused has no data
136
+ if (!_keys(this.currentlyFocused).length)
137
137
  return;
138
- this.currentlyFocused[entity.dbKey] = removeItemFromArray(this.currentlyFocused[entity.dbKey], entity.itemId);
139
- });
140
- this.triggerUnfocus();
141
- };
142
- getFocusData = (dbKey, itemId) => {
143
- return this.focusDataMap[dbKey]?.[itemId];
144
- };
145
- getAccountIdsForFocusedItem = (dbKey, itemId, ignoreCurrentUser = true) => {
146
- const data = this.getFocusData(dbKey, itemId);
147
- const userIds = data ? _keys(data) : [];
148
- const account = ModuleFE_Account.getCurrentlyLoggedAccount();
149
- return ignoreCurrentUser ? userIds.filter(id => id !== account?._id) : userIds;
150
- };
151
- translateCurrentlyFocusedToFocusedEntities = () => {
152
- const focusedEntities = [];
153
- _keys(this.currentlyFocused).forEach(dbKey => {
154
- this.currentlyFocused[dbKey].forEach(itemId => {
155
- focusedEntities.push({ dbKey: dbKey, itemId });
138
+ this.keepAliveTimeout = setTimeout(() => {
139
+ //No need to keepalive if window is not focused
140
+ if (!this.windowIsFocused)
141
+ return this.clearKeepAlive();
142
+ this.apiDebounce();
143
+ }, DefaultTTL_FocusedObject - 20 * Second);
144
+ };
145
+ triggerUnfocus = () => {
146
+ this.clearUnfocus();
147
+ this.unfocusTimeout = setTimeout(() => this.apiDebounce(), 20 * Second);
148
+ };
149
+ clearKeepAlive = () => {
150
+ clearTimeout(this.keepAliveTimeout);
151
+ delete this.keepAliveTimeout;
152
+ };
153
+ clearUnfocus = () => {
154
+ clearTimeout(this.unfocusTimeout);
155
+ delete this.unfocusTimeout;
156
+ };
157
+ updateRTDB = () => {
158
+ const focusedEntities = this.translateCurrentlyFocusedToFocusedEntities();
159
+ this.update({ focusedEntities })
160
+ .catch(e => {
161
+ this.logError('Update focused object failed', e);
162
+ })
163
+ .finally(() => {
164
+ this.clearUnfocus();
165
+ this.triggerKeepAlive();
156
166
  });
157
- });
158
- return focusedEntities;
167
+ };
168
+ focus = (entities) => {
169
+ entities.forEach(entity => {
170
+ if (!this.currentlyFocused[entity.dbKey])
171
+ this.currentlyFocused[entity.dbKey] = [];
172
+ this.currentlyFocused[entity.dbKey] = filterDuplicates([...this.currentlyFocused[entity.dbKey], entity.itemId]);
173
+ });
174
+ this.apiDebounce();
175
+ };
176
+ unfocus = (entities) => {
177
+ entities.forEach(entity => {
178
+ if (!this.currentlyFocused[entity.dbKey])
179
+ return;
180
+ this.currentlyFocused[entity.dbKey] = removeItemFromArray(this.currentlyFocused[entity.dbKey], entity.itemId);
181
+ });
182
+ this.triggerUnfocus();
183
+ };
184
+ getFocusData = (dbKey, itemId) => {
185
+ return this.focusDataMap[dbKey]?.[itemId];
186
+ };
187
+ getAccountIdsForFocusedItem = (dbKey, itemId, ignoreCurrentUser = true) => {
188
+ const data = this.getFocusData(dbKey, itemId);
189
+ const userIds = data ? _keys(data) : [];
190
+ const account = ModuleFE_Account.getCurrentlyLoggedAccount();
191
+ return ignoreCurrentUser ? userIds.filter(id => id !== account?._id) : userIds;
192
+ };
193
+ translateCurrentlyFocusedToFocusedEntities = () => {
194
+ const focusedEntities = [];
195
+ _keys(this.currentlyFocused).forEach(dbKey => {
196
+ this.currentlyFocused[dbKey].forEach(itemId => {
197
+ focusedEntities.push({ dbKey: dbKey, itemId });
198
+ });
199
+ });
200
+ return focusedEntities;
201
+ };
159
202
  };
160
- }
203
+ })();
204
+ export { ModuleFE_FocusedObject_Class };
161
205
  export const ModuleFE_FocusedObject = new ModuleFE_FocusedObject_Class();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nu-art/ts-focused-object-frontend",
3
- "version": "0.401.8",
3
+ "version": "0.500.0",
4
4
  "description": "ts-focused-object - Express & Typescript based backend framework Frontend",
5
5
  "keywords": [
6
6
  "TacB0sS",
@@ -31,18 +31,18 @@
31
31
  "build": "tsc"
32
32
  },
33
33
  "dependencies": {
34
- "@nu-art/ts-focused-object-shared": "0.401.8",
35
- "@nu-art/firebase-frontend": "0.401.8",
36
- "@nu-art/firebase-shared": "0.401.8",
37
- "@nu-art/thunderstorm-frontend": "0.401.8",
38
- "@nu-art/thunderstorm-shared": "0.401.8",
39
- "@nu-art/ts-common": "0.401.8",
40
- "@nu-art/user-account-frontend": "0.401.8",
41
- "@nu-art/user-account-shared": "0.401.8",
34
+ "@nu-art/ts-focused-object-shared": "0.500.0",
35
+ "@nu-art/firebase-frontend": "0.500.0",
36
+ "@nu-art/firebase-shared": "0.500.0",
37
+ "@nu-art/ts-common": "0.500.0",
38
+ "@nu-art/user-account-frontend": "0.500.0",
39
+ "@nu-art/user-account-shared": "0.500.0",
42
40
  "firebase": "^11.9.0",
43
41
  "firebase-admin": "13.4.0",
44
42
  "firebase-functions": "6.3.2",
45
- "react": "^18.0.0"
43
+ "react": "^18.0.0",
44
+ "@nu-art/http-client": "{{THUNDERSTORM_VERSION}}",
45
+ "@nu-art/thunder-widgets": "{{THUNDERSTORM_VERSION}}"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/react": "^18.0.0",