@knocklabs/client 0.8.17 → 0.8.19
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 +17 -0
- package/dist/api.d.ts +25 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +84 -0
- package/dist/cjs/api.js +2 -133
- package/dist/cjs/api.js.map +1 -1
- package/dist/cjs/clients/feed/feed.js +2 -937
- package/dist/cjs/clients/feed/feed.js.map +1 -1
- package/dist/cjs/clients/feed/index.js +2 -34
- package/dist/cjs/clients/feed/index.js.map +1 -1
- package/dist/cjs/clients/feed/store.js +2 -111
- package/dist/cjs/clients/feed/store.js.map +1 -1
- package/dist/cjs/clients/feed/utils.js +2 -26
- package/dist/cjs/clients/feed/utils.js.map +1 -1
- package/dist/cjs/clients/preferences/index.js +2 -373
- package/dist/cjs/clients/preferences/index.js.map +1 -1
- package/dist/cjs/clients/users/index.js +2 -185
- package/dist/cjs/clients/users/index.js.map +1 -1
- package/dist/cjs/index.js +2 -102
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/knock.js +6 -89
- package/dist/cjs/knock.js.map +1 -1
- package/dist/cjs/networkStatus.js +2 -18
- package/dist/cjs/networkStatus.js.map +1 -1
- package/dist/clients/feed/feed.d.ts +64 -0
- package/dist/clients/feed/feed.d.ts.map +1 -0
- package/dist/clients/feed/feed.js +572 -0
- package/dist/clients/feed/index.d.ts +15 -0
- package/dist/clients/feed/index.d.ts.map +1 -0
- package/dist/clients/feed/index.js +34 -0
- package/dist/clients/feed/interfaces.d.ts +60 -0
- package/dist/clients/feed/interfaces.d.ts.map +1 -0
- package/dist/clients/feed/interfaces.js +2 -0
- package/dist/clients/feed/store.d.ts +3 -0
- package/dist/clients/feed/store.d.ts.map +1 -0
- package/dist/clients/feed/store.js +72 -0
- package/dist/clients/feed/types.d.ts +34 -0
- package/dist/clients/feed/types.d.ts.map +1 -0
- package/dist/clients/feed/types.js +2 -0
- package/dist/clients/feed/utils.d.ts +4 -0
- package/dist/clients/feed/utils.d.ts.map +1 -0
- package/dist/clients/feed/utils.js +21 -0
- package/dist/clients/preferences/index.d.ts +46 -0
- package/dist/clients/preferences/index.d.ts.map +1 -0
- package/dist/clients/preferences/index.js +129 -0
- package/dist/clients/preferences/interfaces.d.ts +26 -0
- package/dist/clients/preferences/interfaces.d.ts.map +1 -0
- package/dist/clients/preferences/interfaces.js +2 -0
- package/dist/clients/users/index.d.ts +16 -0
- package/dist/clients/users/index.d.ts.map +1 -0
- package/dist/clients/users/index.js +56 -0
- package/dist/clients/users/interfaces.d.ts +8 -0
- package/dist/clients/users/interfaces.d.ts.map +1 -0
- package/dist/clients/users/interfaces.js +2 -0
- package/dist/esm/api.js +44 -84
- package/dist/esm/api.js.map +1 -1
- package/dist/esm/clients/feed/feed.js +296 -601
- package/dist/esm/clients/feed/feed.js.map +1 -1
- package/dist/esm/clients/feed/index.js +28 -12
- package/dist/esm/clients/feed/index.js.map +1 -1
- package/dist/esm/clients/feed/store.js +37 -71
- package/dist/esm/clients/feed/store.js.map +1 -1
- package/dist/esm/clients/feed/utils.js +10 -15
- package/dist/esm/clients/feed/utils.js.map +1 -1
- package/dist/esm/clients/preferences/index.js +79 -146
- package/dist/esm/clients/preferences/index.js.map +1 -1
- package/dist/esm/clients/users/index.js +52 -76
- package/dist/esm/clients/users/index.js.map +1 -1
- package/dist/esm/index.js +12 -11
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/knock.js +72 -51
- package/dist/esm/knock.js.map +1 -1
- package/dist/esm/networkStatus.js +14 -10
- package/dist/esm/networkStatus.js.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/interfaces.d.ts +41 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +2 -0
- package/dist/knock.d.ts +30 -0
- package/dist/knock.d.ts.map +1 -0
- package/dist/knock.js +135 -0
- package/dist/networkStatus.d.ts +8 -0
- package/dist/networkStatus.d.ts.map +1 -0
- package/dist/networkStatus.js +18 -0
- package/dist/types/api.d.ts +0 -2
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/clients/feed/feed.d.ts +12 -4
- package/dist/types/clients/feed/feed.d.ts.map +1 -1
- package/dist/types/clients/feed/index.d.ts +4 -0
- package/dist/types/clients/feed/index.d.ts.map +1 -1
- package/dist/types/clients/feed/interfaces.d.ts +2 -1
- package/dist/types/clients/feed/interfaces.d.ts.map +1 -1
- package/dist/types/clients/feed/store.d.ts.map +1 -1
- package/dist/types/clients/feed/types.d.ts +1 -2
- package/dist/types/clients/feed/types.d.ts.map +1 -1
- package/dist/types/clients/feed/utils.d.ts +1 -1
- package/dist/types/clients/feed/utils.d.ts.map +1 -1
- package/dist/types/clients/preferences/index.d.ts +2 -1
- package/dist/types/clients/preferences/index.d.ts.map +1 -1
- package/dist/types/clients/preferences/interfaces.d.ts +1 -1
- package/dist/types/clients/preferences/interfaces.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/interfaces.d.ts +8 -8
- package/dist/types/interfaces.d.ts.map +1 -1
- package/dist/types/knock.d.ts +12 -4
- package/dist/types/knock.d.ts.map +1 -1
- package/package.json +15 -10
- package/dist/cjs/clients/feed/interfaces.js +0 -6
- package/dist/cjs/clients/feed/interfaces.js.map +0 -1
- package/dist/cjs/clients/feed/types.js +0 -6
- package/dist/cjs/clients/feed/types.js.map +0 -1
- package/dist/cjs/clients/preferences/interfaces.js +0 -6
- package/dist/cjs/clients/preferences/interfaces.js.map +0 -1
- package/dist/cjs/clients/users/interfaces.js +0 -6
- package/dist/cjs/clients/users/interfaces.js.map +0 -1
- package/dist/cjs/interfaces.js +0 -6
- package/dist/cjs/interfaces.js.map +0 -1
- package/dist/esm/clients/feed/interfaces.js +0 -2
- package/dist/esm/clients/feed/interfaces.js.map +0 -1
- package/dist/esm/clients/feed/types.js +0 -2
- package/dist/esm/clients/feed/types.js.map +0 -1
- package/dist/esm/clients/preferences/interfaces.js +0 -2
- package/dist/esm/clients/preferences/interfaces.js.map +0 -1
- package/dist/esm/clients/users/interfaces.js +0 -2
- package/dist/esm/clients/users/interfaces.js.map +0 -1
- package/dist/esm/interfaces.js +0 -2
- package/dist/esm/interfaces.js.map +0 -1
|
@@ -1,937 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports["default"] = void 0;
|
|
8
|
-
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
9
|
-
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
10
|
-
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
11
|
-
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
12
|
-
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
13
|
-
var _eventemitter = require("eventemitter2");
|
|
14
|
-
var _store = _interopRequireDefault(require("./store"));
|
|
15
|
-
var _networkStatus = require("../../networkStatus");
|
|
16
|
-
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
17
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
18
|
-
// Default options to apply
|
|
19
|
-
var feedClientDefaults = {
|
|
20
|
-
archived: "exclude"
|
|
21
|
-
};
|
|
22
|
-
var DEFAULT_DISCONNECT_DELAY = 2000;
|
|
23
|
-
var Feed = /*#__PURE__*/function () {
|
|
24
|
-
function Feed(knock, feedId, options) {
|
|
25
|
-
var _this = this;
|
|
26
|
-
(0, _classCallCheck2["default"])(this, Feed);
|
|
27
|
-
this.knock = knock;
|
|
28
|
-
this.feedId = feedId;
|
|
29
|
-
(0, _defineProperty2["default"])(this, "apiClient", void 0);
|
|
30
|
-
(0, _defineProperty2["default"])(this, "userFeedId", void 0);
|
|
31
|
-
(0, _defineProperty2["default"])(this, "channel", void 0);
|
|
32
|
-
(0, _defineProperty2["default"])(this, "broadcaster", void 0);
|
|
33
|
-
(0, _defineProperty2["default"])(this, "defaultOptions", void 0);
|
|
34
|
-
(0, _defineProperty2["default"])(this, "broadcastChannel", void 0);
|
|
35
|
-
(0, _defineProperty2["default"])(this, "disconnectTimer", null);
|
|
36
|
-
// The raw store instance, used for binding in React and other environments
|
|
37
|
-
(0, _defineProperty2["default"])(this, "store", void 0);
|
|
38
|
-
this.apiClient = knock.client();
|
|
39
|
-
this.feedId = feedId;
|
|
40
|
-
this.userFeedId = this.buildUserFeedId();
|
|
41
|
-
this.store = (0, _store["default"])();
|
|
42
|
-
this.broadcaster = new _eventemitter.EventEmitter2({
|
|
43
|
-
wildcard: true,
|
|
44
|
-
delimiter: "."
|
|
45
|
-
});
|
|
46
|
-
this.defaultOptions = _objectSpread(_objectSpread({}, feedClientDefaults), options);
|
|
47
|
-
|
|
48
|
-
// In server environments we might not have a socket connection
|
|
49
|
-
if (this.apiClient.socket) {
|
|
50
|
-
this.channel = this.apiClient.socket.channel("feeds:".concat(this.userFeedId), this.defaultOptions);
|
|
51
|
-
this.channel.on("new-message", function (resp) {
|
|
52
|
-
return _this.onNewMessageReceived(resp);
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Attempt to bind to listen to other events from this feed in different tabs
|
|
57
|
-
// Note: here we ensure `self` is available (it's not in server rendered envs)
|
|
58
|
-
this.broadcastChannel = typeof self !== "undefined" && "BroadcastChannel" in self ? new BroadcastChannel("knock:feed:".concat(this.userFeedId)) : null;
|
|
59
|
-
if (options.auto_manage_socket_connection && this.apiClient.socket) {
|
|
60
|
-
this.setupAutoSocketManager(options.auto_manage_socket_connection_delay);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Cleans up a feed instance by destroying the store and disconnecting
|
|
66
|
-
* an open socket connection.
|
|
67
|
-
*/
|
|
68
|
-
(0, _createClass2["default"])(Feed, [{
|
|
69
|
-
key: "teardown",
|
|
70
|
-
value: function teardown() {
|
|
71
|
-
if (this.channel) {
|
|
72
|
-
this.channel.leave();
|
|
73
|
-
this.channel.off("new-message");
|
|
74
|
-
}
|
|
75
|
-
this.broadcaster.removeAllListeners();
|
|
76
|
-
this.store.destroy();
|
|
77
|
-
if (this.broadcastChannel) {
|
|
78
|
-
this.broadcastChannel.close();
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/*
|
|
83
|
-
Initializes a real-time connection to Knock, connecting the websocket for the
|
|
84
|
-
current ApiClient instance if the socket is not already connected.
|
|
85
|
-
*/
|
|
86
|
-
}, {
|
|
87
|
-
key: "listenForUpdates",
|
|
88
|
-
value: function listenForUpdates() {
|
|
89
|
-
var _this2 = this;
|
|
90
|
-
// Connect the socket only if we don't already have a connection
|
|
91
|
-
if (this.apiClient.socket && !this.apiClient.socket.isConnected()) {
|
|
92
|
-
this.apiClient.socket.connect();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Only join the channel if we're not already in a joining state
|
|
96
|
-
if (this.channel && ["closed", "errored"].includes(this.channel.state)) {
|
|
97
|
-
this.channel.join();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Opt into receiving updates from _other tabs for the same user / feed_ via the broadcast
|
|
101
|
-
// channel (iff it's enabled and exists)
|
|
102
|
-
if (this.broadcastChannel && this.defaultOptions.__experimentalCrossBrowserUpdates === true) {
|
|
103
|
-
this.broadcastChannel.onmessage = function (e) {
|
|
104
|
-
switch (e.data.type) {
|
|
105
|
-
case "items:archived":
|
|
106
|
-
case "items:unarchived":
|
|
107
|
-
case "items:seen":
|
|
108
|
-
case "items:unseen":
|
|
109
|
-
case "items:read":
|
|
110
|
-
case "items:unread":
|
|
111
|
-
case "items:all_read":
|
|
112
|
-
case "items:all_seen":
|
|
113
|
-
case "items:all_archived":
|
|
114
|
-
// When items are updated in any other tab, simply refetch to get the latest state
|
|
115
|
-
// to make sure that the state gets updated accordingly. In the future here we could
|
|
116
|
-
// maybe do this optimistically without the fetch.
|
|
117
|
-
return _this2.fetch();
|
|
118
|
-
break;
|
|
119
|
-
default:
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/* Binds a handler to be invoked when event occurs */
|
|
127
|
-
}, {
|
|
128
|
-
key: "on",
|
|
129
|
-
value: function on(eventName, callback) {
|
|
130
|
-
this.broadcaster.on(eventName, callback);
|
|
131
|
-
}
|
|
132
|
-
}, {
|
|
133
|
-
key: "off",
|
|
134
|
-
value: function off(eventName, callback) {
|
|
135
|
-
this.broadcaster.off(eventName, callback);
|
|
136
|
-
}
|
|
137
|
-
}, {
|
|
138
|
-
key: "getState",
|
|
139
|
-
value: function getState() {
|
|
140
|
-
return this.store.getState();
|
|
141
|
-
}
|
|
142
|
-
}, {
|
|
143
|
-
key: "markAsSeen",
|
|
144
|
-
value: function () {
|
|
145
|
-
var _markAsSeen = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(itemOrItems) {
|
|
146
|
-
var now;
|
|
147
|
-
return _regenerator["default"].wrap(function _callee$(_context) {
|
|
148
|
-
while (1) switch (_context.prev = _context.next) {
|
|
149
|
-
case 0:
|
|
150
|
-
now = new Date().toISOString();
|
|
151
|
-
this.optimisticallyPerformStatusUpdate(itemOrItems, "seen", {
|
|
152
|
-
seen_at: now
|
|
153
|
-
}, "unseen_count");
|
|
154
|
-
return _context.abrupt("return", this.makeStatusUpdate(itemOrItems, "seen"));
|
|
155
|
-
case 3:
|
|
156
|
-
case "end":
|
|
157
|
-
return _context.stop();
|
|
158
|
-
}
|
|
159
|
-
}, _callee, this);
|
|
160
|
-
}));
|
|
161
|
-
function markAsSeen(_x) {
|
|
162
|
-
return _markAsSeen.apply(this, arguments);
|
|
163
|
-
}
|
|
164
|
-
return markAsSeen;
|
|
165
|
-
}()
|
|
166
|
-
}, {
|
|
167
|
-
key: "markAllAsSeen",
|
|
168
|
-
value: function () {
|
|
169
|
-
var _markAllAsSeen = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2() {
|
|
170
|
-
var _this$store, getState, setState, _getState, metadata, items, isViewingOnlyUnseen, attrs, itemIds, result;
|
|
171
|
-
return _regenerator["default"].wrap(function _callee2$(_context2) {
|
|
172
|
-
while (1) switch (_context2.prev = _context2.next) {
|
|
173
|
-
case 0:
|
|
174
|
-
// To mark all of the messages as seen we:
|
|
175
|
-
// 1. Optimistically update *everything* we have in the store
|
|
176
|
-
// 2. We decrement the `unseen_count` to zero optimistically
|
|
177
|
-
// 3. We issue the API call to the endpoint
|
|
178
|
-
//
|
|
179
|
-
// Note: there is the potential for a race condition here because the bulk
|
|
180
|
-
// update is an async method, so if a new message comes in during this window before
|
|
181
|
-
// the update has been processed we'll effectively reset the `unseen_count` to be what it was.
|
|
182
|
-
//
|
|
183
|
-
// Note: here we optimistically handle the case whereby the feed is scoped to show only `unseen`
|
|
184
|
-
// items by removing everything from view.
|
|
185
|
-
_this$store = this.store, getState = _this$store.getState, setState = _this$store.setState;
|
|
186
|
-
_getState = getState(), metadata = _getState.metadata, items = _getState.items;
|
|
187
|
-
isViewingOnlyUnseen = this.defaultOptions.status === "unseen"; // If we're looking at the unseen view, then we want to remove all of the items optimistically
|
|
188
|
-
// from the store given that nothing should be visible. We do this by resetting the store state
|
|
189
|
-
// and setting the current metadata counts to 0
|
|
190
|
-
if (isViewingOnlyUnseen) {
|
|
191
|
-
setState(function (store) {
|
|
192
|
-
return store.resetStore(_objectSpread(_objectSpread({}, metadata), {}, {
|
|
193
|
-
total_count: 0,
|
|
194
|
-
unseen_count: 0
|
|
195
|
-
}));
|
|
196
|
-
});
|
|
197
|
-
} else {
|
|
198
|
-
// Otherwise we want to update the metadata and mark all of the items in the store as seen
|
|
199
|
-
setState(function (store) {
|
|
200
|
-
return store.setMetadata(_objectSpread(_objectSpread({}, metadata), {}, {
|
|
201
|
-
unseen_count: 0
|
|
202
|
-
}));
|
|
203
|
-
});
|
|
204
|
-
attrs = {
|
|
205
|
-
seen_at: new Date().toISOString()
|
|
206
|
-
};
|
|
207
|
-
itemIds = items.map(function (item) {
|
|
208
|
-
return item.id;
|
|
209
|
-
});
|
|
210
|
-
setState(function (store) {
|
|
211
|
-
return store.setItemAttrs(itemIds, attrs);
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Issue the API request to the bulk status change API
|
|
216
|
-
_context2.next = 6;
|
|
217
|
-
return this.makeBulkStatusUpdate("seen");
|
|
218
|
-
case 6:
|
|
219
|
-
result = _context2.sent;
|
|
220
|
-
this.broadcaster.emit("items:all_seen", {
|
|
221
|
-
items: items
|
|
222
|
-
});
|
|
223
|
-
this.broadcastOverChannel("items:all_seen", {
|
|
224
|
-
items: items
|
|
225
|
-
});
|
|
226
|
-
return _context2.abrupt("return", result);
|
|
227
|
-
case 10:
|
|
228
|
-
case "end":
|
|
229
|
-
return _context2.stop();
|
|
230
|
-
}
|
|
231
|
-
}, _callee2, this);
|
|
232
|
-
}));
|
|
233
|
-
function markAllAsSeen() {
|
|
234
|
-
return _markAllAsSeen.apply(this, arguments);
|
|
235
|
-
}
|
|
236
|
-
return markAllAsSeen;
|
|
237
|
-
}()
|
|
238
|
-
}, {
|
|
239
|
-
key: "markAsUnseen",
|
|
240
|
-
value: function () {
|
|
241
|
-
var _markAsUnseen = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(itemOrItems) {
|
|
242
|
-
return _regenerator["default"].wrap(function _callee3$(_context3) {
|
|
243
|
-
while (1) switch (_context3.prev = _context3.next) {
|
|
244
|
-
case 0:
|
|
245
|
-
this.optimisticallyPerformStatusUpdate(itemOrItems, "unseen", {
|
|
246
|
-
seen_at: null
|
|
247
|
-
}, "unseen_count");
|
|
248
|
-
return _context3.abrupt("return", this.makeStatusUpdate(itemOrItems, "unseen"));
|
|
249
|
-
case 2:
|
|
250
|
-
case "end":
|
|
251
|
-
return _context3.stop();
|
|
252
|
-
}
|
|
253
|
-
}, _callee3, this);
|
|
254
|
-
}));
|
|
255
|
-
function markAsUnseen(_x2) {
|
|
256
|
-
return _markAsUnseen.apply(this, arguments);
|
|
257
|
-
}
|
|
258
|
-
return markAsUnseen;
|
|
259
|
-
}()
|
|
260
|
-
}, {
|
|
261
|
-
key: "markAsRead",
|
|
262
|
-
value: function () {
|
|
263
|
-
var _markAsRead = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(itemOrItems) {
|
|
264
|
-
var now;
|
|
265
|
-
return _regenerator["default"].wrap(function _callee4$(_context4) {
|
|
266
|
-
while (1) switch (_context4.prev = _context4.next) {
|
|
267
|
-
case 0:
|
|
268
|
-
now = new Date().toISOString();
|
|
269
|
-
this.optimisticallyPerformStatusUpdate(itemOrItems, "read", {
|
|
270
|
-
read_at: now
|
|
271
|
-
}, "unread_count");
|
|
272
|
-
return _context4.abrupt("return", this.makeStatusUpdate(itemOrItems, "read"));
|
|
273
|
-
case 3:
|
|
274
|
-
case "end":
|
|
275
|
-
return _context4.stop();
|
|
276
|
-
}
|
|
277
|
-
}, _callee4, this);
|
|
278
|
-
}));
|
|
279
|
-
function markAsRead(_x3) {
|
|
280
|
-
return _markAsRead.apply(this, arguments);
|
|
281
|
-
}
|
|
282
|
-
return markAsRead;
|
|
283
|
-
}()
|
|
284
|
-
}, {
|
|
285
|
-
key: "markAllAsRead",
|
|
286
|
-
value: function () {
|
|
287
|
-
var _markAllAsRead = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5() {
|
|
288
|
-
var _this$store2, getState, setState, _getState2, metadata, items, isViewingOnlyUnread, attrs, itemIds, result;
|
|
289
|
-
return _regenerator["default"].wrap(function _callee5$(_context5) {
|
|
290
|
-
while (1) switch (_context5.prev = _context5.next) {
|
|
291
|
-
case 0:
|
|
292
|
-
// To mark all of the messages as read we:
|
|
293
|
-
// 1. Optimistically update *everything* we have in the store
|
|
294
|
-
// 2. We decrement the `unread_count` to zero optimistically
|
|
295
|
-
// 3. We issue the API call to the endpoint
|
|
296
|
-
//
|
|
297
|
-
// Note: there is the potential for a race condition here because the bulk
|
|
298
|
-
// update is an async method, so if a new message comes in during this window before
|
|
299
|
-
// the update has been processed we'll effectively reset the `unread_count` to be what it was.
|
|
300
|
-
//
|
|
301
|
-
// Note: here we optimistically handle the case whereby the feed is scoped to show only `unread`
|
|
302
|
-
// items by removing everything from view.
|
|
303
|
-
_this$store2 = this.store, getState = _this$store2.getState, setState = _this$store2.setState;
|
|
304
|
-
_getState2 = getState(), metadata = _getState2.metadata, items = _getState2.items;
|
|
305
|
-
isViewingOnlyUnread = this.defaultOptions.status === "unread"; // If we're looking at the unread view, then we want to remove all of the items optimistically
|
|
306
|
-
// from the store given that nothing should be visible. We do this by resetting the store state
|
|
307
|
-
// and setting the current metadata counts to 0
|
|
308
|
-
if (isViewingOnlyUnread) {
|
|
309
|
-
setState(function (store) {
|
|
310
|
-
return store.resetStore(_objectSpread(_objectSpread({}, metadata), {}, {
|
|
311
|
-
total_count: 0,
|
|
312
|
-
unread_count: 0
|
|
313
|
-
}));
|
|
314
|
-
});
|
|
315
|
-
} else {
|
|
316
|
-
// Otherwise we want to update the metadata and mark all of the items in the store as seen
|
|
317
|
-
setState(function (store) {
|
|
318
|
-
return store.setMetadata(_objectSpread(_objectSpread({}, metadata), {}, {
|
|
319
|
-
unread_count: 0
|
|
320
|
-
}));
|
|
321
|
-
});
|
|
322
|
-
attrs = {
|
|
323
|
-
read_at: new Date().toISOString()
|
|
324
|
-
};
|
|
325
|
-
itemIds = items.map(function (item) {
|
|
326
|
-
return item.id;
|
|
327
|
-
});
|
|
328
|
-
setState(function (store) {
|
|
329
|
-
return store.setItemAttrs(itemIds, attrs);
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Issue the API request to the bulk status change API
|
|
334
|
-
_context5.next = 6;
|
|
335
|
-
return this.makeBulkStatusUpdate("read");
|
|
336
|
-
case 6:
|
|
337
|
-
result = _context5.sent;
|
|
338
|
-
this.broadcaster.emit("items:all_read", {
|
|
339
|
-
items: items
|
|
340
|
-
});
|
|
341
|
-
this.broadcastOverChannel("items:all_read", {
|
|
342
|
-
items: items
|
|
343
|
-
});
|
|
344
|
-
return _context5.abrupt("return", result);
|
|
345
|
-
case 10:
|
|
346
|
-
case "end":
|
|
347
|
-
return _context5.stop();
|
|
348
|
-
}
|
|
349
|
-
}, _callee5, this);
|
|
350
|
-
}));
|
|
351
|
-
function markAllAsRead() {
|
|
352
|
-
return _markAllAsRead.apply(this, arguments);
|
|
353
|
-
}
|
|
354
|
-
return markAllAsRead;
|
|
355
|
-
}()
|
|
356
|
-
}, {
|
|
357
|
-
key: "markAsUnread",
|
|
358
|
-
value: function () {
|
|
359
|
-
var _markAsUnread = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(itemOrItems) {
|
|
360
|
-
return _regenerator["default"].wrap(function _callee6$(_context6) {
|
|
361
|
-
while (1) switch (_context6.prev = _context6.next) {
|
|
362
|
-
case 0:
|
|
363
|
-
this.optimisticallyPerformStatusUpdate(itemOrItems, "unread", {
|
|
364
|
-
read_at: null
|
|
365
|
-
}, "unread_count");
|
|
366
|
-
return _context6.abrupt("return", this.makeStatusUpdate(itemOrItems, "unread"));
|
|
367
|
-
case 2:
|
|
368
|
-
case "end":
|
|
369
|
-
return _context6.stop();
|
|
370
|
-
}
|
|
371
|
-
}, _callee6, this);
|
|
372
|
-
}));
|
|
373
|
-
function markAsUnread(_x4) {
|
|
374
|
-
return _markAsUnread.apply(this, arguments);
|
|
375
|
-
}
|
|
376
|
-
return markAsUnread;
|
|
377
|
-
}()
|
|
378
|
-
}, {
|
|
379
|
-
key: "markAsInteracted",
|
|
380
|
-
value: function () {
|
|
381
|
-
var _markAsInteracted = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(itemOrItems) {
|
|
382
|
-
var now;
|
|
383
|
-
return _regenerator["default"].wrap(function _callee7$(_context7) {
|
|
384
|
-
while (1) switch (_context7.prev = _context7.next) {
|
|
385
|
-
case 0:
|
|
386
|
-
now = new Date().toISOString();
|
|
387
|
-
this.optimisticallyPerformStatusUpdate(itemOrItems, "interacted", {
|
|
388
|
-
read_at: now,
|
|
389
|
-
interacted_at: now
|
|
390
|
-
}, "unread_count");
|
|
391
|
-
return _context7.abrupt("return", this.makeStatusUpdate(itemOrItems, "interacted"));
|
|
392
|
-
case 3:
|
|
393
|
-
case "end":
|
|
394
|
-
return _context7.stop();
|
|
395
|
-
}
|
|
396
|
-
}, _callee7, this);
|
|
397
|
-
}));
|
|
398
|
-
function markAsInteracted(_x5) {
|
|
399
|
-
return _markAsInteracted.apply(this, arguments);
|
|
400
|
-
}
|
|
401
|
-
return markAsInteracted;
|
|
402
|
-
}()
|
|
403
|
-
/*
|
|
404
|
-
Marking one or more items as archived should:
|
|
405
|
-
- Decrement the badge count for any unread / unseen items
|
|
406
|
-
- Remove the item from the feed list when the `archived` flag is "exclude" (default)
|
|
407
|
-
TODO: how do we handle rollbacks?
|
|
408
|
-
*/
|
|
409
|
-
}, {
|
|
410
|
-
key: "markAsArchived",
|
|
411
|
-
value: (function () {
|
|
412
|
-
var _markAsArchived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8(itemOrItems) {
|
|
413
|
-
var _this$store3, getState, setState, state, shouldOptimisticallyRemoveItems, normalizedItems, itemIds, unseenCount, unreadCount, updatedMetadata, entriesToSet;
|
|
414
|
-
return _regenerator["default"].wrap(function _callee8$(_context8) {
|
|
415
|
-
while (1) switch (_context8.prev = _context8.next) {
|
|
416
|
-
case 0:
|
|
417
|
-
_this$store3 = this.store, getState = _this$store3.getState, setState = _this$store3.setState;
|
|
418
|
-
state = getState();
|
|
419
|
-
shouldOptimisticallyRemoveItems = this.defaultOptions.archived === "exclude";
|
|
420
|
-
normalizedItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
|
|
421
|
-
itemIds = normalizedItems.map(function (item) {
|
|
422
|
-
return item.id;
|
|
423
|
-
});
|
|
424
|
-
/*
|
|
425
|
-
In the code here we want to optimistically update counts and items
|
|
426
|
-
that are persisted such that we can display updates immediately on the feed
|
|
427
|
-
without needing to make a network request.
|
|
428
|
-
Note: right now this does *not* take into account offline handling or any extensive retry
|
|
429
|
-
logic, so rollbacks aren't considered. That probably needs to be a future consideration for
|
|
430
|
-
this library.
|
|
431
|
-
Scenarios to consider:
|
|
432
|
-
## Feed scope to archived *only*
|
|
433
|
-
- Counts should not be decremented
|
|
434
|
-
- Items should not be removed
|
|
435
|
-
## Feed scoped to exclude archived items (the default)
|
|
436
|
-
- Counts should be decremented
|
|
437
|
-
- Items should be removed
|
|
438
|
-
## Feed scoped to include archived items as well
|
|
439
|
-
- Counts should not be decremented
|
|
440
|
-
- Items should not be removed
|
|
441
|
-
*/
|
|
442
|
-
if (shouldOptimisticallyRemoveItems) {
|
|
443
|
-
// If any of the items are unseen or unread, then capture as we'll want to decrement
|
|
444
|
-
// the counts for these in the metadata we have
|
|
445
|
-
unseenCount = normalizedItems.filter(function (i) {
|
|
446
|
-
return !i.seen_at;
|
|
447
|
-
}).length;
|
|
448
|
-
unreadCount = normalizedItems.filter(function (i) {
|
|
449
|
-
return !i.read_at;
|
|
450
|
-
}).length; // Build the new metadata
|
|
451
|
-
updatedMetadata = _objectSpread(_objectSpread({}, state.metadata), {}, {
|
|
452
|
-
total_count: state.metadata.total_count - normalizedItems.length,
|
|
453
|
-
unseen_count: state.metadata.unseen_count - unseenCount,
|
|
454
|
-
unread_count: state.metadata.unread_count - unreadCount
|
|
455
|
-
}); // Remove the archiving entries
|
|
456
|
-
entriesToSet = state.items.filter(function (item) {
|
|
457
|
-
return !itemIds.includes(item.id);
|
|
458
|
-
});
|
|
459
|
-
setState(function (state) {
|
|
460
|
-
return state.setResult({
|
|
461
|
-
entries: entriesToSet,
|
|
462
|
-
meta: updatedMetadata,
|
|
463
|
-
page_info: state.pageInfo
|
|
464
|
-
});
|
|
465
|
-
});
|
|
466
|
-
} else {
|
|
467
|
-
// Mark all the entries being updated as archived either way so the state is correct
|
|
468
|
-
state.setItemAttrs(itemIds, {
|
|
469
|
-
archived_at: new Date().toISOString()
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
return _context8.abrupt("return", this.makeStatusUpdate(itemOrItems, "archived"));
|
|
473
|
-
case 7:
|
|
474
|
-
case "end":
|
|
475
|
-
return _context8.stop();
|
|
476
|
-
}
|
|
477
|
-
}, _callee8, this);
|
|
478
|
-
}));
|
|
479
|
-
function markAsArchived(_x6) {
|
|
480
|
-
return _markAsArchived.apply(this, arguments);
|
|
481
|
-
}
|
|
482
|
-
return markAsArchived;
|
|
483
|
-
}())
|
|
484
|
-
}, {
|
|
485
|
-
key: "markAllAsArchived",
|
|
486
|
-
value: function () {
|
|
487
|
-
var _markAllAsArchived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee9() {
|
|
488
|
-
var _this$store4, setState, getState, _getState3, items, shouldOptimisticallyRemoveItems, result;
|
|
489
|
-
return _regenerator["default"].wrap(function _callee9$(_context9) {
|
|
490
|
-
while (1) switch (_context9.prev = _context9.next) {
|
|
491
|
-
case 0:
|
|
492
|
-
// Note: there is the potential for a race condition here because the bulk
|
|
493
|
-
// update is an async method, so if a new message comes in during this window before
|
|
494
|
-
// the update has been processed we'll effectively reset the `unseen_count` to be what it was.
|
|
495
|
-
_this$store4 = this.store, setState = _this$store4.setState, getState = _this$store4.getState;
|
|
496
|
-
_getState3 = getState(), items = _getState3.items; // Here if we're looking at a feed that excludes all of the archived items by default then we
|
|
497
|
-
// will want to optimistically remove all of the items from the feed as they are now all excluded
|
|
498
|
-
shouldOptimisticallyRemoveItems = this.defaultOptions.archived === "exclude";
|
|
499
|
-
if (shouldOptimisticallyRemoveItems) {
|
|
500
|
-
// Reset the store to clear out all of items and reset the badge count
|
|
501
|
-
setState(function (store) {
|
|
502
|
-
return store.resetStore();
|
|
503
|
-
});
|
|
504
|
-
} else {
|
|
505
|
-
// Mark all the entries being updated as archived either way so the state is correct
|
|
506
|
-
setState(function (store) {
|
|
507
|
-
var itemIds = items.map(function (i) {
|
|
508
|
-
return i.id;
|
|
509
|
-
});
|
|
510
|
-
store.setItemAttrs(itemIds, {
|
|
511
|
-
archived_at: new Date().toISOString()
|
|
512
|
-
});
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// Issue the API request to the bulk status change API
|
|
517
|
-
_context9.next = 6;
|
|
518
|
-
return this.makeBulkStatusUpdate("archive");
|
|
519
|
-
case 6:
|
|
520
|
-
result = _context9.sent;
|
|
521
|
-
this.broadcaster.emit("items:all_archived", {
|
|
522
|
-
items: items
|
|
523
|
-
});
|
|
524
|
-
this.broadcastOverChannel("items:all_archived", {
|
|
525
|
-
items: items
|
|
526
|
-
});
|
|
527
|
-
return _context9.abrupt("return", result);
|
|
528
|
-
case 10:
|
|
529
|
-
case "end":
|
|
530
|
-
return _context9.stop();
|
|
531
|
-
}
|
|
532
|
-
}, _callee9, this);
|
|
533
|
-
}));
|
|
534
|
-
function markAllAsArchived() {
|
|
535
|
-
return _markAllAsArchived.apply(this, arguments);
|
|
536
|
-
}
|
|
537
|
-
return markAllAsArchived;
|
|
538
|
-
}()
|
|
539
|
-
}, {
|
|
540
|
-
key: "markAsUnarchived",
|
|
541
|
-
value: function () {
|
|
542
|
-
var _markAsUnarchived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee10(itemOrItems) {
|
|
543
|
-
return _regenerator["default"].wrap(function _callee10$(_context10) {
|
|
544
|
-
while (1) switch (_context10.prev = _context10.next) {
|
|
545
|
-
case 0:
|
|
546
|
-
this.optimisticallyPerformStatusUpdate(itemOrItems, "unarchived", {
|
|
547
|
-
archived_at: null
|
|
548
|
-
});
|
|
549
|
-
return _context10.abrupt("return", this.makeStatusUpdate(itemOrItems, "unarchived"));
|
|
550
|
-
case 2:
|
|
551
|
-
case "end":
|
|
552
|
-
return _context10.stop();
|
|
553
|
-
}
|
|
554
|
-
}, _callee10, this);
|
|
555
|
-
}));
|
|
556
|
-
function markAsUnarchived(_x7) {
|
|
557
|
-
return _markAsUnarchived.apply(this, arguments);
|
|
558
|
-
}
|
|
559
|
-
return markAsUnarchived;
|
|
560
|
-
}() /* Fetches the feed content, appending it to the store */
|
|
561
|
-
}, {
|
|
562
|
-
key: "fetch",
|
|
563
|
-
value: (function () {
|
|
564
|
-
var _fetch = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee11() {
|
|
565
|
-
var options,
|
|
566
|
-
_this$store5,
|
|
567
|
-
setState,
|
|
568
|
-
getState,
|
|
569
|
-
_getState4,
|
|
570
|
-
networkStatus,
|
|
571
|
-
queryParams,
|
|
572
|
-
result,
|
|
573
|
-
response,
|
|
574
|
-
opts,
|
|
575
|
-
_opts,
|
|
576
|
-
feedEventType,
|
|
577
|
-
eventPayload,
|
|
578
|
-
_args11 = arguments;
|
|
579
|
-
return _regenerator["default"].wrap(function _callee11$(_context11) {
|
|
580
|
-
while (1) switch (_context11.prev = _context11.next) {
|
|
581
|
-
case 0:
|
|
582
|
-
options = _args11.length > 0 && _args11[0] !== undefined ? _args11[0] : {};
|
|
583
|
-
_this$store5 = this.store, setState = _this$store5.setState, getState = _this$store5.getState;
|
|
584
|
-
_getState4 = getState(), networkStatus = _getState4.networkStatus; // If there's an existing request in flight, then do nothing
|
|
585
|
-
if (!(0, _networkStatus.isRequestInFlight)(networkStatus)) {
|
|
586
|
-
_context11.next = 5;
|
|
587
|
-
break;
|
|
588
|
-
}
|
|
589
|
-
return _context11.abrupt("return");
|
|
590
|
-
case 5:
|
|
591
|
-
// Set the loading type based on the request type it is
|
|
592
|
-
setState(function (store) {
|
|
593
|
-
var _options$__loadingTyp;
|
|
594
|
-
return store.setNetworkStatus((_options$__loadingTyp = options.__loadingType) !== null && _options$__loadingTyp !== void 0 ? _options$__loadingTyp : _networkStatus.NetworkStatus.loading);
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
// Always include the default params, if they have been set
|
|
598
|
-
queryParams = _objectSpread(_objectSpread(_objectSpread({}, this.defaultOptions), options), {}, {
|
|
599
|
-
// Unset options that should not be sent to the API
|
|
600
|
-
__loadingType: undefined,
|
|
601
|
-
__fetchSource: undefined,
|
|
602
|
-
__experimentalCrossBrowserUpdates: undefined
|
|
603
|
-
});
|
|
604
|
-
_context11.next = 9;
|
|
605
|
-
return this.apiClient.makeRequest({
|
|
606
|
-
method: "GET",
|
|
607
|
-
url: "/v1/users/".concat(this.knock.userId, "/feeds/").concat(this.feedId),
|
|
608
|
-
params: queryParams
|
|
609
|
-
});
|
|
610
|
-
case 9:
|
|
611
|
-
result = _context11.sent;
|
|
612
|
-
if (!(result.statusCode === "error" || !result.body)) {
|
|
613
|
-
_context11.next = 13;
|
|
614
|
-
break;
|
|
615
|
-
}
|
|
616
|
-
setState(function (store) {
|
|
617
|
-
return store.setNetworkStatus(_networkStatus.NetworkStatus.error);
|
|
618
|
-
});
|
|
619
|
-
return _context11.abrupt("return", {
|
|
620
|
-
status: result.statusCode,
|
|
621
|
-
data: result.error || result.body
|
|
622
|
-
});
|
|
623
|
-
case 13:
|
|
624
|
-
response = {
|
|
625
|
-
entries: result.body.entries,
|
|
626
|
-
meta: result.body.meta,
|
|
627
|
-
page_info: result.body.page_info
|
|
628
|
-
};
|
|
629
|
-
if (options.before) {
|
|
630
|
-
opts = {
|
|
631
|
-
shouldSetPage: false,
|
|
632
|
-
shouldAppend: true
|
|
633
|
-
};
|
|
634
|
-
setState(function (state) {
|
|
635
|
-
return state.setResult(response, opts);
|
|
636
|
-
});
|
|
637
|
-
} else if (options.after) {
|
|
638
|
-
_opts = {
|
|
639
|
-
shouldSetPage: true,
|
|
640
|
-
shouldAppend: true
|
|
641
|
-
};
|
|
642
|
-
setState(function (state) {
|
|
643
|
-
return state.setResult(response, _opts);
|
|
644
|
-
});
|
|
645
|
-
} else {
|
|
646
|
-
setState(function (state) {
|
|
647
|
-
return state.setResult(response);
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// Legacy `messages.new` event, should be removed in a future version
|
|
652
|
-
this.broadcast("messages.new", response);
|
|
653
|
-
|
|
654
|
-
// Broadcast the appropriate event type depending on the fetch source
|
|
655
|
-
feedEventType = options.__fetchSource === "socket" ? "items.received.realtime" : "items.received.page";
|
|
656
|
-
eventPayload = {
|
|
657
|
-
items: response.entries,
|
|
658
|
-
metadata: response.meta,
|
|
659
|
-
event: feedEventType
|
|
660
|
-
};
|
|
661
|
-
this.broadcast(eventPayload.event, eventPayload);
|
|
662
|
-
return _context11.abrupt("return", {
|
|
663
|
-
data: response,
|
|
664
|
-
status: result.statusCode
|
|
665
|
-
});
|
|
666
|
-
case 20:
|
|
667
|
-
case "end":
|
|
668
|
-
return _context11.stop();
|
|
669
|
-
}
|
|
670
|
-
}, _callee11, this);
|
|
671
|
-
}));
|
|
672
|
-
function fetch() {
|
|
673
|
-
return _fetch.apply(this, arguments);
|
|
674
|
-
}
|
|
675
|
-
return fetch;
|
|
676
|
-
}())
|
|
677
|
-
}, {
|
|
678
|
-
key: "fetchNextPage",
|
|
679
|
-
value: function () {
|
|
680
|
-
var _fetchNextPage = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee12() {
|
|
681
|
-
var getState, _getState5, pageInfo;
|
|
682
|
-
return _regenerator["default"].wrap(function _callee12$(_context12) {
|
|
683
|
-
while (1) switch (_context12.prev = _context12.next) {
|
|
684
|
-
case 0:
|
|
685
|
-
// Attempts to fetch the next page of results (if we have any)
|
|
686
|
-
getState = this.store.getState;
|
|
687
|
-
_getState5 = getState(), pageInfo = _getState5.pageInfo;
|
|
688
|
-
if (pageInfo.after) {
|
|
689
|
-
_context12.next = 4;
|
|
690
|
-
break;
|
|
691
|
-
}
|
|
692
|
-
return _context12.abrupt("return");
|
|
693
|
-
case 4:
|
|
694
|
-
this.fetch({
|
|
695
|
-
after: pageInfo.after,
|
|
696
|
-
__loadingType: _networkStatus.NetworkStatus.fetchMore
|
|
697
|
-
});
|
|
698
|
-
case 5:
|
|
699
|
-
case "end":
|
|
700
|
-
return _context12.stop();
|
|
701
|
-
}
|
|
702
|
-
}, _callee12, this);
|
|
703
|
-
}));
|
|
704
|
-
function fetchNextPage() {
|
|
705
|
-
return _fetchNextPage.apply(this, arguments);
|
|
706
|
-
}
|
|
707
|
-
return fetchNextPage;
|
|
708
|
-
}()
|
|
709
|
-
}, {
|
|
710
|
-
key: "broadcast",
|
|
711
|
-
value: function broadcast(eventName, data) {
|
|
712
|
-
this.broadcaster.emit(eventName, data);
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
// Invoked when a new real-time message comes in from the socket
|
|
716
|
-
}, {
|
|
717
|
-
key: "onNewMessageReceived",
|
|
718
|
-
value: function () {
|
|
719
|
-
var _onNewMessageReceived = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee13(_ref) {
|
|
720
|
-
var metadata, _this$store6, getState, setState, _getState6, items, currentHead;
|
|
721
|
-
return _regenerator["default"].wrap(function _callee13$(_context13) {
|
|
722
|
-
while (1) switch (_context13.prev = _context13.next) {
|
|
723
|
-
case 0:
|
|
724
|
-
metadata = _ref.metadata;
|
|
725
|
-
// Handle the new message coming in
|
|
726
|
-
_this$store6 = this.store, getState = _this$store6.getState, setState = _this$store6.setState;
|
|
727
|
-
_getState6 = getState(), items = _getState6.items;
|
|
728
|
-
currentHead = items[0]; // Optimistically set the badge counts
|
|
729
|
-
setState(function (state) {
|
|
730
|
-
return state.setMetadata(metadata);
|
|
731
|
-
});
|
|
732
|
-
// Fetch the items before the current head (if it exists)
|
|
733
|
-
this.fetch({
|
|
734
|
-
before: currentHead === null || currentHead === void 0 ? void 0 : currentHead.__cursor,
|
|
735
|
-
__fetchSource: "socket"
|
|
736
|
-
});
|
|
737
|
-
case 6:
|
|
738
|
-
case "end":
|
|
739
|
-
return _context13.stop();
|
|
740
|
-
}
|
|
741
|
-
}, _callee13, this);
|
|
742
|
-
}));
|
|
743
|
-
function onNewMessageReceived(_x8) {
|
|
744
|
-
return _onNewMessageReceived.apply(this, arguments);
|
|
745
|
-
}
|
|
746
|
-
return onNewMessageReceived;
|
|
747
|
-
}()
|
|
748
|
-
}, {
|
|
749
|
-
key: "buildUserFeedId",
|
|
750
|
-
value: function buildUserFeedId() {
|
|
751
|
-
return "".concat(this.feedId, ":").concat(this.knock.userId);
|
|
752
|
-
}
|
|
753
|
-
}, {
|
|
754
|
-
key: "optimisticallyPerformStatusUpdate",
|
|
755
|
-
value: function optimisticallyPerformStatusUpdate(itemOrItems, type, attrs, badgeCountAttr) {
|
|
756
|
-
var _this$store7 = this.store,
|
|
757
|
-
getState = _this$store7.getState,
|
|
758
|
-
setState = _this$store7.setState;
|
|
759
|
-
var normalizedItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
|
|
760
|
-
var itemIds = normalizedItems.map(function (item) {
|
|
761
|
-
return item.id;
|
|
762
|
-
});
|
|
763
|
-
if (badgeCountAttr) {
|
|
764
|
-
var _getState7 = getState(),
|
|
765
|
-
metadata = _getState7.metadata;
|
|
766
|
-
|
|
767
|
-
// We only want to update the counts of items that have not already been counted towards the
|
|
768
|
-
// badge count total to avoid updating the badge count unnecessarily.
|
|
769
|
-
var itemsToUpdate = normalizedItems.filter(function (item) {
|
|
770
|
-
switch (type) {
|
|
771
|
-
case "seen":
|
|
772
|
-
return item.seen_at === null;
|
|
773
|
-
case "unseen":
|
|
774
|
-
return item.seen_at !== null;
|
|
775
|
-
case "read":
|
|
776
|
-
case "interacted":
|
|
777
|
-
return item.read_at === null;
|
|
778
|
-
case "unread":
|
|
779
|
-
return item.read_at !== null;
|
|
780
|
-
default:
|
|
781
|
-
return true;
|
|
782
|
-
}
|
|
783
|
-
});
|
|
784
|
-
|
|
785
|
-
// Tnis is a hack to determine the direction of whether we're
|
|
786
|
-
// adding or removing from the badge count
|
|
787
|
-
var direction = type.startsWith("un") ? itemsToUpdate.length : -itemsToUpdate.length;
|
|
788
|
-
setState(function (store) {
|
|
789
|
-
return store.setMetadata(_objectSpread(_objectSpread({}, metadata), {}, (0, _defineProperty2["default"])({}, badgeCountAttr, Math.max(0, metadata[badgeCountAttr] + direction))));
|
|
790
|
-
});
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
// Update the items with the given attributes
|
|
794
|
-
setState(function (store) {
|
|
795
|
-
return store.setItemAttrs(itemIds, attrs);
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
}, {
|
|
799
|
-
key: "makeStatusUpdate",
|
|
800
|
-
value: function () {
|
|
801
|
-
var _makeStatusUpdate = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee14(itemOrItems, type) {
|
|
802
|
-
var items, itemIds, result;
|
|
803
|
-
return _regenerator["default"].wrap(function _callee14$(_context14) {
|
|
804
|
-
while (1) switch (_context14.prev = _context14.next) {
|
|
805
|
-
case 0:
|
|
806
|
-
// Always treat items as a batch to use the corresponding batch endpoint
|
|
807
|
-
items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
|
|
808
|
-
itemIds = items.map(function (item) {
|
|
809
|
-
return item.id;
|
|
810
|
-
});
|
|
811
|
-
_context14.next = 4;
|
|
812
|
-
return this.apiClient.makeRequest({
|
|
813
|
-
method: "POST",
|
|
814
|
-
url: "/v1/messages/batch/".concat(type),
|
|
815
|
-
data: {
|
|
816
|
-
message_ids: itemIds
|
|
817
|
-
}
|
|
818
|
-
});
|
|
819
|
-
case 4:
|
|
820
|
-
result = _context14.sent;
|
|
821
|
-
// Emit the event that these items had their statuses changed
|
|
822
|
-
// Note: we do this after the update to ensure that the server event actually completed
|
|
823
|
-
this.broadcaster.emit("items:".concat(type), {
|
|
824
|
-
items: items
|
|
825
|
-
});
|
|
826
|
-
this.broadcastOverChannel("items:".concat(type), {
|
|
827
|
-
items: items
|
|
828
|
-
});
|
|
829
|
-
return _context14.abrupt("return", result);
|
|
830
|
-
case 8:
|
|
831
|
-
case "end":
|
|
832
|
-
return _context14.stop();
|
|
833
|
-
}
|
|
834
|
-
}, _callee14, this);
|
|
835
|
-
}));
|
|
836
|
-
function makeStatusUpdate(_x9, _x10) {
|
|
837
|
-
return _makeStatusUpdate.apply(this, arguments);
|
|
838
|
-
}
|
|
839
|
-
return makeStatusUpdate;
|
|
840
|
-
}()
|
|
841
|
-
}, {
|
|
842
|
-
key: "makeBulkStatusUpdate",
|
|
843
|
-
value: function () {
|
|
844
|
-
var _makeBulkStatusUpdate = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee15(type) {
|
|
845
|
-
var options;
|
|
846
|
-
return _regenerator["default"].wrap(function _callee15$(_context15) {
|
|
847
|
-
while (1) switch (_context15.prev = _context15.next) {
|
|
848
|
-
case 0:
|
|
849
|
-
// The base scope for the call should take into account all of the options currently
|
|
850
|
-
// set on the feed, as well as being scoped for the current user. We do this so that
|
|
851
|
-
// we ONLY make changes to the messages that are currently in view on this feed, and not
|
|
852
|
-
// all messages that exist.
|
|
853
|
-
options = {
|
|
854
|
-
user_ids: [this.knock.userId],
|
|
855
|
-
engagement_status: this.defaultOptions.status !== "all" ? this.defaultOptions.status : undefined,
|
|
856
|
-
archived: this.defaultOptions.archived,
|
|
857
|
-
has_tenant: this.defaultOptions.has_tenant,
|
|
858
|
-
tenants: this.defaultOptions.tenant ? [this.defaultOptions.tenant] : undefined
|
|
859
|
-
};
|
|
860
|
-
_context15.next = 3;
|
|
861
|
-
return this.apiClient.makeRequest({
|
|
862
|
-
method: "POST",
|
|
863
|
-
url: "/v1/channels/".concat(this.feedId, "/messages/bulk/").concat(type),
|
|
864
|
-
data: options
|
|
865
|
-
});
|
|
866
|
-
case 3:
|
|
867
|
-
return _context15.abrupt("return", _context15.sent);
|
|
868
|
-
case 4:
|
|
869
|
-
case "end":
|
|
870
|
-
return _context15.stop();
|
|
871
|
-
}
|
|
872
|
-
}, _callee15, this);
|
|
873
|
-
}));
|
|
874
|
-
function makeBulkStatusUpdate(_x11) {
|
|
875
|
-
return _makeBulkStatusUpdate.apply(this, arguments);
|
|
876
|
-
}
|
|
877
|
-
return makeBulkStatusUpdate;
|
|
878
|
-
}()
|
|
879
|
-
}, {
|
|
880
|
-
key: "broadcastOverChannel",
|
|
881
|
-
value: function broadcastOverChannel(type, payload) {
|
|
882
|
-
// The broadcastChannel may not be available in non-browser environments
|
|
883
|
-
if (!this.broadcastChannel) {
|
|
884
|
-
return;
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
// Here we stringify our payload and try and send as JSON such that we
|
|
888
|
-
// don't get any `An object could not be cloned` errors when trying to broadcast
|
|
889
|
-
try {
|
|
890
|
-
var stringifiedPayload = JSON.parse(JSON.stringify(payload));
|
|
891
|
-
this.broadcastChannel.postMessage({
|
|
892
|
-
type: type,
|
|
893
|
-
payload: stringifiedPayload
|
|
894
|
-
});
|
|
895
|
-
} catch (e) {
|
|
896
|
-
console.warn("Could not broadcast ".concat(type, ", got error: ").concat(e));
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
/**
|
|
901
|
-
* Listen for changes to document visibility and automatically disconnect
|
|
902
|
-
* or reconnect the socket after a delay
|
|
903
|
-
*/
|
|
904
|
-
}, {
|
|
905
|
-
key: "setupAutoSocketManager",
|
|
906
|
-
value: function setupAutoSocketManager(autoManageSocketConnectionDelay) {
|
|
907
|
-
var _this3 = this;
|
|
908
|
-
var disconnectDelay = autoManageSocketConnectionDelay !== null && autoManageSocketConnectionDelay !== void 0 ? autoManageSocketConnectionDelay : DEFAULT_DISCONNECT_DELAY;
|
|
909
|
-
document.addEventListener("visibilitychange", function () {
|
|
910
|
-
if (document.visibilityState === "hidden") {
|
|
911
|
-
// When the tab is hidden, clean up the socket connection after a delay
|
|
912
|
-
_this3.disconnectTimer = setTimeout(function () {
|
|
913
|
-
_this3.apiClient.disconnectSocket();
|
|
914
|
-
_this3.disconnectTimer = null;
|
|
915
|
-
}, disconnectDelay);
|
|
916
|
-
} else if (document.visibilityState === "visible") {
|
|
917
|
-
var _this3$apiClient$sock;
|
|
918
|
-
// When the tab is visible, clear the disconnect timer if active to cancel disconnecting
|
|
919
|
-
// This handles cases where the tab is only briefly hidden to avoid unnecessary disconnects
|
|
920
|
-
if (_this3.disconnectTimer) {
|
|
921
|
-
clearTimeout(_this3.disconnectTimer);
|
|
922
|
-
_this3.disconnectTimer = null;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
// If the socket is not connected, try to reconnect
|
|
926
|
-
if (!((_this3$apiClient$sock = _this3.apiClient.socket) !== null && _this3$apiClient$sock !== void 0 && _this3$apiClient$sock.isConnected())) {
|
|
927
|
-
_this3.apiClient.reconnectSocket();
|
|
928
|
-
_this3.fetch();
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
});
|
|
932
|
-
}
|
|
933
|
-
}]);
|
|
934
|
-
return Feed;
|
|
935
|
-
}();
|
|
936
|
-
var _default = exports["default"] = Feed;
|
|
937
|
-
//# sourceMappingURL=feed.js.map
|
|
1
|
+
"use strict";var _=Object.defineProperty;var k=(m,e,t)=>e in m?_(m,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):m[e]=t;var u=(m,e,t)=>(k(m,typeof e!="symbol"?e+"":e,t),t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const p=require("eventemitter2"),f=require("../../networkStatus.js"),S=require("./store.js"),g={archived:"exclude"},v=2e3;class y{constructor(e,t,s){u(this,"userFeedId");u(this,"channel");u(this,"broadcaster");u(this,"defaultOptions");u(this,"broadcastChannel");u(this,"disconnectTimer",null);u(this,"hasSubscribedToRealTimeUpdates",!1);u(this,"store");this.knock=e,this.feedId=t,this.feedId=t,this.userFeedId=this.buildUserFeedId(),this.store=S.default(),this.broadcaster=new p.EventEmitter2({wildcard:!0,delimiter:"."}),this.defaultOptions={...g,...s},this.knock.log(`[Feed] Initialized a feed on channel ${t}`),this.initializeRealtimeConnection(),this.setupBroadcastChannel()}reinitialize(){this.userFeedId=this.buildUserFeedId(),this.initializeRealtimeConnection(),this.setupBroadcastChannel()}teardown(){this.knock.log("[Feed] Tearing down feed instance"),this.channel&&(this.channel.leave(),this.channel.off("new-message")),this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),this.broadcastChannel&&this.broadcastChannel.close()}dispose(){this.knock.log("[Feed] Disposing of feed instance"),this.teardown(),this.broadcaster.removeAllListeners(),this.knock.feeds.removeInstance(this)}listenForUpdates(){this.knock.log("[Feed] Connecting to real-time service"),this.hasSubscribedToRealTimeUpdates=!0;const e=this.knock.client().socket;e&&!e.isConnected()&&e.connect(),this.channel&&["closed","errored"].includes(this.channel.state)&&this.channel.join()}on(e,t){this.broadcaster.on(e,t)}off(e,t){this.broadcaster.off(e,t)}getState(){return this.store.getState()}async markAsSeen(e){const t=new Date().toISOString();return this.optimisticallyPerformStatusUpdate(e,"seen",{seen_at:t},"unseen_count"),this.makeStatusUpdate(e,"seen")}async markAllAsSeen(){const{getState:e,setState:t}=this.store,{metadata:s,items:a}=e();if(this.defaultOptions.status==="unseen")t(i=>i.resetStore({...s,total_count:0,unseen_count:0}));else{t(o=>o.setMetadata({...s,unseen_count:0}));const i={seen_at:new Date().toISOString()},l=a.map(o=>o.id);t(o=>o.setItemAttrs(l,i))}const n=await this.makeBulkStatusUpdate("seen");return this.broadcaster.emit("items:all_seen",{items:a}),this.broadcastOverChannel("items:all_seen",{items:a}),n}async markAsUnseen(e){return this.optimisticallyPerformStatusUpdate(e,"unseen",{seen_at:null},"unseen_count"),this.makeStatusUpdate(e,"unseen")}async markAsRead(e){const t=new Date().toISOString();return this.optimisticallyPerformStatusUpdate(e,"read",{read_at:t},"unread_count"),this.makeStatusUpdate(e,"read")}async markAllAsRead(){const{getState:e,setState:t}=this.store,{metadata:s,items:a}=e();if(this.defaultOptions.status==="unread")t(i=>i.resetStore({...s,total_count:0,unread_count:0}));else{t(o=>o.setMetadata({...s,unread_count:0}));const i={read_at:new Date().toISOString()},l=a.map(o=>o.id);t(o=>o.setItemAttrs(l,i))}const n=await this.makeBulkStatusUpdate("read");return this.broadcaster.emit("items:all_read",{items:a}),this.broadcastOverChannel("items:all_read",{items:a}),n}async markAsUnread(e){return this.optimisticallyPerformStatusUpdate(e,"unread",{read_at:null},"unread_count"),this.makeStatusUpdate(e,"unread")}async markAsInteracted(e){const t=new Date().toISOString();return this.optimisticallyPerformStatusUpdate(e,"interacted",{read_at:t,interacted_at:t},"unread_count"),this.makeStatusUpdate(e,"interacted")}async markAsArchived(e){const{getState:t,setState:s}=this.store,a=t(),r=this.defaultOptions.archived==="exclude",n=Array.isArray(e)?e:[e],i=n.map(l=>l.id);if(r){const l=n.filter(c=>!c.seen_at).length,o=n.filter(c=>!c.read_at).length,d={...a.metadata,total_count:a.metadata.total_count-n.length,unseen_count:a.metadata.unseen_count-l,unread_count:a.metadata.unread_count-o},h=a.items.filter(c=>!i.includes(c.id));s(c=>c.setResult({entries:h,meta:d,page_info:c.pageInfo}))}else a.setItemAttrs(i,{archived_at:new Date().toISOString()});return this.makeStatusUpdate(e,"archived")}async markAllAsArchived(){const{setState:e,getState:t}=this.store,{items:s}=t(),a=this.defaultOptions.archived==="exclude";e(a?n=>n.resetStore():n=>{const i=s.map(l=>l.id);n.setItemAttrs(i,{archived_at:new Date().toISOString()})});const r=await this.makeBulkStatusUpdate("archive");return this.broadcaster.emit("items:all_archived",{items:s}),this.broadcastOverChannel("items:all_archived",{items:s}),r}async markAsUnarchived(e){return this.optimisticallyPerformStatusUpdate(e,"unarchived",{archived_at:null}),this.makeStatusUpdate(e,"unarchived")}async fetch(e={}){const{setState:t,getState:s}=this.store,{networkStatus:a}=s();if(f.isRequestInFlight(a))return;t(d=>d.setNetworkStatus(e.__loadingType??f.NetworkStatus.loading));const r={...this.defaultOptions,...e,__loadingType:void 0,__fetchSource:void 0,__experimentalCrossBrowserUpdates:void 0,auto_manage_socket_connection:void 0,auto_manage_socket_connection_delay:void 0},n=await this.knock.client().makeRequest({method:"GET",url:`/v1/users/${this.knock.userId}/feeds/${this.feedId}`,params:r});if(n.statusCode==="error"||!n.body)return t(d=>d.setNetworkStatus(f.NetworkStatus.error)),{status:n.statusCode,data:n.error||n.body};const i={entries:n.body.entries,meta:n.body.meta,page_info:n.body.page_info};if(e.before){const d={shouldSetPage:!1,shouldAppend:!0};t(h=>h.setResult(i,d))}else if(e.after){const d={shouldSetPage:!0,shouldAppend:!0};t(h=>h.setResult(i,d))}else t(d=>d.setResult(i));this.broadcast("messages.new",i);const l=e.__fetchSource==="socket"?"items.received.realtime":"items.received.page",o={items:i.entries,metadata:i.meta,event:l};return this.broadcast(o.event,o),{data:i,status:n.statusCode}}async fetchNextPage(){const{getState:e}=this.store,{pageInfo:t}=e();t.after&&this.fetch({after:t.after,__loadingType:f.NetworkStatus.fetchMore})}broadcast(e,t){this.broadcaster.emit(e,t)}async onNewMessageReceived({metadata:e}){this.knock.log("[Feed] Received new real-time message");const{getState:t,setState:s}=this.store,{items:a}=t(),r=a[0];s(n=>n.setMetadata(e)),this.fetch({before:r==null?void 0:r.__cursor,__fetchSource:"socket"})}buildUserFeedId(){return`${this.feedId}:${this.knock.userId}`}optimisticallyPerformStatusUpdate(e,t,s,a){const{getState:r,setState:n}=this.store,i=Array.isArray(e)?e:[e],l=i.map(o=>o.id);if(a){const{metadata:o}=r(),d=i.filter(c=>{switch(t){case"seen":return c.seen_at===null;case"unseen":return c.seen_at!==null;case"read":case"interacted":return c.read_at===null;case"unread":return c.read_at!==null;default:return!0}}),h=t.startsWith("un")?d.length:-d.length;n(c=>c.setMetadata({...o,[a]:Math.max(0,o[a]+h)}))}n(o=>o.setItemAttrs(l,s))}async makeStatusUpdate(e,t){const s=Array.isArray(e)?e:[e],a=s.map(n=>n.id),r=await this.knock.client().makeRequest({method:"POST",url:`/v1/messages/batch/${t}`,data:{message_ids:a}});return this.broadcaster.emit(`items:${t}`,{items:s}),this.broadcastOverChannel(`items:${t}`,{items:s}),r}async makeBulkStatusUpdate(e){const t={user_ids:[this.knock.userId],engagement_status:this.defaultOptions.status!=="all"?this.defaultOptions.status:void 0,archived:this.defaultOptions.archived,has_tenant:this.defaultOptions.has_tenant,tenants:this.defaultOptions.tenant?[this.defaultOptions.tenant]:void 0};return await this.knock.client().makeRequest({method:"POST",url:`/v1/channels/${this.feedId}/messages/bulk/${e}`,data:t})}setupBroadcastChannel(){this.broadcastChannel=typeof self<"u"&&"BroadcastChannel"in self?new BroadcastChannel(`knock:feed:${this.userFeedId}`):null,this.broadcastChannel&&this.defaultOptions.__experimentalCrossBrowserUpdates===!0&&(this.broadcastChannel.onmessage=e=>{switch(e.data.type){case"items:archived":case"items:unarchived":case"items:seen":case"items:unseen":case"items:read":case"items:unread":case"items:all_read":case"items:all_seen":case"items:all_archived":return this.fetch();default:return null}})}broadcastOverChannel(e,t){if(this.broadcastChannel)try{const s=JSON.parse(JSON.stringify(t));this.broadcastChannel.postMessage({type:e,payload:s})}catch(s){console.warn(`Could not broadcast ${e}, got error: ${s}`)}}initializeRealtimeConnection(){const{socket:e}=this.knock.client();e&&(this.channel=e.channel(`feeds:${this.userFeedId}`,this.defaultOptions),this.channel.on("new-message",t=>this.onNewMessageReceived(t)),this.defaultOptions.auto_manage_socket_connection&&this.setupAutoSocketManager(this.defaultOptions.auto_manage_socket_connection_delay),this.hasSubscribedToRealTimeUpdates&&(e.isConnected()||e.connect(),this.channel.join()))}setupAutoSocketManager(e){const t=e??v;document.addEventListener("visibilitychange",()=>{var a;const s=this.knock.client();document.visibilityState==="hidden"?this.disconnectTimer=setTimeout(()=>{var r;(r=s.socket)==null||r.disconnect(),this.disconnectTimer=null},t):document.visibilityState==="visible"&&(this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),(a=s.socket)!=null&&a.isConnected()||this.initializeRealtimeConnection())})}}exports.default=y;
|
|
2
|
+
//# sourceMappingURL=feed.js.map
|